opencv 智能答卷识别系统(二) 自动阅卷
智能识别答卷二这是一,可以参考 智能答卷识别系统一A 、根据条件去截取多个区域1、 姓名班级考场这一步可以使用文字识别来做,也可以去除,因为哪一张考卷是谁的,证件号码是可以识别的,这里是为了冗余而做。2、 证件号码3、 答案区域把这三个部分都识别出来,就好办了show me the main code主程序是通过试卷上面的标记来识别是哪一种试卷,然后分割出自己要的三部分区域,然后,重点,就是识别函
·
智能识别答卷二
这是一,可以参考 智能答卷识别系统一
A 、根据条件去截取多个区域
1、 姓名班级考场

这一步可以使用文字识别来做,也可以去除,因为哪一张考卷是谁的,证件号码是可以识别的,这里是为了冗余而做。
2、 证件号码

3、 答案区域

把这三个部分都识别出来,就好办了
show me the main code
主程序是通过试卷上面的标记来识别是哪一种试卷,然后分割出自己要的三部分区域,然后,重点,就是识别函数
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;
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)