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

OpenCV Python中如何区分圆形轮廓与字母/数字轮廓?

问题原因

你当前通过approxPolyDP拟合轮廓后判断边数的筛选逻辑鲁棒性极低:字母、数字中的类封闭曲线(如0、O、Q)、边缘带毛刺的轮廓,拟合后的边数很容易落在你设置的8-23区间内,自然会出现大量误检。

高鲁棒性圆形筛选方案

组合使用以下几何特征约束,基本可以完全区分目标圆形与字母/数字轮廓,不需要复杂的模型方案:

  • 圆度校验(核心判定条件):正圆的圆度值为1,越接近1说明轮廓形状越接近正圆,计算公式为圆度 = 4 * π * 轮廓面积 / (轮廓周长的平方)。你场景里的规整填涂类圆形,圆度普遍在0.85以上;而字母、数字哪怕是类圆形的0、O,受字体设计、笔画粗细变化影响,圆度基本都在0.7以下,设置0.8的阈值即可筛掉90%以上的误检。
  • 宽高比校验:正圆的最小外接旋转矩形为正方形,宽高比为1。计算每个轮廓的最小外接旋转矩形,要求宽高比在0.9~1.1区间内,即可直接排除扁形、长条形的字符轮廓。
  • 面积范围约束:你当前仅设置了面积大于30的阈值,过于宽松。提前统计图中目标圆形的实际像素面积,设置合理的上下限(比如目标圆面积集中在100-200像素区间,就仅保留该范围的轮廓),过大、过小的干扰轮廓会被快速排除,字符轮廓的面积普遍远小于目标填涂圆,这一步可筛掉大半干扰。
  • 凸性校验:正圆是完全凸的形状,凸包面积与轮廓自身面积的比值接近1。而B、8、D这类带凹陷的字符,凸性值会明显低于0.9,增加该条件可进一步筛掉带内凹的非圆轮廓。

如果是固定机位拍摄的固定版式场景(比如答题卡识别),还可以提前定位到填涂区域的ROI后再做轮廓检测,直接避开题号、字符印刷区域,准确率会进一步提升,几乎不会出现误检。

改进后代码
import cv2
import math

cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contour_list = []

# 以下阈值可根据你的实际图像调整
MIN_AREA = 80
MAX_AREA = 300
MIN_CIRCULARITY = 0.8
MIN_ASPECT_RATIO = 0.9
MAX_ASPECT_RATIO = 1.1
MIN_CONVEXITY = 0.9

for contour in cnts:
    area = cv2.contourArea(contour)
    # 优先筛面积,计算最快,提前排除小干扰
    if area < MIN_AREA or area > MAX_AREA:
        continue

    perimeter = cv2.arcLength(contour, True)
    if perimeter == 0:
        continue
    # 圆度校验
    circularity = 4 * math.pi * area / (perimeter ** 2)
    if circularity < MIN_CIRCULARITY:
        continue

    # 外接旋转矩形宽高比校验
    rect = cv2.minAreaRect(contour)
    w, h = rect[1]
    if h == 0 or w == 0:
        continue
    aspect_ratio = w / h if w > h else h / w
    if aspect_ratio < MIN_ASPECT_RATIO or aspect_ratio > MAX_ASPECT_RATIO:
        continue

    # 凸性校验
    hull = cv2.convexHull(contour)
    hull_area = cv2.contourArea(hull)
    if hull_area == 0:
        continue
    convexity = area / hull_area
    if convexity < MIN_CONVEXITY:
        continue

    contour_list.append(contour)

mcq = cv2.drawContours(paper, contour_list, -1, (255, 0, 0), 1)
cv2.imshow("thresh", thresh)
cv2.imshow("mcq", mcq)
cv2.waitKey(0)

内容的提问来源于stack exchange,提问作者Joshua Yang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:33:22