为了计算图像中的圆形物体,我想使用分水岭算法。
为了了解它的工作方式以及如何满足需要,我在python中搜索了一些工作示例(https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html; http://scikit-image.org/docs/dev/auto_examples/segmentation/plot_label.html)

我最终找到了一个可行的解决方案,该解决方案出于我自己的目的或多或少地开箱即用(How to define the markers for Watershed in OpenCV?)

通过此代码,无论示例文件还是我自己的图像,我都得到不错的结果。
经过分水岭分析,我确实得到了奇怪的举动。由于某些原因,分水岭步骤还会在图像周围添加边框。因此,在检测到的对象旁边,图像的整个边缘也会被检测和着色。

我的猜测是,我应该更改代码中的参数以阻止这种情况的发生,但是到目前为止,我仍然找不到应该做什么。

这是代码:

import cv2
import numpy as np
from scipy.ndimage import label
def segment_on_dt(a, img):
    border = cv2.dilate(img, None, iterations=3)
    border = border - cv2.erode(border, None)
    dt = cv2.distanceTransform(img, cv2.DIST_L2, 3)
    dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(np.uint8)
    _, dt = cv2.threshold(dt, 200, 255, cv2.THRESH_BINARY)
    lbl, ncc = label(dt)
    # Completing the markers now.
    lbl[border == 255] = 255
    lbl = lbl.astype(np.int32)
    cv2.watershed(a, lbl)
    lbl[lbl == -1] = 0
    lbl = lbl.astype(np.uint8)
    return 255 - lbl

# Load image file
img = cv2.imread('coins.jpg')
# Pre-processing.
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray = cv2.GaussianBlur(img_gray,(5,5),0)
width, height = img_gray.shape
_, img_bin = cv2.threshold(img_gray, 0,  255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
img_bin = cv2.morphologyEx(img_bin, cv2.MORPH_OPEN,np.ones((5, 5),     dtype=int))
result = segment_on_dt(img, img_bin)
result[result != 255] = 0
result = cv2.dilate(result, None)
img[result == 255] = (0, 0, 255)
cv2.imwrite('Img_output.png',img)

运行此代码将得到此结果(至少在我的电脑上)

检测硬币的结果足以达到我的目的,但是我对同时检测到的图像边缘有些疑惑。从调试过程中看到的情况来看,分水岭增加了这一优势,但我不清楚为什么会发生这种情况。

最佳答案

您可以使用openCV提供的教程添加背景标签来解决此问题。
https://docs.opencv.org/3.1.0/d3/db4/tutorial_py_watershed.html

他们增加了一个额外的步骤来插入确定的背景和确定的前景区域,以帮助分水岭算法正确分割硬币区域。

***********编辑**************

再次阅读代码后。我发现您的原始代码没有问题。
使用可变边框设置背景标签。

通过执行OpenCV教程中找到的代码,您可能会获得相同的结果。问题在于您得出结果的方式。由于这是一个显示问题,因此我们可以采用多种方法来解决该问题。其中之一是使用肯定背景的信息

这是对功能segment_on_dt的修改

def segment_on_dt(a, img):
    sure_background = cv2.dilate(img, None, iterations=3)
    border = sure_background - cv2.erode(sure_background, None)


    dt = cv2.distanceTransform(img, cv2.DIST_L2, 3)
    dt = ((dt - dt.min()) / (dt.max() - dt.min()) * 255).astype(np.uint8)
    _, dt = cv2.threshold(dt, 200, 255, cv2.THRESH_BINARY)
    lbl, ncc = label(dt)


    # Completing the markers now.
    lbl[border == 255] = 255


    lbl = lbl.astype(np.int32)
    cv2.watershed(a, lbl)
    lbl[lbl == -1] = 0
    # Only draw red line if its not in sure background
    lbl[sure_background == 0] = 255

    lbl = lbl.astype(np.uint8)
    cv2.imshow('lbl_2',lbl)

    return 255 - lbl

我为绘制红线添加了新条件。仅当线条不在确定的背景区域中时才绘制线条。

您的最终结果应如下所示。

python - 硬币的分水岭-错误的输出-LMLPHP

关于python - 硬币的分水岭-错误的输出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53630329/

10-12 22:42