赞
踩
这是一,可以参考 智能答卷识别系统一
这一步可以使用文字识别来做,也可以去除,因为哪一张考卷是谁的,证件号码是可以识别的,这里是为了冗余而做。
把这三个部分都识别出来,就好办了
主程序是通过试卷上面的标记来识别是哪一种试卷,然后分割出自己要的三部分区域,然后,重点,就是识别函数
int main(int argc, char** argv) { #if 0 if (argc < 2) { std::cout << "please use .exe filename.tif"; return 0; } const char * fname = argv[1]; #endif #if 1 const char * fname = "D:/opencv/2.tif"; #endif //const char * fname = "D:/4.tif"; Mat img,gray; //声明一个保存图像的类 img = imread(fname); //读取图像,根据图片所在位置填写路径即可 if (img.empty()) { cout << "the file is empty" << endl; return -1; } cv::cvtColor(img, gray, COLOR_BGR2GRAY); int up_flag_rect = 0; cv::Rect answer_rect,id_rect; Mat imgid, imgan,imname; if (findpos(gray, up_flag_rect, answer_rect) == 0 && up_flag_rect == 6) { Rect rect_id(615 + 5, 395 + 5, 507 - 10, 328 - 10); imgid = gray(rect_id); //识别出来 Rect rect_an(answer_rect.x+5 , answer_rect.y+5, answer_rect.width - 10, answer_rect.height - 10); imgan = gray(rect_an); Rect rect_name(800, 780, 250, 62); imname = img(rect_name); } else if(up_flag_rect == 8) { Rect rect_id(531 + 5, 438 + 5, 507 - 10, 328 - 10); imgid = gray(rect_id); //imgid = gray(rect_id); Rect rect_an(125 + 16, 1080 + 16, 1405 - 32, 369 - 32); imgan = gray(rect_an); Rect rect_name(1180, 480, 250, 70); imname = img(rect_name); } else { cout << "flag error,can not use this or not support" << endl; } //recognizeText(imname); //531 438 507 328 //125 1080 1405 369 cv::imshow("1", imgid); cv::imshow("2", imname); cv::imshow("3", imgan); cv::waitKey(0); #if 0 cv::imshow("id", imgid); //cv::imshow("answer", imgan); cv::waitKey(0); return 0; #endif #if 1 main_idfind(imgid); main_answerfind(imgan); #endif }
两个最重要的部分就是如何识别答案,注意是可以识别多选题的
int find_answer(int row, int col, vector<Rect>& rec, int start, int end ) { #define _Gap_Answer_ 7 //cout << "process row:" << row << " col:" << col << endl; #define _Ratio_ 1.2f //找出面积最大的那个,并且是长大于宽 int area = 0; int num = 0; //找到最大面积的 for (int i = start; i < end; i++) { if (rec[i].area() > area) { area = rec[i].area(); num = i; } } int size = end - start; int r = start + 1; //跳过第一个数字 if (rec[start + 1].x - (rec[start].x + rec[start].width) < 3) { r++;//两个数字在一起,如11 22,跳过第二个数字 } //组位置探测 int pos = -1; s_rowcol group; //一个测试group 也就是一个 1 [ A ] [ B ] [ C ] [ D ] group.row = row; group.col = col; for (int i = r; i < end; i++) { int gap1 = rec[i].x - (rec[i - 1].x + rec[i - 1].width); if (gap1 > _Gap_Answer_) //碰到了组开头 如 [ A ] 或者 [ B ] 或者 描写的答案 { ++pos; //pos初始值为-1 float ratio = (float)rec[i].width / (float)rec[i].height; if (i < end - 1) {//不是最后一个 int gap2 = rec[i+1].x - (rec[i].x + rec[i].width); if ((gap2 > _Gap_Answer_) && (i ==num || (ratio > _Ratio_))) { if (group.detect < group.an) {//A B C D E F 多了说明判断错误 group.detect++; //探测到的答案 group.answer[pos] = 1; } else { cout << "error! what happened? >F?" << endl; } } } else //组最后一个,不用判断后面空隙 { if (ratio > _Ratio_) if (group.detect < group.an) { group.detect++;//探测到的答案 group.answer[pos] = 1; } else { cout << "error! what happened? >F?" << endl; } } } } g_answer.push_back(group); return pos; }
我们根据答案的排列顺序来识别,里面最重要的1 是排序 2 是图像处理的基本函数.最基本的如二值化,寻找轮廓,膨胀腐蚀操作都是基础,这是必须熟练的,所有的一切都是基本功扎实才能做出好的程序。
int main_answerfind(Mat gray) { #if 0 Mat img; //声明一个保存图像的类 img = imread("D:/answer.tif"); //读取图像,根据图片所在位置填写路径即可 if (img.empty()) //判断图像文件是否存在 { std::cout << "请确认图像文件名称是否正确" << endl; return -1; } #endif //Mat gray; //cv::cvtColor(img, gray, COLOR_BGR2GRAY); threshold(gray, gray, 100, 255, THRESH_BINARY_INV); gray = MyDilate2(gray); vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(gray, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); //drawContours(dstImage, contours, -1, (255, 255, 255)); vector<Rect> recs; vector<vector<Point>>::iterator It; for (It = contours.begin(); It < contours.end(); It++) { //画出可包围数字的最小矩形 Rect rect = boundingRect(*It); if (rect.area()>16 && rect.width < 400 && rect.height<400 && rect.width>3 && rect.width<100 && rect.height>6) { #if 0 Point2f vertex[4]; vertex[0] = rect.tl(); //矩阵左上角的点 vertex[1].x = (float)rect.tl().x, vertex[1].y = (float)rect.br().y; //矩阵左下方的点 vertex[2] = rect.br(); //矩阵右下角的点 vertex[3].x = (float)rect.br().x, vertex[3].y = (float)rect.tl().y; //矩阵右上方的点 for (int j = 0; j < 4; j++) line(img, vertex[j], vertex[(j + 1) % 4], Scalar(0, 0, 255), 1); #endif recs.push_back(rect); } } vector<int> col_nums; sort_y2(recs,col_nums); process_lines(recs,col_nums); process_answer(g_answer); // #if 0 cv::imshow("gray", gray); cv::imshow("img", img); cv::waitKey(0); #endif return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。