The world’s leading publication for data science, AI, and ML professionals.

Image Processing – Blob Detection

Finding the Connection!

Image by author
Image by author

Image processing is primarily used to extract different features in an image. Since digital images contain different objects and information, it is evident that this kind of information is extracted from such images.

To do this, we can perform image processing techniques to single out and detect such features and objects. One of the most promising techniques is called Blob Detection.

A Blob, in a sense, is anything that is considered a large object or anything bright in a dark background, in images, we can generalize it as a group of pixel values that forms a somewhat colony or a large object that is distinguishable from its background. Using image processing, we can detect such blobs in an image.

Scikit-Image has different functions that can be used to show the different blob in an image. Let us go through each of them.

Let us first load the example image:

import numpy as np
from skimage.io import imshow, imread
from skimage.color import rgb2gray
import matplotlib.pyplot as plt
sample = imread('flowers2.png')
sample_g = rgb2gray(sample)
fig, ax = plt.subplots(1,2,figsize=(10,5))
ax[0].imshow(sample)
ax[1].imshow(sample_g,cmap='gray')
ax[0].set_title('Colored Image',fontsize=15)
ax[1].set_title('Grayscale Image',fontsize=15)
plt.show()
Figure 1: Sample Image (Image by author)
Figure 1: Sample Image (Image by author)

Now, let us binarize the image:

fig, ax = plt.subplots(1,3,figsize=(15,5))
sample_b = sample_g > 0.6
ax[0].set_title('Grayscale Image',fontsize=20)
ax[0].imshow(sample_g,cmap='gray')
ax[1].plot(sample_g[600])
ax[1].set_ylabel('Pixel Value')
ax[1].set_xlabel('Width of Picture')
ax[1].set_title('Plot of 1 Line',fontsize=15)
ax[2].set_title('Binarized Image',fontsize=15)
ax[2].imshow(sample_b,cmap='gray')
Figure 2: Binarized Image (Image by author)
Figure 2: Binarized Image (Image by author)

For binarizing, we used a threshold on the pixel value of 0.6 since we can see on the sample plotline that there is a separation within this value.

We usually binarize our image before blob detection since it is easier to work around the smaller dimensions and normalized values.

There are nifty functions in scikit-image where you can use different methods to detect the blobs in the image, some of them are as follows:

Laplacian of Gaussian (LOG)

Determines the blobs by using the Laplacian of Gaussian Method

from skimage.feature import blob_dog, blob_log, blob_doh
fig, ax = plt.subplots(1,2,figsize=(10,5))
ax[0].set_title('Binarized Image',fontsize=15)
ax[0].imshow(sample_g,cmap='gray')
blobs = blob_log(sample_b, max_sigma=30, threshold=0.01)
ax[1].imshow(sample_b, cmap='gray')
for blob in blobs:
    y, x, area = blob
    ax[1].add_patch(plt.Circle((x, y), area*np.sqrt(2), color='r', 
                            fill=False))
ax[1].set_title('Using LOG',fontsize=15)
plt.tight_layout()
plt.show()
Figure 3: Using LOG (Image by author)
Figure 3: Using LOG (Image by author)

Notice that we were able to detect the circular blobs in the image, even the smallest blobs were detected also.

Difference of Gaussian(DOG)

Determines the blobs by using the difference of two gaussian smoothed image

The code will be the same as above with a variation on the blobs variable by using the direct function blob_dog from scikit-image.

blobs = blob_dog(sample_b, max_sigma=30, threshold=0.01)
Figure 4: Using DOG (Image by author)
Figure 4: Using DOG (Image by author)

Comparing the result of the DOG to LOG, we can see that the DOG method can detect much larger blobs, and also the center coordinates of the blobs are much more centered compared to LOG.

Determinant of Hessian (DOH)

Determines the bobs by using the maximum in the matrix of the Hessian determinant.

blobs = blob_doh(sample_b, max_sigma=30, threshold=0.01)
Figure 5: Using DOH (Image by author)
Figure 5: Using DOH (Image by author)

Comparing the results of DOH, to DOG and LOG, the DOH coordinates of the blobs are much more centered on the edges of the circular ground truth blobs unlike the DOG, and also, it detects way more small blobs compared to LOG.

Connected Components(Labelling)

Another approach in dealing with blob detection is by using the connected component in the image. Using this approach we can easily detect all shapes.

To do so, we need to make sure our binarized image is a little bit cleaned. We can perform a morphological operation on the binarized image to easily clean it. Sample below:

sample_c = im_cleaned = multi_ero(multi_dil(sample_b,5),5)
Figure 6: Morphing the Image (Image by author)
Figure 6: Morphing the Image (Image by author)

Notice that when we used a dilation effect, we were able to make the white roses more complete and whole. This will make our labeling much easier and minimized.

There is already a nifty function on the scikit-image library that you can use to label the morphed image. Sample code and graph are as follows:

sample_l = label(sample_c)
Figure 7: Labelling the Image (Image by author)
Figure 7: Labelling the Image (Image by author)

Notice on the labeled image figure that we were able to label each blob. All the small blobs are actually also labeled. We can check how many blobs were detected by doing:

sample_rp=regionprops(sample_l)
print('How many Blobs detected?:', len(sample_rp))

How many Blobs detected?: 1541

We were able to detect almost a thousand blobs, this is because the label function will also label even the smallest blob, because it only needs to satisfy one condition, if it is a different pixel value from its surrounding. If it has the same pixel values then it will connect it to the whole group making a much bigger blob.

We can use the function region props to further segment the blobs, some codes as an example follows:

list1 = []
for x in sample_rp:
    list1.append(x.area)
list2  = sorted(list(enumerate(list1)),key=lambda x: x[1], reverse=True)[:7]
fig, ax = plt.subplots(1,4,figsize=(15,10))
ax[0].imshow(sample_l)
ax[0].set_title('Labelled Image',fontsize=15)
for x,y in enumerate(list2[:3]):
    ax[x+1].imshow(sample_rp[y[0]].image)
    ax[x+1].set_title('Biggest Blob'+str(x+1))
Figure 8: Regionalizing the Image (Image by author)
Figure 8: Regionalizing the Image (Image by author)

Notice that we were able to segment the biggest 3 blobs in the image by using the pixel area of the Connected Components.

SUMMARY

In this article, we were able to show different kinds of functions to use for circular blob detection which are LoG, DoG, and DoH. We were able also to see how connected components can simplify blob detection much easier and lastly, we were able to segment the blobs seen on the image by using region props.

Stay tuned for the next article!


Related Articles