OpenCV-在检测到Canny边缘后找到血管轮廓

时间:2018-12-02 21:50:07

标签: python opencv image-processing

我有一个血管的图像。经过精巧的边缘检测和其他处理之后,我设法得到了image。可以清楚地看到该容器,但我想获得该容器的轮廓。我该怎么办?

1 个答案:

答案 0 :(得分:0)

得到两个不同轮廓的原因是将Canny边缘检测器应用于灰度图像。这给出了“白线”的结果-空白图像上的边缘。通俗地说,cv2.findContours()在二进制图像上寻找相连的白色像素。因此,由于您有两条分开的线,因此可以找到两个轮廓。 cv2.findContours()返回轮廓的点数组,因此在搜索感兴趣的区域之前,必须首先连接这两条线以获得一个轮廓。您可以通过遍历各个点并附加xy的值为0和/或图像的高度或宽度为值的点来完成此操作。这将给您4个点-第一个轮廓的起点和终点以及第二个轮廓的起点和终点。然后,您可以测量这些点之间的距离,以确定适合的手握式吸盘。我记得两点之间的距离的公式是sqrt((x2-x1)^2+(y2-y1)^2)。因此,如果您计算一个点到其余3个点的距离,则最短的距离意味着这两个点适合放手枪(这两个点也适合放得更远的手枪)。现在,您已经有了两条线的起点和终点,可以将它们连接起来。当然,您可以制定其他条件,例如第一个点具有x==0y>0,然后在点(0,0)上划一条线,然后在另一点划到第二点,这样您就不必t切掉部分感兴趣的区域。我举了一个简单的例子,向您展示了实现这一目标的逻辑。请注意,这不是自动化的可行解决方案-要实现此目的,您将不得不对其进行大量升级。

示例代码:

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()

原始图片:

enter image description here

边缘:

enter image description here

边缘+线:

enter image description here

轮廓:

enter image description here

话虽如此,您可以尝试将图像阈值化而不是搜索边缘。这样可以使您从getgo中获得一个轮廓,并使事情变得容易得多。无法确定,因为您尚未发布原始图片!

示例代码:

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()

阈值图像:

enter image description here

轮廓:

enter image description here