如何使用Python OpenCV对血管进行分割

9
我正在尝试使用Python和OpenCV分割视网膜图像中的血管。以下是原始图像:

enter image description here

理想情况下,我希望所有的血管都像这张图片一样非常清晰:

enter image description here

目前为止,我尝试了以下方法:我获取了该图像的绿色通道。
img = cv2.imread('images/HealthyEyeFundus.jpg')
b,g,r = cv2.split(img)

接下来我按照这篇文章中的方法尝试创建一个匹配滤波器,结果如下图所示:

enter image description here

接着我又尝试进行最大熵阈值处理:

def max_entropy(data):
    # calculate CDF (cumulative density function)
    cdf = data.astype(np.float).cumsum()

    # find histogram's nonzero area
    valid_idx = np.nonzero(data)[0]
    first_bin = valid_idx[0]
    last_bin = valid_idx[-1]

    # initialize search for maximum
    max_ent, threshold = 0, 0

    for it in range(first_bin, last_bin + 1):
        # Background (dark)
        hist_range = data[:it + 1]
        hist_range = hist_range[hist_range != 0] / cdf[it]  # normalize within selected range & remove all 0 elements
        tot_ent = -np.sum(hist_range * np.log(hist_range))  # background entropy

        # Foreground/Object (bright)
        hist_range = data[it + 1:]
        # normalize within selected range & remove all 0 elements
        hist_range = hist_range[hist_range != 0] / (cdf[last_bin] - cdf[it])
        tot_ent -= np.sum(hist_range * np.log(hist_range))  # accumulate object entropy

        # find max
        if tot_ent > max_ent:
            max_ent, threshold = tot_ent, it

    return threshold


img = skimage.io.imread('image.jpg')
# obtain histogram
hist = np.histogram(img, bins=256, range=(0, 256))[0]
# get threshold
th = max_entropy.max_entropy(hist)
print th

ret,th1 = cv2.threshold(img,th,255,cv2.THRESH_BINARY)

这是我得到的结果,很明显没有显示所有的血管: enter image description here 我还尝试了使用匹配滤波器获取图像并取其sobel值的幅度。
img0 = cv2.imread('image.jpg',0)
sobelx = cv2.Sobel(img0,cv2.CV_64F,1,0,ksize=5)  # x
sobely = cv2.Sobel(img0,cv2.CV_64F,0,1,ksize=5)  # y
magnitude = np.sqrt(sobelx**2+sobely**2)

这会使得血管更加突出:

enter image description here

然后我对其进行了大津阈值处理:
img0 = cv2.imread('image.jpg',0)
# # Otsu's thresholding
ret2,th2 = cv2.threshold(img0,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img0,(9,9),5)
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

one = Image.fromarray(th2).show()
one = Image.fromarray(th3).show()

Otsu算法无法给出充分的结果。它最终会将噪音包含在结果中:enter image description here 如果能够成功地将血管分割出来,我将不胜感激。
1个回答

2
我几年前曾经从事视网膜血管检测的工作,有不同的方法可以实现它:

为了获得更好的结果,以下是一些建议:

个人而言,我使用了Gabor滤波器的组合,结果相当不错。请参见此处在drive上第一幅图像上的分割结果
而且Gabor可以与学习结合以获得良好的结果,或者请参见这里
几年前,他们声称拥有最佳算法,但我从未有机会测试它。我对性能差距和他们如何阈值化线检测器结果的方式持怀疑态度,这是有些难以理解的。
但我知道现在许多人尝试使用CNN来解决这个问题,但我没有听说有重大改进。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接