如何从OMR答题卡提取标记答案?代码调试求助
OMR答题卡标记答案转换为指定格式的解决方案
核心问题分析
固定box_size计算行列失效,本质是答题卡拍摄时的倾斜、缩放偏差导致预设尺寸和实际坐标不匹配,硬调尺寸解决不了问题,得换坐标分组逻辑。
可行解决方案
1. 用聚类算法替代固定尺寸划分行列
直接对质心坐标做聚类,自动分组题目行和选项列,完全适配坐标偏移:
- 按y坐标聚类划分题目:把所有标记质心的y坐标提取出来,用K-Means聚类成对应题目数量的组(比如目标格式有13个值就分13组),每组对应一道题的行位置。
- 按x坐标匹配对应选项:对每道题内的质心x坐标聚类,找到标记位置后和预设的选项x基准位置匹配,得到选项序号;没有标记的题目填0。
- 生成目标格式字符串:把每道题的结果按顺序拼接成逗号分隔的字符串。
2. 可运行代码示例
import numpy as np from sklearn.cluster import KMeans # 替换成你实际获取的标记质心列表 centroids = [(120, 210), (310, 210), (118, 405), ...] num_questions = 13 # 对应目标格式的13个数值 num_options = 5 # 假设每题有5个选项(1-5) # 替换成你空白答题卡上各选项的基准x坐标(提前提取好的) preset_option_x = [100, 200, 300, 400, 500] # 按y坐标聚类分组题目行 y_coords = np.array([[y] for x, y in centroids]) row_cluster = KMeans(n_clusters=num_questions, random_state=42).fit(y_coords) # 按行位置从顶到底排序聚类中心 sorted_row_centers = sorted(row_cluster.cluster_centers_.flatten()) # 初始化结果列表,默认全为0 result = [0] * num_questions for row_idx in range(num_questions): # 找到当前行对应的所有质心 current_row_centroids = [] for idx, centroid in enumerate(centroids): # 匹配当前行的聚类标签 if row_cluster.labels_[idx] == np.argmin(np.abs(sorted_row_centers - row_cluster.cluster_centers_[row_idx])): current_row_centroids.append(centroid) if not current_row_centroids: continue # 该行无标记,跳过 # 找到当前标记的x坐标中心 x_coords = np.array([[x] for x, y in current_row_centroids]) x_center = KMeans(n_clusters=1, random_state=42).fit(x_coords).cluster_centers_[0][0] # 匹配最接近的选项序号 option_num = np.argmin(np.abs(preset_option_x - x_center)) + 1 result[row_idx] = option_num # 生成目标格式的字符串 output_str = ",".join(map(str, result)) print(output_str)
3. 必做前置优化
- 先做透视矫正:如果答题卡拍歪了,先用四个角点把图像矫正成正矩形,确保所有气泡的坐标规整,这能大幅降低后续处理的误差。
- 提前提取基准坐标:找一张空白答题卡,提取所有气泡的质心,保存每行的y坐标和每列的x坐标作为预设值,比纯聚类更准确。
- 过滤误标记:识别时加面积阈值,只保留面积符合气泡大小的标记,排除噪点或划痕导致的假质心。
内容的提问来源于stack exchange,提问作者S M
相关产品推荐
相关产品推荐

