【问题标题】:Opencv - finding vessel contour after canny edge detectionOpencv - 在精明边缘检测后找到血管轮廓
【发布时间】:2018-12-02 21:50:07
【问题描述】:

我有一个容器的图像。经过精明的边缘检测和不同的处理,我设法得到了这个image。可以清楚地看到该容器,但我想了解该容器的轮廓。我该怎么做?

【问题讨论】:

  • 怎么不是轮廓?缺什么?请澄清您的问题。
  • 这只是两行。 Cv.findcontours 会分别找到那两条线的轮廓。我想要一个容器轮廓,其中包含图像内部的图像边界。

标签: python opencv image-processing


【解决方案1】:

获得两个单独轮廓的原因是您将 Canny 边缘检测器应用于灰度图像。这给出了“白线”的结果 - 空白图像上的边缘。外行术语中的cv2.findContours() 在二值图像上寻找连接的白色像素。所以因为你有两条单独的线,它会找到两个轮廓。 cv2.findContours() 返回一个轮廓点数组,因此在搜索感兴趣区域之前,您必须首先连接这两条线以获得一个轮廓。您可以通过遍历这些点并附加具有 x 或 y 的值为 0 和/或具有图像高度或宽度的值的点来执行此操作。这将为您提供 4 个点 - 第一个轮廓的起点和终点加上第二个轮廓的起点和终点。然后您可以测量这些点之间的距离以确定哪个更适合。我记得两点之间的距离公式是sqrt((x2-x1)^2+(y2-y1)^2)。因此,如果您计算一个点与其余 3 个点的距离,则最短距离意味着这两个点更适合(就像这两个点更适合更远的点一样)。所以现在你有了两条线的起点和终点,你可以连接它们。 Ofcorse您可以制定其他标准,例如第一个点是否有x==0和y>0,然后在(0,0)点上画一条线,然后从那里再到第二个点,这样你就不会切掉部分感兴趣的区域。我做了一个简单的例子来向你展示实现这一点的逻辑。请注意,这不是自动化的有效解决方案 - 要实现这一目标,您必须对其进行大量升级。

示例代码:

import cv2
import numpy as np

img = cv2.imread('vessel.png')
h, w, ch = img.shape
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img,100,200)
_, contours, hierarchy = cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
points = []

cv2.imshow('edges', edges)

for cnt in contours:
    for i in cnt[:,0]:
        x = int(i[0])
        y = int(i[1])
        if x == 0:
            points.append((x,y))
        elif y == 0:
            points.append((x,y))
        elif w-1<= x <= w+1:
            points.append((x,y))
        elif h-1<= y <= h+1:
            points.append((x,y))

if len(points) == 4:
    x1, y1 = points[0]
    x2, y2 = points[1]
    x3, y3 = points[2]
    x4, y4 = points[3]

dist1 = np.sqrt((x2-x1)**2 + (y2-y1)**2)
dist2 = np.sqrt((x3-x1)**2 + (y3-y1)**2)    
dist3 = np.sqrt((x4-x1)**2 + (y4-y1)**2)

if dist2 < dist1 and dist2 < dist3:
    cv2.line(edges, (x3,y3), (x1,y1), 255, 1)
    cv2.line(edges, (x2,y2), (x4,y4), 255, 1)

_, contours, hierarchy = cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, 0, (0,255,0), 2)

cv2.imshow('img', img)
cv2.imshow('edges+lines', edges)

cv2.waitKey(0)
cv2.destroyAllWindows()

原图:

边缘:

边+线:

轮廓:

话虽如此,您可以尝试对图像设置阈值而不是搜索边缘。这可以从一开始就为您提供一个轮廓,并使事情变得容易得多。不能肯定,因为你还没有发布原图!

示例代码:

import cv2
import numpy as np

img = cv2.imread('vessel.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, 0, (0,255,0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

阈值图像:

轮廓:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    相关资源
    最近更新 更多