Fork me on GitHub

复杂答题卡客观题识别技术要点

一、目标问题
    对于已经成功切片的答题卡客观题部分内容进行具体识别,得到答题结果。客观题部分分为3类,分别是学号、单选题、多选题。
学号:
单选题:
多选题:
二、解题思路
    目标的缺点在于无定位点,优点在于采集质量比较高、相对位置固定,故计划直接采用"划分ROI区域->识别灰度值"的方法进行识别。
    学号的排列最为简单,可以采用x_blank,x_step,y_blank,y_step的方式来辅助定位:
    单选题的排序较为复杂
   多选题虽然只有一行,复杂度和单选是一样的。
三、算法研究
    有用的算法需要采用逐步的方式实现。从最外部来看,每一个部分都是双重(三重循环)
       for (size_t i_index = 0; i_index <9; i_index++)
            {
                for (size_t j_index = 0; j_index <10; j_index++)
                {……
    差异在循环内部的算法编写,以学号为例。首先通过画线,来判断并调整手工测量的结果:
       line(matNumber, cv::Point(i_index*x_step, 0), cv::Point(i_index*x_step, matNumber.rows - 1), cv::Scalar(00255));
       line(matNumber, cv::Point(050 + j_index * y_step), cv::Point(matNumber.cols - 150 + j_index * y_step), cv::Scalar(00255));
而后可以具体识别,同样通过可视化的方式进行初步检测:
             for (size_t i_index = 0; i_index <9; i_index++)
            {
                int maxBlob = -1;
                int maxindex = -1;
                for (size_t j_index = 0; j_index <10; j_index++)
                {
                    /*line(matNumber, cv::Point(i_index*x_step, 0), cv::Point(i_index*x_step, matNumber.rows - 1), cv::Scalar(0, 0, 255));
                    line(matNumber, cv::Point(0, 50 + j_index * y_step), cv::Point(matNumber.cols - 1, 50 + j_index * y_step), cv::Scalar(0, 0, 255));*/

                    Mat tmp = matNumber(Rect(i_index*x_step, 50 + j_index * y_step, x_step-1, y_step-1));
                    Mat tmpGray; Mat tmpBin;
                    cvtColor(tmp, tmpGray, COLOR_BGR2GRAY);
                    threshold(tmpGray,tmpBin, 100255, THRESH_BINARY_INV);
                    int tmpBlob = countNonZero(tmpBin);
                    //StudentNo[i_index][j_index] = tmpBlob;
                    if (maxBlob < tmpBlob)
                    {
                        maxBlob = tmpBlob;
                        maxindex = j_index;
                    }
                    char cbuf[255];
                    sprintf_s(cbuf, "%d", tmpBlob);
                    putText(matNumber, cbuf, Point(i_index*x_step,50+ j_index*y_step), FONT_HERSHEY_PLAIN, 1.0f, Scalar(00255));
                }
                printf_s("%d", maxindex);
            }
在小批量的数据上测试可行,证明算法思路初步正确,可以继续进行下一步研究。这里需要注意的是对于学号来说,使用双重循环,分别对应列数和填图的号码。
但是多选题来说,我建议使用3重循环。
从框架上来说就是这样:
     for (size_t i_index = 0; i_index < 4; i_index++)
            { 
                for (size_t j_index = 0; j_index < 4; j_index++)
                {
                    int maxBlob = -1;
                    int maxindex = -1;
                    //line(matChooseOne, cv::Point(0, 13 + j_index * y_step), cv::Point(matChooseOne.cols - 1, 13+j_index * y_step), cv::Scalar(0, 0, 255));
                    for (size_t blob_index = 0;blob_index <4;blob_index++)
                    {……
在识别多选题这块,细节有所改变:
    Mat tmp = matChooseMore(Rect(54 + i_index * 197 + blob_index * x_step, 11 + j_index * y_step, x_step, y_step));
    Mat tmpGray; Mat tmpBin;
    cvtColor(tmp, tmpGray, COLOR_BGR2GRAY);
    threshold(tmpGray, tmpBin, 100255, THRESH_BINARY_INV);
    int tmpBlob = countNonZero(tmpBin);
    if (tmpBlob>100)
{
    printf_s("%s", strConvert(blob_index));
}

四、算法实现

    /////////////////////////////////识别学号////////////////////////////////////////////////
            int x_step = matNumber.cols / 9;
            int y_step = (matNumber.rows -50)/ 10;
            printf_s("学号:");
            for (size_t i_index = 0; i_index <9; i_index++)
            {
                int maxBlob = -1;
                int maxindex = -1;
                for (size_t j_index = 0; j_index <10; j_index++)
                {
                    if (DEBUG)
                    {
                        line(matNumber, cv::Point(i_index*x_step, 0), cv::Point(i_index*x_step, matNumber.rows - 1), cv::Scalar(00255));
                        line(matNumber, cv::Point(050 + j_index * y_step), cv::Point(matNumber.cols - 150 + j_index * y_step), cv::Scalar(00255));
                    }
                    Mat tmp = matNumber(Rect(i_index*x_step, 50 + j_index * y_step, x_step-1, y_step-1));
                    Mat tmpGray; Mat tmpBin;
                    cvtColor(tmp, tmpGray, COLOR_BGR2GRAY);
                    threshold(tmpGray,tmpBin, 100255, THRESH_BINARY_INV);
                    int tmpBlob = countNonZero(tmpBin);
                    if (maxBlob < tmpBlob)
                    {
                        maxBlob = tmpBlob;
                        maxindex = j_index;
                    }
                    if (DEBUG)
                    {
                        char cbuf[255];
                        sprintf_s(cbuf, "%d", tmpBlob);
                        putText(matNumber, cbuf, Point(i_index*x_step, 50 + j_index * y_step), FONT_HERSHEY_PLAIN, 1.0f, Scalar(00255));
                    }        
                }
                printf_s("%d", maxindex);
            }
            printf_s("\n");
            /////////////////////////////////识别单选////////////////////////////////////////////////
            cv::imwrite("E:/未来项目/智慧校园/result/_" + to_string(i_index) + "matChooseOne.jpg", matChooseOne);
            printf_s("单选:");
            x_step = 35;
            y_step = 25;
            for (size_t i_index = 0; i_index < 4; i_index++)
            {
                for (size_t j_index = 0; j_index < 4; j_index++)
                {
                    int maxBlob = -1;
                    int maxindex = -1;
                    if (DEBUG)
                    {
                        line(matChooseOne, cv::Point(013 + j_index * y_step), cv::Point(matChooseOne.cols - 113+j_index * y_step), cv::Scalar(00255));
                    }
                    for (size_t blob_index = 0;blob_index <4;blob_index++)
                    {
                        if (DEBUG)
                        {
                            line(matChooseOne, cv::Point(55 + i_index * 195 + blob_index * x_step, 0), cv::Point(55 + i_index * 195 + blob_index * x_step, matNumber.rows - 1), cv::Scalar(00255));
                        }
                        Mat tmp = matChooseOne(Rect(55 + i_index * 195 + blob_index * x_step, 13 + j_index * y_step, x_step, y_step));
                        Mat tmpGray; Mat tmpBin;
                        cvtColor(tmp, tmpGray, COLOR_BGR2GRAY);
                        threshold(tmpGray, tmpBin, 100255, THRESH_BINARY_INV);
                        int tmpBlob = countNonZero(tmpBin);
                        if (maxBlob < tmpBlob)
                        {
                            maxBlob = tmpBlob;
                            maxindex = blob_index;
                        }
                        if (DEBUG)
                        {
                            char cbuf[255];
                            sprintf_s(cbuf, "%d", tmpBlob);
                            putText(matChooseOne, cbuf, Point(55 + i_index * 195 + blob_index * x_step, 13 + j_index * y_step), FONT_HERSHEY_PLAIN, 1.0f, Scalar(00255));
                        }
                    }
                    printf_s("%s ", strConvert( maxindex));
                }
            }
            printf_s("\n");
            /////////////////////////////////识别多选////////////////////////////////////////////////
            cv::imwrite("E:/未来项目/智慧校园/result/_" + to_string(i_index) + "matChooseMore.jpg", matChooseMore);
            printf_s("多选:");
            x_step = 35;
            y_step = 25;
            for (size_t i_index = 0; i_index < 3; i_index++)
            {
                for (size_t j_index = 0; j_index < 1; j_index++)
                {
                    int maxBlob = -1;
                    int maxindex = -1;
                    if (DEBUG)
                    {
                        line(matChooseMore, cv::Point(011 + j_index * y_step), cv::Point(matChooseMore.cols - 111 + j_index * y_step), cv::Scalar(00255));
                    }
                    for (size_t blob_index = 0; blob_index < 4; blob_index++)
                    {
                        if (DEBUG)
                        {
                            line(matChooseMore, cv::Point(54 + i_index * 197 + blob_index * x_step, 0), cv::Point(54 + i_index * 197 + blob_index * x_step, matNumber.rows - 1), cv::Scalar(00255));
                        }
                        Mat tmp = matChooseMore(Rect(54 + i_index * 197 + blob_index * x_step, 11 + j_index * y_step, x_step, y_step));
                        Mat tmpGray; Mat tmpBin;
                        cvtColor(tmp, tmpGray, COLOR_BGR2GRAY);
                        threshold(tmpGray, tmpBin, 100255, THRESH_BINARY_INV);
                        int tmpBlob = countNonZero(tmpBin);
                        if (tmpBlob>100)
                        {
                            printf_s("%s", strConvert(blob_index));
                        }
                        if (DEBUG)
                        {
                            char cbuf[255];
                            sprintf_s(cbuf, "%d", tmpBlob);
                            putText(matChooseMore, cbuf, Point(54 + i_index * 197 + blob_index * x_step, 11 + j_index * y_step), FONT_HERSHEY_PLAIN, 1.0f, Scalar(00255));
                        }
                    }
                    printf_s("  ");
                }
            }

识别结果:
1 8371610079632028081800
学号:320210741
单选:c d d c c a a d a d c c c d b b
多选:acd  bd  bd
2 8371610079632028081800
学号:320211633
单选:c d c c b a a d b d c c c d b b
多选:b  abd  d
3 8371610079632028081800
学号:320211632
单选:c d d c b a a a d d c b c d b b
多选:cd  abd  bd
4 8371610079632028081800
学号:320211650
单选:c b c c c a a d b d c c c d b b
多选:cd  abcd  acd
5 8371610079632028081800
学号:320211615
单选:c d a c b a a d b d c c c d c b
多选:acd  abd  bd
6 8371610079632028081800
学号:320211609
单选:c d d c c a a d d d c c c d b b
多选:acd  abd  bd
7 8371610079632028081800
学号:320211642
单选:c a d c b a a a d d c c c d b b
多选:acd  abd  bd
8 8371610079632028081800
学号:320211617
单选:c d d c b a a d d d c c c d b b
多选:ad  ad  bd
9 8371610079632028081800
学号:320211616
单选:d d d c b a a d c d c c c a b b
多选:acd  ad  bcd
10 8371610079632028081800
学号:320211610
单选:c d d c c a a d d d c c c d b b
多选:acd  ad  bd
11 8371610079632028081800
学号:320211622
单选:c d d c b a a d b d c b c a b b
多选:d  abd  b
12 8371610079632028081800
学号:320211026
单选:c b b c b a a a d d c c c d a b
多选:ad  ad  bd
13 8371610079632028081800
学号:320211040
单选:c b a c c a a c b d c c c d a a
多选:b  abd  b
14 8371610079632028081800
学号:320211029
单选:d b d c b a a d a d c c c d b b
多选:cd  abd  bd
15 8371610079632028081800
学号:320211025
单选:c d d c b a a d a d c c c d b b
多选:cd  d  cd
16 8371610079632028081800
学号:320211032
单选:c c b b a a a d c d c c c d b b
多选:ad  ad  bd
17 8371610079632028081800
学号:320211028
单选:c b d c b a b d d d c c c b a b
多选:acd  ad  bd
18 8371610079632028081800
学号:320211010
单选:c b d c b a a d b d c c c d b b
多选:acd  abd  bd
19 8371610079632028081800
学号:320211004
单选:c b d c c a a d d d c d c d b b
多选:ad  ad  bd
20 8371610079632028081800
学号:320211039
单选:d b d c b a a d d d c c c b b b
多选:cd  abd  bd
21 8371610079632028081800
学号:320211018
单选:d b d c b a a d a d c a c d b b
多选:cd  abd  bd
22 8371610079632028081800
学号:320211052
单选:c d d c c b a d b d c c c d b b
多选:cd  ad  bd
23 8371610079632028081800
学号:320211012
单选:c d d c b a a d b d c c c b b b
多选:ad  bd  bd
24 8371610079632028081800
学号:320211024
单选:c d d c c a a d a d c c c d b a
多选:acd  abd  bd
25 8371610079632028081800
学号:320211036
单选:d d d c b a a c b a c c c a b b
多选:ad  ad  bd
26 8371610079632028081800
学号:320211049
单选:d d d c c a a d a b c c c b a b
多选:c  acd  bcd
27 8371610079632028081800
学号:320211047
单选:c d d c b a a d b d c c c b b b
多选:d  ad  bd
28 8371610079632028081800
学号:320211053
单选:c d d c b a c c a d c c c d b b
多选:bcd  cd  bd
29 8371610079632028081800
学号:320211005
单选:d b d c b a a a c d c c c b b a
多选:acd  abd  bd
学号:320211005
单选:d b d c b a a a c d c c c b b a
多选:acd  abd  bd
30 8371610079632028081800
31 8371610079632028081800
学号:320211045
单选:d d d c b a a d b d c d c d b a
多选:bd  cd  bd
32 8371610079632028081800
学号:320211007
单选:d b d c b a a a a d c c b b b a
多选:acd  abd  bcd
33 8371610079632028081800
学号:320211037
单选:c b d c b a d a d d c a c a a b
多选:cd  ab  bd
34 8371610079632028081800
学号:320211046
单选:d d a c b a a d c d c c c a a b
多选:c  bd  b
35 8371610079632028081800
学号:320211035
单选:b b d c b a a d d d c b d a b b
多选:cd  b  b
36 8371610079632028081800
学号:320210718
单选:c d d c c a a d b d c c c a b b
多选:ac  abd  bd
37 8371610079632028081800
学号:320210705
单选:c d d c c a a d b d c c c d b b
多选:acd  abd  bd
38 8371610079632028081800
学号:320210742
单选:d a d c b a a d d d c c c d b b
多选:acd  abd  bd
39 8371610079632028081800
学号:320210755
单选:c a d c b a a d b d c c c d b b
多选:c  abcd  bd
40 8371610079632028081800
学号:320210747
单选:c d a c b b a d d d c c c d b b
多选:cd  ab  bd
41 8371610079632028081800
学号:320210730
单选:c d b c b a a d b d c c c d b b
多选:ad  abd  bd
42 8371610079632028081800
学号:320210727
单选:c b d c c a a d b c c c c d b b
多选:d  abd  cd
43 8371610079632028081800
学号:320210750
单选:c d b c b a b d b a c c c b b b
多选:ad  abcd  bd
44 8371610079632028081800
学号:320210710
单选:c d b c b a a d a d c c c d b d
多选:acd  abd  bcd
45 8371610079632028081800
学号:320210706
单选:c d d c b a a d d d c c c d b b
多选:ad  abd  bd
46 8371610079632028081800
学号:320210702
单选:c d b c b a a d b d c c c b b b
多选:acd  abd  bd
47 8371610079632028081800
学号:320210749
单选:c d c c b a a d b d c c c b b b
多选:bc  abd  bd
48 8371610079632028081800
学号:320210719
单选:c d b c b a a d d d c b c b b b
多选:acd  abd  bd
49 8371610079632028081800
学号:320210726
单选:c d b c b a a d b d c c c d b b
多选:c  abd  bd
50 8371610079632028081800
学号:320210701
单选:c d d c b b a d b d c c c d b b
多选:ad  abd  bd
51 8371610079632028081800
学号:320210714
单选:c d d c b a a d a d c c c d b b
多选:acd  bd  bd
52 8371610079632028081800
学号:320210709
单选:c b b c b a a d d d c c c d b b
多选:cd  abd  bd
53 8371610079632028081800
学号:320210733
单选:c d d c b a a d b d c c d d b b
多选:acd  abcd  bcd
54 8371610079632028081800
学号:320210707
单选:d d d c a a a d d c c c d b b b
多选:acd  d  bd
55 8371610079632028081800
学号:320210744
单选:c d d c b a a d b d c c c d b b
多选:acd  abd  bd
56 8371610079632028081800
学号:320210736
单选:c d d c b a a d d d c c c d b b
多选:bc  abd  cd
57 8371610079632028081800
学号:320210751
单选:b d c c b a a d d d c c c d b b
多选:acd  abd  bd
58 8371610079632028081800
学号:320210716
单选:c d d c b a a d b d c c d d b b
多选:acd  abd  bd
59 8371610079632028081800
学号:320210729
单选:c b b c b a a d a d c c c d b b
多选:acd  ab  bcd
60 8371610079632028081800
学号:320210723
单选:c d a c b a a a d d c c c d b b
多选:acd  acd  bcd
61 8371610079632028081800
学号:320210703
单选:c d d c b a a b b d c c c d b c
多选:abd  ab  bd
62 8371610079632028081800
学号:320210740
单选:c d d c b b a b b d c c c d b b
多选:acd  abd  bd
63 8371610079632028081800
学号:320210748
单选:c d d c b a a b d d d c c d b b
多选:cd  abd  cd
64 8371610079632028081800
学号:320210721
单选:c d b c b a a d b d c c c a b b
多选:acd  abd  bd
65 8371610079632028081800
学号:320210754
单选:d d d c b a a d d d c c c d b b
多选:c  abd  bd
五、小结和扩展
从目前的结果来看,是能够解决当前问题的。但是答题卡项目的难点在于模板的定制以及对于采集质量不好情况的处理,所以这里提到的方法只能作为基础资料进行参考。




附件列表

     

    posted @ 2021-03-05 14:16  jsxyhelu  阅读(120)  评论(0编辑  收藏