首页 文章

OpenCV对距离图像的分水岭变换

提问于
浏览
1

在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

1 回答

  • 1

    你可以知道在分水岭的功能中发生了什么 . 它开始用它的种子泛滥,并把它们的邻居的坐标和梯度放在一个优先级队列中 .

    如您所知,当您在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时,哪一个会首先弹出,哪一个会弹出第二个)

相关问题