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

使用Python OpenCV检测矩形角点时的异常问题求助

光学标记识别(OMR)轮廓检测不稳定问题

我正尝试使用Python OpenCV实现光学标记识别(OMR)。程序流程为先通过预处理“滤镜”将原始图像转换为二值图像,随后进行轮廓检测。二值图像乍看效果不错,但对部分相似图像应用轮廓检测时,结果时好时坏。

现有代码

预处理函数

def PreProcessing(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    ret, imgThresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    return imgThresh

角点检测函数

def findCorners(canny):
    contourCounter = 0
    points1 = []
    points2 = []
    contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 400000 and area < 2500000:
            epsilon = 0.001 * cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, epsilon, True)
            for point in approx:
                x, y = point[0]
                if contourCounter == 0:
                    points1.append((x, y))
                elif contourCounter == 1:
                    points2.append((x, y))
            contourCounter += 1
    if contourCounter != 2:
        raise Exception(f"the number of big contours detacted is {contourCounter}")
    return points1 , points2

示例情况

  • 有效示例:原始图像经处理后能正确检测到2个目标轮廓,输出对应角点。
  • 无效示例:原始图像处理后无法检测到2个目标轮廓,触发异常。

问题分析与解决方案

1. 预处理环节鲁棒性不足

无效示例的二值图可能因光照不均导致阈值分割失效,或目标区域出现断裂。可通过以下方式优化:

  • 改用自适应阈值分割应对光照差异:
def PreProcessing(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    # 自适应阈值适配局部光照
    imgThresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                      cv2.THRESH_BINARY_INV, 11, 2)
    return imgThresh
  • 增加形态学操作修复二值图断裂区域:
def PreProcessing(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    ret, imgThresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    # 膨胀操作修复目标区域断裂
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    imgThresh = cv2.dilate(imgThresh, kernel, iterations=1)
    return imgThresh

2. 轮廓筛选条件过于刚性

固定的面积阈值无法适配不同尺寸的图像,可改为基于图像总面积的相对比例筛选:

def findCorners(canny):
    contourCounter = 0
    points1 = []
    points2 = []
    contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 计算图像总面积,设置相对面积阈值
    img_area = canny.shape[0] * canny.shape[1]
    min_area = img_area * 0.1
    max_area = img_area * 0.4

    for cnt in contours:
        area = cv2.contourArea(cnt)
        if min_area < area < max_area:
            epsilon = 0.01 * cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, epsilon, True)
            # 额外筛选矩形轮廓(4个顶点)
            if len(approx) == 4:
                for point in approx:
                    x, y = point[0]
                    if contourCounter == 0:
                        points1.append((x, y))
                    elif contourCounter == 1:
                        points2.append((x, y))
                contourCounter += 1
    if contourCounter != 2:
        raise Exception(f"the number of big contours detected is {contourCounter}")
    return points1 , points2

3. 轮廓近似参数优化

固定的epsilon系数可能导致轮廓近似失效,可将系数调整为0.01-0.02区间,根据实际图像效果微调。

内容的提问来源于stack exchange,提问作者guy blau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:16:10