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

- 期望的距离变换效果:

- 参考文章:OpenCV学习笔记
我的代码
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
相关产品推荐
相关产品推荐

