使用Python在OpenCV的findContours后去除异常轮廓以检测矩形
嘿,我看你现在用OpenCV的findContours找矩形时,捡了一堆多余的形状,这事儿我之前也碰到过!咱们一步步把这些干扰项过滤掉~
解决OpenCV轮廓识别中过滤非矩形的问题
核心思路
问题出在你只做了轮廓提取,没对轮廓做形状校验。从你的结果图能看出来,很多细碎噪点、非四边形的轮廓都被识别出来了。我们需要在找到轮廓后,通过两个关键步骤筛选:
- 把轮廓近似成多边形,矩形的近似结果应该正好是4条边
- 结合轮廓的凸性、面积、长宽比,进一步排除不符合要求的形状
完整优化代码
import cv2 import numpy as np # 读取图像并预处理 img = cv2.imread('CD/A.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 先做高斯模糊,减少噪点干扰(这步是关键!) blurred = cv2.GaussianBlur(gray, (5, 5), 0) # Canny边缘检测,参数可以根据你的图像微调 edges = cv2.Canny(blurred, 50, 150, apertureSize=3) # 提取轮廓(注意OpenCV版本:新版本返回contours和hierarchy) contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 创建空白画布用来绘制筛选后的矩形 result_img = np.ones(img.shape, dtype=np.uint8) * 255 # 遍历每个轮廓,逐一筛选 for cnt in contours: # 计算轮廓周长,用于多边形近似 perimeter = cv2.arcLength(cnt, True) # 用approxPolyDP简化轮廓,epsilon是周长的比例,控制近似程度 approx = cv2.approxPolyDP(cnt, 0.02 * perimeter, True) # 多条件过滤: # 1. 近似后是4条边(四边形) # 2. 轮廓是凸的(矩形是凸四边形) # 3. 面积足够大,过滤小噪点(阈值根据你的图像尺寸调整) if len(approx) == 4 and cv2.isContourConvex(approx) and cv2.contourArea(cnt) > 100: # 可选:验证长宽比,排除太扁/太窄的形状 x, y, w, h = cv2.boundingRect(approx) aspect_ratio = float(w) / h # 这里设定长宽比在0.5到2之间,你可以根据需求修改 if 0.5 < aspect_ratio < 2: # 画出符合要求的矩形 cv2.drawContours(result_img, [approx], 0, (0, 0, 255), 2) # 展示结果 cv2.imshow('Filtered Rectangles', result_img) cv2.waitKey(0) cv2.destroyAllWindows()
关键优化点说明
- 高斯模糊预处理:
cv2.GaussianBlur能有效减少图像中的细碎噪点,避免Canny检测出大量无用边缘 - 轮廓近似:
cv2.approxPolyDP是把复杂轮廓简化成多边形的核心,epsilon越小,近似结果越接近原轮廓,你可以根据实际情况调整(比如0.01或0.03) - 多维度过滤:
- 边数判断:直接锁定四边形
- 凸性校验:排除凹四边形(矩形必然是凸的)
- 面积过滤:去掉那些小到可以忽略的噪点轮廓
- 长宽比过滤:避免把细长条或者扁片当成矩形
额外调整建议
如果还是有漏网之鱼,可以试试:
- 调整Canny的高低阈值(比如把50改成30,150改成200),或者换成自适应阈值
cv2.adaptiveThreshold - 修改面积阈值和长宽比范围,匹配你的图像实际尺寸
- 用
cv2.moments计算轮廓的矩,进一步校验形状特征
内容的提问来源于stack exchange,提问作者yondaim
相关产品推荐
相关产品推荐

