如何使用OpenCV分离重叠轮廓并统计其正确数量
重叠轮廓分离计数方案
现有方案问题原因
- 你调用
cv2.findContours时使用的cv2.RETR_EXTERNAL参数仅会检索最外层轮廓,重叠的多个目标会被判定为单个外层轮廓,直接导致计数偏少 - 高斯模糊+Canny边缘检测+膨胀的预处理逻辑会合并重叠目标的相邻边缘,多个粘连目标会被识别为单个连通域,无法区分单个目标
优化方案
针对重叠粘连目标的计数需求,推荐使用距离变换+分水岭算法实现精准分割,该方案是工业视觉计数场景的通用成熟方案,修改后代码如下:
import cv2 import numpy as np # image为你已加载的灰度原图 # 1. 自适应阈值二值化,比Canny更适配目标分割场景 _, binary = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 2. 开运算去除噪声点 kernel = np.ones((3,3), np.uint8) opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2) # 3. 确定确定背景、前景区域 sure_bg = cv2.dilate(opening, kernel, iterations=3) dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) # 0.7为阈值系数,可根据实际图像效果调整 _, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 4. 标记未知区域与连通域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) _, markers = cv2.connectedComponents(sure_fg) markers += 1 markers[unknown == 255] = 0 # 5. 执行分水岭分割 markers = cv2.watershed(cv2.cvtColor(image, cv2.COLOR_GRAY2BGR), markers) # 6. 分割后检测轮廓计数 segment[markers == -1] = 255 (sticks, hierarchy) = cv2.findContours(segment.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cnt = len(sticks) print(f'计数结果: {cnt}') # 可视化结果 rgb = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB) cv2.drawContours(rgb, sticks, -1, (255, 0, 0), 1) cv2.imshow('分割结果', rgb) cv2.waitKey(0)
调优提示
- 距离变换的阈值系数
0.7可根据实际测试效果调整,系数越低越容易分割出更多目标,系数越高越容易漏分割 - 如果原图像对比度较低,可在二值化前先执行直方图均衡化
cv2.equalizeHist(image)提升分割效果
内容的提问来源于stack exchange,提问作者iwannalearn
相关产品推荐
相关产品推荐

