首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >基于滑动窗口的填涂范围寻找

基于滑动窗口的填涂范围寻找

原创
作者头像
sw_deng
发布2025-10-10 17:35:20
发布2025-10-10 17:35:20
550
举报
文章被收录于专栏:答题卡识别答题卡识别

主要是参考文献:一种答题卡客观题识别算法 --要曙丽 1, 王少荣 1,2, 盖 孟 2,3, 王 震 4 ,略做修改实现,思路可以参考原论文。

按照这篇论文中寻找目标区域的方法,可以一定程度上规避由于学生填涂偏移造成的误差,相对于之前使用的外扩矩形中直接进行二值统计的方法,也更大程度上减少了额外的干扰区域,对于客观题识别准确度有一定的提高。

过程:

1.找到题块区域-选择题区域-选项外扩区域(搜索窗口)

==============》

2.X方向上滑动搜索(棕色区域)

3.棕色区域内,在Y方向滑动搜索(黄色区域)

4.四个方向上缩边(缩边前为绿色,最终区域为红色)

对于整张试卷:

主要代码:

代码语言:txt
复制
void publicImgTools::detect_aim_optrect(cv::Mat& gray, vector<new_optBlock>& opt_blocks)
{

#ifdef DEBUG_OUTPUT	
	Mat orignal_img;
	cv::cvtColor(gray, orignal_img, COLOR_GRAY2BGR);
#endif

	for (auto& opt_block : opt_blocks)
	{
		//题块外接矩形
		cv::Rect block_rect = opt_block.block_rect;
		cv::Mat optblock_area = gray(block_rect);
		//publicImgTools::show_img(optblock_area);
		for (auto& ques_block : opt_block.opts_info)
		{
			//单个选择题外接矩形
			cv::Rect opt_round_rect = ques_block.round_rect;
			cv::Mat opt_area = gray(opt_round_rect);
			//publicImgTools::show_img(opt_area);

			cv::Rect target_rect;
			for (auto rect : ques_block.opt_rects)
			{
				//选择题选项快扩矩形(搜索窗口)
				cv::Rect expand_rect(rect.x - 10, rect.y - 5, rect.width + 20, rect.height + 10);
				cv::Mat exp_choice_area = gray(expand_rect);				
				//publicImgTools::show_img(exp_choice_area);

				int sum_pixel = std::numeric_limits<int>::max();
				int max_x = 0;
				int max_y = 0;
				for (int row = 0; row < exp_choice_area.cols - rect.width - 1; row++)
				{
					cv::Rect x_aim_range = cv::Rect(row, 0, rect.width, exp_choice_area.rows);
					
					/*Mat temp;
					cv::cvtColor(exp_choice_area, temp, COLOR_GRAY2BGR);
					cv::rectangle(temp, x_aim_range, Scalar(0, 0, 255), 2);
					publicImgTools::show_img(temp);*/

					cv::Mat x_aim_area = exp_choice_area(x_aim_range);
					int total_pixelcount = publicImgTools::count_gray_pixelSum(x_aim_area);
					if (total_pixelcount < sum_pixel)
					{
						sum_pixel = total_pixelcount;
						max_x = row;
					}
				}
#ifdef DEBUG_OUTPUT				
				Mat temp;
				cv::cvtColor(exp_choice_area, temp, COLOR_GRAY2BGR);

				cv::Rect x_aim_range = cv::Rect(max_x, 0, rect.width, exp_choice_area.rows);
				cv::rectangle(temp, x_aim_range, Scalar(19, 69, 139), 2);
				//publicImgTools::show_img(temp);
#endif

				sum_pixel = std::numeric_limits<int>::max();
				for (int col = 0; col < exp_choice_area.rows - rect.height - 1; col++)
				{
					cv::Rect y_aim_range = cv::Rect(max_x, col, rect.width, rect.height);

					/*Mat temp;
					cv::cvtColor(exp_choice_area, temp, COLOR_GRAY2BGR);
					cv::rectangle(temp, x_aim_range, Scalar(0, 0, 255), 2);
					publicImgTools::show_img(temp);*/

					cv::Mat y_aim_area = exp_choice_area(y_aim_range);
					int total_pixelcount = publicImgTools::count_gray_pixelSum(y_aim_area);
					if (total_pixelcount < sum_pixel)
					{
						sum_pixel = total_pixelcount;
						max_y = col;
					}
				}

#ifdef DEBUG_OUTPUT		
				cv::Rect final_aim_range = cv::Rect(max_x, max_y, rect.width, rect.height);
				cv::rectangle(temp, final_aim_range, Scalar(0, 255, 255), 2);
				//publicImgTools::show_img(temp);
#endif
				target_rect.x = expand_rect.x + max_x;
				target_rect.y = expand_rect.y + max_y;
				target_rect.width = rect.width;
				target_rect.height = rect.height;
#ifdef DEBUG_OUTPUT	
				cv::rectangle(orignal_img, target_rect, Scalar(0, 255, 0), 1);		
#endif

				cv::Mat target_area = gray(target_rect);
				double gray_v = publicImgTools::count_gray_pixelSum(target_area) / (double)(target_area.rows * target_area.cols);

				int data_lx = down_scale_rect(target_area, gray_v,2,0);
				if (data_lx > 0)
					target_rect.x = target_rect.x + data_lx;
				target_area = gray(target_rect);
				gray_v = publicImgTools::count_gray_pixelSum(target_area) / (double)(target_area.rows * target_area.cols);

				int data_ty = down_scale_rect(target_area, gray_v, 2, 1);
				if (data_ty > 0)
					target_rect.y = target_rect.y + data_ty;
				target_area = gray(target_rect);
				gray_v = publicImgTools::count_gray_pixelSum(target_area) / (double)(target_area.rows * target_area.cols);
				
				int data_rx = down_scale_rect(target_area, gray_v, 2, 2);
				if (data_rx > 0)
					target_rect.width = target_rect.width - data_rx;
				target_area = gray(target_rect);
				gray_v = publicImgTools::count_gray_pixelSum(target_area) / (double)(target_area.rows * target_area.cols);

				int data_by = down_scale_rect(target_area, gray_v, 2, 3);
				if (data_by > 0)
					target_rect.height = target_rect.height - data_by;
				target_area = gray(target_rect);
				gray_v = publicImgTools::count_gray_pixelSum(target_area) / (double)(target_area.rows * target_area.cols);

#ifdef DEBUG_OUTPUT	
				cv::rectangle(orignal_img, target_rect, Scalar(0, 0, 255), 1);
#endif
			}
		}


#ifdef DEBUG_OUTPUT
		cv::Mat display_img = orignal_img(block_rect);
		publicImgTools::show_img(orignal_img);
#endif
	}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档