首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Search for the filling range based on the sliding window

Search for the filling range based on the sliding window

原创
作者头像
Swing Dunn
发布2025-10-17 09:33:53
发布2025-10-17 09:33:53
560
举报
文章被收录于专栏:答题卡识别答题卡识别

Mainly references[一种答题卡客观题识别算法 --要曙丽. 王少荣. 盖 孟. 王 震 ]

Based on this paper, some modifications have been made to achieve the result. The thinking process can be referred to in the original paper.

According to the method for locating the target area described in this paper, it applies some extent to avoid the errors caused by the deviation of students' filling. Compared with the previous method of directly conducting binary statistics within the expanded rectangle, it also reduces the additional interference areas to a greater extent, and has a certain improvement in the accuracy of objective question recognition.

process of algo
process of algo

Process:

1. Locate the question block area(pic 1) - Select the question area - Expand the options area (search window - pic2)

1.block area
1.block area
2.search window
2.search window

2. Sliding search in the X direction (the brown area)

X_range
X_range

3. Within the brown area, perform a sliding search in the Y direction (the yellow area)

Y_range based on previous x_range
Y_range based on previous x_range

4. Reduce the borders in all four directions (the borders before reduction are green, and the final area is red)

down scaled range_final target area
down scaled range_final target area

5.Applying to the entire paper:

result of detection
result of detection

main source code:

代码语言:txt
复制
void detect_aim_optrect(cv::Mat& gray, vector<new_optBlock>& opt_blocks)
{
	Mat orignal_img;
	cv::cvtColor(gray, orignal_img, COLOR_GRAY2BGR);
	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;
					}
				}			
				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);

				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;
					}
				}

				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);
				
				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;
				
				cv::rectangle(orignal_img, target_rect, Scalar(0, 255, 0), 1);		

				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);

				cv::rectangle(orignal_img, target_rect, Scalar(0, 0, 255), 1);
			}
		}
		cv::Mat display_img = orignal_img(block_rect);
		publicImgTools::show_img(orignal_img);
	}

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

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

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

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

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