首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Another method for detecting the positioning points on an answer sheet

Another method for detecting the positioning points on an answer sheet

原创
作者头像
Swing Dunn
发布2025-10-15 17:47:44
发布2025-10-15 17:47:44
730
举报
文章被收录于专栏:答题卡识别答题卡识别

Since the positioning block area on the answer sheet is a non-answering zone, there are relatively few interfering factors, and the positioning block detection belongs to the search of black rectangular blocks with clear targets. Therefore, the target area can be found by following the idea of searching for the maximum filled area within the sliding window.

Expand the specific area coordinates provided by the template as the window for target retrieval, search for the maximum filled area within the form, and then find the accurate target area through edge indentation. Count the filling ratio of the target area. If it meets the filling threshold, it is considered that the positioning block has been found.

Slide to search for the target area in the target window. The process is shown as follows:

The failed search results are displayed as follows(error threshold value for display):

Finally, all experiments are concluded:

Sorce code:

代码语言:txt
复制

import cv2
import os
import numpy as np
import sys

global_extendsize = 40

# 读取目标图像和模板图像
def show_image(img):
    cv2.namedWindow("1",cv2.WINDOW_FREERATIO)
    cv2.imshow("1",img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def detect_archor_block(gray, temp_archor):
    #模板定位点的位置和大小
    height, width = gray.shape[:2]
    ar_lt_pt = (temp_archor[0],temp_archor[1])
    ar_width = temp_archor[2]
    ar_height = temp_archor[3]
    ar_rb_pt = (ar_lt_pt[0] + ar_width, ar_lt_pt[1] + ar_height)

    # cv2.rectangle(gray,ar_lt_pt ,ar_rb_pt, (0,0,255),2)
    #向各个方向外扩75个像素
    expand_range_lt = (ar_lt_pt[0] - global_extendsize if ar_lt_pt[0] - global_extendsize > 0 else 0, ar_lt_pt[1] - global_extendsize if ar_lt_pt[1] - global_extendsize > 0 else 0)
    expand_range_rb = (ar_rb_pt[0] + global_extendsize if ar_rb_pt[0] + global_extendsize < width else width  , ar_rb_pt[1] + global_extendsize if ar_rb_pt[1] + global_extendsize < height else height)
    # cv2.rectangle(gray,expand_range_lt ,expand_range_rb, (0,0,255),2)
    
    aim_range_image = gray[expand_range_lt[1]:expand_range_rb[1], expand_range_lt[0]: expand_range_rb[0]]

    display_aim_img = cv2.cvtColor(aim_range_image, cv2.COLOR_GRAY2BGR)
    #show_image(aim_range_image) 
    
    aim_range_height= aim_range_image.shape[0]  
    aim_range_width = aim_range_image.shape[1]

    max_pixelSum = sys.maxsize
    target_h_start = 0
    for col in range(0,aim_range_width - ar_width):
        aim_h_img = aim_range_image[ : ,col: col + ar_width]
        sum_pixel = np.sum(aim_h_img)
        if sum_pixel < max_pixelSum:
            max_pixelSum = sum_pixel
            target_h_start = col
        #show_image(aim_h_img) 
    cv2.rectangle(display_aim_img,(target_h_start,0) ,(target_h_start + ar_width, aim_range_height), (0,255,255),2)

    max_pixelSum = sys.maxsize
    target_v_start = 0
    for row in range(0, aim_range_height - ar_height):
        aim_v_img = aim_range_image[row : row + ar_height,target_h_start: target_h_start + ar_width]
        sum_pixel = np.sum(aim_v_img)
        if sum_pixel < max_pixelSum:
            max_pixelSum = sum_pixel
            target_v_start = row
    cv2.rectangle(display_aim_img,(target_h_start,target_v_start) ,(target_h_start + ar_width, target_v_start + ar_height), (0,165,255),1)

    target_range_img = aim_range_image[target_v_start : target_v_start + ar_height, target_h_start: target_h_start + ar_width]

    gray_average = np.sum(target_range_img) / target_range_img.size
    l_scaled_level = 0
    for i in  range(0,2):
        target_range_height = target_range_img.shape[0]
        target_range_width = target_range_img.shape[1]
        l_scaled_img = target_range_img[0: target_range_height, 1: target_range_width]
        l_scaled_img_average = np.sum(l_scaled_img) / l_scaled_img.size
        if(l_scaled_img_average < gray_average):
            gray_average = l_scaled_img_average
            target_range_img = l_scaled_img.copy()
            l_scaled_level = i

    t_scaled_level = 0
    for i in  range(0,2):
        target_range_height = target_range_img.shape[0]
        target_range_width = target_range_img.shape[1]
        t_scaled_img = target_range_img[1: target_range_height, 0: target_range_width]
        t_scaled_img_average = np.sum(t_scaled_img) / t_scaled_img.size
        if(t_scaled_img_average < gray_average):
            gray_average = t_scaled_img_average
            target_range_img = t_scaled_img.copy()
            t_scaled_level = i

    r_scaled_level = 0
    for i in  range(0,2):
        target_range_height = target_range_img.shape[0]
        target_range_width = target_range_img.shape[1]
        r_scaled_img = target_range_img[0: target_range_height, 0: target_range_width - 1]
        r_scaled_img_average = np.sum(r_scaled_img) / r_scaled_img.size
        if(r_scaled_img_average < gray_average):
            gray_average = r_scaled_img_average
            target_range_img = r_scaled_img.copy()
            r_scaled_level = i

    b_scaled_level = 0
    for i in  range(0,2):
        target_range_height = target_range_img.shape[0]
        target_range_width = target_range_img.shape[1]
        b_scaled_img = target_range_img[0: target_range_height - 1, 0 : target_range_width]
        b_scaled_img_average = np.sum(b_scaled_img) / b_scaled_img.size
        if(b_scaled_img_average < gray_average):
            gray_average = b_scaled_img_average
            target_range_img = b_scaled_img.copy()
            b_scaled_level = i

    final_start_x = target_h_start + l_scaled_level
    final_start_y = target_v_start + t_scaled_level

    final_end_x = target_h_start + ar_width - r_scaled_level
    finale_end_y = target_v_start + ar_height - b_scaled_level

    cv2.rectangle(display_aim_img,(final_start_x,final_start_y) ,(final_end_x, finale_end_y), (255,0,0),1)
    
    #display_bin_img = np.where(target_range_img > 56, 255, 0)
    #display_bin_img = cv2.convertScaleAbs(display_bin_img)
    #show_image(display_aim_img)

    result_arr = np.where(target_range_img > 178 , 0, 1)
    print_input_rate = np.sum(result_arr) / target_range_img.size
    print('印刷填涂率为:' ,print_input_rate)

    find : bool =  False
    if print_input_rate > 0.9:
        find = True
        result_rect = (expand_range_lt[0] +  final_start_x, expand_range_lt[1] +  final_start_y,final_end_x - final_start_x, finale_end_y - final_start_y)
    else:
        find = False
        result_rect = (expand_range_lt[0],  expand_range_lt[1], expand_range_rb[0],  expand_range_rb[1])

    _,binary = cv2.threshold(aim_range_image, 58,255, cv2.THRESH_BINARY)
   
    # cv2.rectangle(display_aim_img,(result_rect[0],result_rect[1]) ,(result_rect[0] + result_rect[2],result_rect[1] + result_rect[3]), (0,255,0),2) 
    # show_image(display_aim_img)
    return find, result_rect, binary

def main():
    folder_path = './imgs4'
    #模板定位点信息
    temp_block_info =[(73, 126, 47, 30), (1526, 124, 47, 30),(76, 2166, 46, 31),(1530, 2160, 49, 32)]
    paper_num = 0
    error_paper_num = 0
    
    # 递归遍历文件夹
    for root, dirs, files in os.walk(folder_path):
        for filename in files:
            if filename.lower().endswith('.jpg'):
                file_path = os.path.join(root, filename)
                ori_img = cv2.imread(file_path, cv2.IMREAD_ANYCOLOR)  # 目标图像
                if len(ori_img.shape) == 3 and ori_img.shape[2] == 3:
                    gray_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
                elif len(ori_img.shape) == 2:
                    gray_img = ori_img.copy()
                else:
                    print('error: bad image')
                    return                

                #show_image(img)
                paper_num += 1
                lt_archor = temp_block_info[0]
                rt_archor = temp_block_info[1]
                lb_archor = temp_block_info[2]
                rb_archor = temp_block_info[3]

                # cv2.rectangle(ori_img,(lt_archor[0], lt_archor[1]) ,(lt_archor[0] +lt_archor[2] ,lt_archor[1] +lt_archor[3]), (0,0,255),2)
                # show_image(ori_img)
                #左上
                print(f"检测第{paper_num}试卷")
                exist_nofound = False

                find, re_lt_rect ,aim_binary =  detect_archor_block(gray_img, lt_archor)   
                if(find):
                    cv2.rectangle(ori_img,(re_lt_rect[0], re_lt_rect[1]) ,(re_lt_rect[0] +re_lt_rect[2] ,re_lt_rect[1] +re_lt_rect[3]), (0,0,255),2)
                else:
                    display_binary= cv2.cvtColor(aim_binary, cv2.COLOR_GRAY2BGR)
                    ori_img[re_lt_rect[1]:re_lt_rect[3], re_lt_rect[0]:re_lt_rect[2]] = display_binary
                    exist_nofound = True
                    print(f"第{paper_num}试卷 左上定位点缺失") 
                    
            
                #右上
                find, re_rt_rect ,aim_binary =  detect_archor_block(gray_img, rt_archor)
                if(find):
                    cv2.rectangle(ori_img,(re_rt_rect[0], re_rt_rect[1]) ,(re_rt_rect[0] +re_rt_rect[2] ,re_rt_rect[1] +re_rt_rect[3]), (0,0,255),2)
                else:
                    display_binary= cv2.cvtColor(aim_binary, cv2.COLOR_GRAY2BGR)
                    ori_img[re_rt_rect[1]:re_rt_rect[3], re_rt_rect[0]:re_rt_rect[2]] = display_binary
                    exist_nofound = True
                    print(f"第{paper_num}试卷 右上定位点缺失") 

                #左下
                find, re_lb_rect ,aim_binary =  detect_archor_block(gray_img, lb_archor)
                if(find):
                    cv2.rectangle(ori_img,(re_lb_rect[0], re_lb_rect[1]) ,(re_lb_rect[0] +re_lb_rect[2] ,re_lb_rect[1] +re_lb_rect[3]), (0,0,255),2)
                else:
                    display_binary= cv2.cvtColor(aim_binary, cv2.COLOR_GRAY2BGR)
                    ori_img[re_lb_rect[1]:re_lb_rect[3], re_lb_rect[0]:re_lb_rect[2]] = display_binary
                    exist_nofound = True
                    print(f"第{paper_num}试卷 左下定位点缺失") 

                #右下
                find, re_rb_rect ,aim_binary =  detect_archor_block(gray_img, rb_archor)
                if(find):
                    cv2.rectangle(ori_img,(re_rb_rect[0], re_rb_rect[1]) ,(re_rb_rect[0] +re_rb_rect[2] ,re_rb_rect[1] +re_rb_rect[3]), (0,0,255),2)
                else:
                    display_binary= cv2.cvtColor(aim_binary, cv2.COLOR_GRAY2BGR)
                    ori_img[re_rb_rect[1]:re_rb_rect[3], re_rb_rect[0]:re_rb_rect[2]] = display_binary
                    exist_nofound = True
                    print(f"第{paper_num}试卷 右下定位点缺失") 

                if exist_nofound:
                    error_paper_num += 1
                    show_image(ori_img)

                print(f"已检测{paper_num}张试卷, {error_paper_num}张试卷存在定位点检测缺失, 识别率{1 - error_paper_num / paper_num}")
                       
                print()

if __name__ == '__main__':
    main()

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

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

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

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

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