Extract Blood Vessels from Fundus Image Using OpenCV Python

What I learned from my first Image Processing Project

Binith Jayasinghe
Analytics Vidhya
Published in
5 min readJun 30, 2020

--

Fundus Image

Image processing is a method to perform some operations on an image, in order to get an enhanced image or to extract some useful information from it.

A pipeline is a some set of operations connected in a series, where the output of one is the input of the next one. In image processing, a task can be achieved through many different pipelines with different qualities.

My advise for anyone who is trying to start a project with a new framework is not to try to learn everything about that framework before the start of the project. You can get to know it while you are doing it. It’s better to have a general idea about what we can do with this technology and blueprint of the project. Lets take this project as a example.

In this project, our final goal is to extract large vessels and small vessels separately. The blood vessels were highlighted in the image because they were darker than others. So at first i thought if I am able to filter all the vessels by color(it does not work), then I can remove small vessels by smoothing or blurring and extract the large vessels. After that all I needed to do was subtract large vessels from all vessels and extract small vessels. This was my initial path to the goal.

Then I found a way to detect object using HSV color space. Here is the code.

mask & res output with trackbar

Here you can change parameters and see how the output changes. Click escape button to close it. The above figure was the best one I got by this and I was not satisfied with the outputs. Then I tried it with increasing brightness and contrast at the beginning. But it did not give me the thing I want. So I decided to move on to another method.

Then I found that Grayscale and green channel images are much easier to work within a variety of tasks like in many morphological operations and image segmentation problems and it is easier to distinguish features of an image when we deal with a single layered image. So I applied Grayscale and threshold with denoising.

Threshold & denoising after applying grayscale

So we can clearly see that it had extracted more vessels than previous time but with lot of noises. So I had to find a way to remove those noises. Thanks to stack overflow I found a way to remove small objects but when I directly applied it to here, it removed some considerable amount of data. And again with the help of google & stack overflow I found a way to tackle this problem with applying dilation and then removing small objects.

remove small objects
dilation with kernel size (5, 5)

I tried dilation with different kernel sizes and end up with size (2, 2). Then I accidentally tried with the size (1, 2) and it had some extra details than kernel size (2, 2). Then I tried with the size (2, 1) and it also had some extra details than kernel size (2, 2) and even more details than (1, 2) while some were missing. When I merged both (1, 2) and (2, 1) images It gave a better output.

from the left ( with kernel size (2, 2), with kernel size (1, 2), with kernel size (2, 1) )
from the left ( after removing small objects with kernel size (2, 2), with kernel size (1, 2), with kernel size (2, 1) )
after merge images filtered with kernel size (1, 2) and (2, 1)
extract all vessels

There may be some other pipelines which give a way better output than this. But I’m happy with what I got because this is my first image processing project and with the time I had 😉. You may have a better view, if we remove the background. You can done it using masking and bitwise_not operator.

A mask is a binary image consisting of zero- and non-zero values. If a mask is applied to another binary or to a grayscale image of the same size, all pixels which are zero in the mask are set to zero in the output image. All others remain unchanged.

In our case we can define a function like following to remove the background.

after removing background

Okay then! Now my first step is done. Now I should try to extract large vessels or small vessels. Then I could subtract it from all vessels and get the other vessel type. But since the small blood vessels are thin, I think it will be easy to remove small blood vessels other than large ones.

My initial idea was to extract small vessels by applying blurring and smoothing. But it didn’t work as I thought. So I have to move on to another method. Then I tried morphological transformation using structuring element of shape ellipse and I was able to remove small vessels. Then I found contours and remove the small components while drawing other contours. Following function will extract large vessels for you.

after applying morphological transformation
large blood vessels

Then by subtracting you can extract small vessels using following function.

small blood vessels

As I already said this is my first try and it may not be the best pipeline for this. If you have something better than this leave a comment and let me know. At the end what I learnt was there is no theory or rules to find out the best pipeline. It is something you have to earn with experience and through researches.

Hope this tutorial about image processing operations will help someone new to image processing with OpenCV.

Please visit my Github repository for the full code.

--

--