<p>I worked on retina vessel detection for a bit few years ago, and there are different ways to do it:</p>

<ul>
<li>If you don't need a top result but something fast, you can use oriented openings, <a href="https://www.researchgate.net/publication/3327391_Segmentation_of_vessel-like_patterns_using_mathematical_morphology_and_curvature_evaluation" rel="nofollow">see here</a> and <a href="http://cmm.ensmp.fr/Anciens/zana/" rel="nofollow">here</a>.</li>
<li>Then you have an other version using mathematical morphology <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0ahUKEwiJ1qDb-cXMAhUMOsAKHaXXBcoQFggkMAA&amp;url=http%3A%2F%2Fcmm.ensmp.fr%2F~walter%2Farticles_walter%2Fwalterklein.pdf.gz&amp;usg=AFQjCNG3e1Ueke67eY9JEw6ub00Y8roQ-A&amp;sig2=dzVYD_5_2BKMaOQpRLjjOQ&amp;cad=rja" rel="nofollow">version here</a>.</li>
</ul>

<p>For better results, here are some ideas:</p>

<ul>
<li>Personally, I used combination of Gabor filters, and results where pretty good. See <a href="http://www.thibault.biz/StackOverflow/RetinaVesselsGabor.png" rel="nofollow">the segmentation result here on the first image of drive</a>.</li>
<li>And <a href="https://arxiv.org/pdf/cs/0510001.pdf" rel="nofollow">Gabor can be combined with learning for a good result</a>, or <a href="http://www.icmlc.org/icmlc2011/014_icmlc2011.pdf" rel="nofollow">here</a>.</li>
<li>Few years ago, <a href="https://www.researchgate.net/publication/5896442_Retinal_Blood_Vessel_Segmentation_Using_Line_Operators_and_Support_Vector_Classification" rel="nofollow">they claimed to have the best algorithm</a>, but I've never had the opportunity to test it. I was sceptic about the performance gap and the way they thresholded the line detector results, it was kind of obscure.</li>
<li>But I know that nowadays, many people try to tackle the problem using CNN, but I've not heard about significant improvements.</li>
</ul>
How to segment blood vessels python opencv
<p>I am trying to segment the blood vessels in retinal images using Python and OpenCV. Here is the original image:</p>

<p><a href="https://i.stack.imgur.com/aB4Iz.jpg"><img src="https://i.stack.imgur.com/aB4Iz.jpg" alt="enter image description here"></a></p>

<p>Ideally I want all the blood vessels to be very visible like this (different image):</p>

<p><a href="https://i.stack.imgur.com/Yv2Ki.png"><img src="https://i.stack.imgur.com/Yv2Ki.png" alt="enter image description here"></a></p>

<p>Here is what I have tried so far. I took the green color channel of the image.</p>

<pre><code>img = cv2.imread('images/HealthyEyeFundus.jpg')
b,g,r = cv2.split(img)
</code></pre>

<p>Then I tried to create a matched filter by following <a href="http://funcvis.org/blog/?p=51">this article</a> and this is what the output image is:</p>

<p><a href="https://i.stack.imgur.com/5ZX7g.png"><img src="https://i.stack.imgur.com/5ZX7g.png" alt="enter image description here"></a></p>

<p>Then I tried doing max entropy thresholding:</p>

<pre><code>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 &amp; 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 &amp; 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 &gt; 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)
</code></pre>

<p>This is the result I'm getting, which is obviously not showing all the blood vessels:</p>

<p><a href="https://i.stack.imgur.com/5HIoE.png"><img src="https://i.stack.imgur.com/5HIoE.png" alt="enter image description here"></a></p>

<p>I've also tried taking the matched filter version of the image and taking the magnitude of its sobel values. </p>

<pre><code>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)
</code></pre>

<p>This makes the vessels pop out more:</p>

<p><a href="https://i.stack.imgur.com/9fZDJ.png"><img src="https://i.stack.imgur.com/9fZDJ.png" alt="enter image description here"></a></p>

<p>Then I tried Otsu thresholding on it:</p>

<pre><code>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()
</code></pre>

<p>Otsu doesn't give adequate results. It ends up including noise in the results: </p>

<p><a href="https://i.stack.imgur.com/XkkYd.png"><img src="https://i.stack.imgur.com/XkkYd.png" alt="enter image description here"></a></p>

<p>Any help is appreciated on how I can segment the blood vessels successfully.</p>