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

OpenCV/Python种子分割:相连种子分离及距离变换失效求助

种子分割中距离变换效果不佳的问题

我知道这个主题已经有相关讨论,但还是卡壳了。作为OpenCV和Python新手,我正在做种子分割,现在卡在分离图像中心3个相连的种子上。用了距离变换后效果很差,几乎没法辨认,不知道接下来该怎么弄。我想得到示例图里那种距离变换效果,这种方法在圆形物体上表现很好,但到我的场景就不行了。

相关素材

我的代码

import cv2
from google.colab.patches import cv2_imshow
import numpy as np

img = cv2.imread('connected_seeds.jpg')
img = cv2.resize(img,(600,400))

# 灰度转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 图像模糊
blur_img = cv2.medianBlur(gray, 7)

# 阈值处理
ret, thresh = cv2.threshold(blur_img, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# 闭运算
kernel = np.ones((5,5), np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

sure_bg = cv2.dilate(closing,kernel,iterations=2)

# 距离变换
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform,0.5*dist_transform.max(),255,0)

解决思路和调整方案

1. 优化预处理,避免种子过度融合

你当前闭运算迭代次数过多、核尺寸太大,直接把种子间的缝隙填满了,导致距离变换找不到独立峰值。可以调整:

  • 改用3x3的小核,减少闭运算迭代次数,保留种子间的细微边界
  • 先做开运算去噪,再做闭运算补种子内部孔洞,避免过度粘连

调整后的预处理代码:

# 调整形态学操作参数
kernel = np.ones((3,3), np.uint8)
# 开运算去除小噪点
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
# 闭运算填补种子内部孔洞(仅1次迭代)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)

2. 调整距离变换参数

  • 把距离变换的掩码尺寸改成3(原5),小掩码对非圆形物体的中心峰值捕捉更敏感
  • 降低前景阈值比例,从0.5改成0.3,保留更多潜在的种子中心,后续再过滤

调整后的距离变换代码:

# 小掩码距离变换
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 3)
# 降低阈值比例
ret, sure_fg = cv2.threshold(dist_transform, 0.3*dist_transform.max(), 255, 0)
# 转成uint8格式方便后续操作
sure_fg = np.uint8(sure_fg)

3. 结合连通域分析提取种子中心

如果距离变换后仍有粘连,用连通域分析提取每个区域的质心作为分割种子:

# 连通域分析,获取质心
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(sure_fg, connectivity=8)
# 跳过背景标签0,绘制每个种子的质心
for i in range(1, num_labels):
    cx, cy = int(centroids[i][0]), int(centroids[i][1])
    cv2.circle(img, (cx, cy), 5, (0,255,0), -1)
cv2_imshow(img)

4. 补全分水岭算法完成分割

基于已有的sure_bg和sure_fg,直接运行分水岭完成分割:

# 计算未知区域(背景与前景的差值)
unknown = cv2.subtract(sure_bg, sure_fg)
# 标记连通域,给背景加1避免和未知区域混淆
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown==255] = 0
# 运行分水岭分割
markers = cv2.watershed(img, markers)
# 用红色绘制分割边界
img[markers == -1] = [255,0,0]
cv2_imshow(img)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:50:37