python - 使用 OpenCV 对距离图像进行分水岭变换

标签 python opencv distance image-segmentation watershed

在Matlab中,我们可以对距离变换进行分水岭变换来分离两个接触的物体:

enter image description here enter image description here

上面的第一张图片是我们希望分离的带有触摸对象的图片。第二张图是它的距离变换。

所以,如果黑白图像被称为img,在Matlab中我们可以这样做:

D = -bwdist(~img); 
L = watershed(D);

现在用 openCV 做同样的事情: OpenCV 具有基于标记的分水岭分割功能。似乎要使用 openCV 执行分离两个触摸对象的相同任务,需要为两个对象和背景提供标记。

img = np.zeros((400, 400), np.uint8)
cv2.circle(img, (150, 150), 100, 255, -1)
cv2.circle(img, (250, 250), 100, 255, -1)

dist = cv2.distanceTransform(img, cv2.cv.CV_DIST_L2, cv2.cv.CV_DIST_MASK_PRECISE)
dist3 = np.zeros((dist.shape[0], dist.shape[1], 3), dtype = np.uint8)
dist3[:, :, 0] = dist
dist3[:, :, 1] = dist
dist3[:, :, 2] = dist

markers = np.zeros(img.shape, np.int32)
markers[150,150] = 1 # seed for circle one
markers[250, 250] = 2 # seed for circle two
markers[50,50] =  3 # seeds for background

cv2.watershed(dist3, markers)

在下图中,您可以看到执行分水岭后的 markers 图像。将原本黑白的img以红色叠加在上面。 问题在于生成的 markers 图像中的对象边界与原始图像不同。如何确保对象边界保持不变?

enter image description here

最佳答案

您很可能会了解分水岭的功能中会发生什么。 它开始用它的种子泛滥,并将其邻居的坐标和梯度放入优先队列。

如您所知,当您对 img 应用 distanceTransform 时,圆的渐变变为 0 或 1,但背景始终为 0;

所以,现在你有 3 个种子,泛洪开始起作用:背景(seed3)、邻居(seed1)、邻居(seed2),它们可以依次起作用,直到 seed1 或 seed2 满足它们的梯度 1;然后只有 seed3 可以继续工作。

当seed3遇到圆的边界时,它的梯度变为1,现在它们又可以轮流工作了。

所以如果你想保证物体边界保持不变,你最好在seed3遇到圆的边界时增加梯度。

就像:

dist = cv2.distanceTransform(img, cv2.cv.CV_DIST_L2, cv2.cv.CV_DIST_MASK_PRECISE)
dist[dist > 0] += 2.0

这里是 result

...里面有一些问题(当队列中的梯度全部为1时,哪个先出,哪个后出)

关于python - 使用 OpenCV 对距离图像进行分水岭变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24871188/

相关文章:

python - 如何在 matplotlib 中的子图中选取一个点并在相邻子图中突出显示它(点区域的扩展)

python - 在 python 中使用 MySQL boolean 值

python - 如何在 python 中写入整数,特别是字节数(文件写入)

ios - 以 OpenCV Mat 格式从相机捕获静止图像

c++ - 无法在 Linux 上构建 opencv_contrib 模块

javascript - 如何查找 Google MAP javascript 上任意两个标记之间的距离

google-maps - 如何找到两个地址之间的距离? (Java服务器端)

python - Discord.py 消息固定?

c++ - 这是命名空间问题吗

geolocation - 地理空间坐标和距离(以公里为单位)