主要是参考文献:一种答题卡客观题识别算法 --要曙丽 1, 王少荣 1,2, 盖 孟 2,3, 王 震 4 ,略做修改实现,思路可以参考原论文。
按照这篇论文中寻找目标区域的方法,可以一定程度上规避由于学生填涂偏移造成的误差,相对于之前使用的外扩矩形中直接进行二值统计的方法,也更大程度上减少了额外的干扰区域,对于客观题识别准确度有一定的提高。
过程:
1.找到题块区域-选择题区域-选项外扩区域(搜索窗口)
==============》
2.X方向上滑动搜索(棕色区域)
3.棕色区域内,在Y方向滑动搜索(黄色区域)
4.四个方向上缩边(缩边前为绿色,最终区域为红色)
对于整张试卷:
主要代码:
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 删除。