当前位置:   article > 正文

opencv 智能答卷识别系统(二) 自动阅卷_cv如何自动识别试卷上的空白区域

cv如何自动识别试卷上的空白区域

智能识别答卷二

这是一,可以参考 智能答卷识别系统一

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

识别答案

两个最重要的部分就是如何识别答案,注意是可以识别多选题的

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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

识别结果

答案和学号识别
我们根据答案的排列顺序来识别,里面最重要的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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号