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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 11:45:04