You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用OpenCV Python提取MCQ答题卡上的学生ID铅笔标记?

解决OpenCV提取铅笔标记学生ID的问题

问题描述

需要提取MCQ扫描图中的铅笔填写学生ID标记,调整形态学核尺寸后效果仍不理想。

原图:
Original image

当前使用代码:

# Assume student_area is the image posted above

blur_img = cv2.GaussianBlur(student_area,(5,5),0)
#cv2.imshow("gaussian_blur", blur_img)

res, cut_image = cv2.threshold(blur_img, 160, 255, cv2.THRESH_BINARY_INV)
#cv2.imshow("image", cut_image)

# apply morphology close
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,2))
morph = cv2.morphologyEx(cut_image, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, (20,10))

处理后图像:
处理后图像

问题分析

当前代码的核心问题是开运算的核尺寸(20,10)过大,直接把铅笔的细标记腐蚀掉了;另外固定阈值对铅笔这种灰度不均匀的标记适配性差,容易漏检或误检。

改进方案

1. 替换固定阈值为自适应阈值

自适应阈值能根据局部区域的灰度自动调整阈值,更适合铅笔这种边缘模糊、灰度波动的标记。

2. 调整形态学操作的核与顺序

先使用小核的闭合操作强化铅笔标记的连通性,再用匹配标记尺寸的开运算去除噪点,避免过度腐蚀有效标记。

3. 轮廓过滤与中心点计算

提取轮廓后,通过面积过滤掉小噪点,再用cv2.moments()计算每个有效标记的中心点。

改进后的代码

import cv2
import numpy as np

# 假设student_area是输入的灰度图
student_area = cv2.imread("your_image_path.png", 0)

# 1. 高斯模糊去噪
blur_img = cv2.GaussianBlur(student_area, (3, 3), 0)

# 2. 自适应阈值二值化 - 适配铅笔标记的灰度不均
cut_image = cv2.adaptiveThreshold(
    blur_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2
)

# 3. 形态学操作:先闭合强化标记,再开运算去噪
# 闭合核:横向略宽,强化铅笔标记的连通性
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 2))
morph = cv2.morphologyEx(cut_image, cv2.MORPH_CLOSE, close_kernel)

# 开运算核:尺寸匹配单个标记的大小,避免过度腐蚀
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 4))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, open_kernel)

# 4. 提取轮廓并计算中心点
contours, _ = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 过滤小噪点轮廓(根据实际标记面积调整阈值)
min_area = 50
valid_centers = []
for cnt in contours:
    area = cv2.contourArea(cnt)
    if area > min_area:
        M = cv2.moments(cnt)
        if M["m00"] != 0:
            cX = int(M["m10"] / M["m00"])
            cY = int(M["m01"] / M["m00"])
            valid_centers.append((cX, cY))
            # 可选:在图上绘制中心点和轮廓
            cv2.circle(student_area, (cX, cY), 3, (0, 0, 255), -1)
            cv2.drawContours(student_area, [cnt], -1, (0, 255, 0), 1)

# 显示结果
cv2.imshow("Processed Image", morph)
cv2.imshow("Centers Marked", student_area)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 输出有效中心点
print("提取到的标记中心点:", valid_centers)

关键调整说明

  • 自适应阈值用ADAPTIVE_THRESH_GAUSSIAN_C,结合邻域大小11和常数2,能更好保留铅笔的淡标记。
  • 形态学核尺寸缩小到匹配单个标记的宽度(6,4),既去除噪点又保留有效标记。
  • 增加轮廓面积过滤,排除小的噪点轮廓,确保只处理真实的铅笔标记。

内容的提问来源于stack exchange,提问作者Rohan Chhabra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 09:15:57