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:
1. Locate the question block area(pic 1) - Select the question area - Expand the options area (search window - pic2)
2. Sliding search in the X direction (the brown area)
3. Within the brown area, perform a sliding search in the Y direction (the yellow area)
4. Reduce the borders in all four directions (the borders before reduction are green, and the final area is red)
5.Applying to the entire paper:
main source code:
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 删除。