Retinal blood vessel segmentation using Python

Viewed 857

I have the following retina image and I'm trying to trace the vessels (the darker lines coming out of the circle). Here is the original image:

enter image description here

I have tried thresholding the image using division normalization followed by filtering on contour area (as per a different stackoverflow solution):

import cv2
import numpy as np

# read the image
img = cv2.imread('retina_eye.jpg')

# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (5,5))
morph = cv2.morphologyEx(gray, cv2.MORPH_DILATE, kernel)

# divide gray by morphology image
division = cv2.divide(gray, morph, scale=255)

# threshold
thresh = cv2.threshold(division, 0, 255, cv2.THRESH_OTSU )[1] 

# invert
thresh = 255 - thresh

# find contours and discard contours with small areas
mask = np.zeros_like(thresh)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

area_thresh = 10000
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > area_thresh:
        cv2.drawContours(mask, [cntr], -1, 255, 2)

# apply mask to thresh
result1 = cv2.bitwise_and(thresh, mask)
mask = cv2.merge([mask,mask,mask])
result2 = cv2.bitwise_and(img, mask)

# save results
cv2.imwrite('retina_eye_division.jpg',division)
cv2.imwrite('retina_eye_thresh.jpg',thresh)
cv2.imwrite('retina_eye_mask.jpg',mask)
cv2.imwrite('retina_eye_result1.jpg',result1)
cv2.imwrite('retina_eye_result2.jpg',result2)

# show results
cv2.imshow('morph', morph)  
cv2.imshow('division', division)  
cv2.imshow('thresh', thresh)  
cv2.imshow('mask', mask)  
cv2.imshow('result1', result1)  
cv2.imshow('result2', result2)  
cv2.waitKey(0)
cv2.destroyAllWindows()

Here is the final output I got:

enter image description here

It ended up tracing the vessels, but it also had some background noise.

Ideally I am looking for this output:

enter image description here

Any suggestions for achieving this result?

1 Answers

I have been researching the topic of retinal blood-vessel segmentation using deep learning and the question you asked is basically the same. I would like to share my research with you.

In the cases where the part of images we want to segment has very low intensity or contrast, we have to apply CLAHE (Contrast Limited Adaptive Histogram Equalization). It is very powerful technique to get the very good results. I would like you to try it. Let me provide you some code for this also:

import cv2

bgr = cv2.imread(retinal_image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equalized = clahe.apply(gray)

More over you can also use Non Local Mean for denoising the image.

If you want to know about the full process how it is done, I would recommend you to go through this easy paper which covers the whole process.

Related