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

基于OpenCV的重叠蠕虫图像计数问题求助

解决OpenCV中重叠蠕虫的计数问题

嘿,我很熟悉这种重叠目标计数的痛点,你用腐蚀没效果太正常了——毕竟腐蚀是整体缩小前景,碰到连接区域大的情况,还没分开蠕虫呢,蠕虫本身都被磨没了。给你推荐几个针对性的解决方案,尤其是分水岭算法,处理这种场景特别靠谱:

方案一:距离变换+分水岭算法(推荐)

这是处理重叠物体分割的经典方法,核心思路是先找到每个蠕虫的“核心区域”作为种子,再让算法从种子开始“填充”,自动分隔开重叠的部分。

完整代码示例

import cv2 as cv
import numpy as np

# 读取图像并预处理
img = cv.imread('worms.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
blur = cv.GaussianBlur(gray, (5, 5), 1)
# OTSU二值化得到黑底白虫的图像
ret, osu = cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)

# 1. 形态学开运算去除细小噪声(可选,但能提升后续效果)
kernel = np.ones((3, 3), np.uint8)
opening = cv.morphologyEx(osu, cv.MORPH_OPEN, kernel, iterations=2)

# 2. 确定确定的背景区域(通过膨胀操作)
sure_bg = cv.dilate(opening, kernel, iterations=3)

# 3. 距离变换找到确定的前景种子
# 距离变换会计算每个前景像素到最近背景的距离,距离越大越接近物体中心
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
# 取距离变换最大值的70%作为阈值,提取出物体核心区域作为种子
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)

# 4. 计算未知区域(背景和前景之间的过渡区)
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)

# 5. 标记连通域作为分水岭的初始标记
ret, markers = cv.connectedComponents(sure_fg)
# 把背景标记从0改为1,让未知区域标记为0(分水岭要求未知区域是0)
markers = markers + 1
markers[unknown == 255] = 0

# 6. 应用分水岭算法分割图像
markers = cv.watershed(img, markers)
# 用蓝色线条标记分割边界
img[markers == -1] = [255, 0, 0]

# 统计蠕虫数量:连通域的数量(ret就是sure_fg中的连通域数,也就是蠕虫数量)
print(f"检测到的蠕虫数量:{ret}")

# 显示结果
cv.imshow('分割结果', img)
cv.waitKey(0)
cv.destroyAllWindows()

原理说明

  • 距离变换:帮我们定位每个蠕虫的中心区域,这些区域不会被重叠部分干扰,是可靠的分割种子。
  • 分水岭算法:把图像看作地形,种子是“山峰”,算法会从山峰开始向四周“灌水”,不同山峰的水碰到一起时会形成分割线,完美分隔开重叠的蠕虫。

方案二:自适应阈值+形态学组合(针对轻度重叠)

如果你的蠕虫重叠程度不高,可以试试用自适应阈值替代全局OTSU阈值,它能根据局部区域的灰度调整阈值,可能让重叠处的边界更清晰,再结合形态学操作优化:

import cv2 as cv
import numpy as np

img = cv.imread('worms.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
blur = cv.GaussianBlur(gray, (5, 5), 1)

# 自适应阈值二值化,局部调整阈值
osu = cv.adaptiveThreshold(blur, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, 
                          cv.THRESH_BINARY_INV, 11, 2)  # 注意这里用THRESH_BINARY_INV得到白底黑虫,方便后续操作

# 形态学闭运算填补蠕虫内部的小空洞,再开运算断开细小连接
kernel = np.ones((3, 3), np.uint8)
closing = cv.morphologyEx(osu, cv.MORPH_CLOSE, kernel, iterations=2)
opening = cv.morphologyEx(closing, cv.MORPH_OPEN, kernel, iterations=1)

# 找轮廓并计数
imsource, contours, test = cv.findContours(opening, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(img, contours, -1, (0, 0, 255), 2)
print(f"检测到的蠕虫数量:{len(contours)}")

cv.imshow('结果', img)
cv.waitKey(0)
cv.destroyAllWindows()

注意事项

  • 自适应阈值的参数(比如11是块大小,2是常数)需要根据你的图像调整,块大小必须是奇数。
  • 这个方法适合轻度重叠的场景,如果重叠太严重,还是分水岭效果更好。

内容的提问来源于stack exchange,提问作者A.Cossard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:38:24