Spot the blob on the job: Image Detection, Labeling, and Measurement using Python

Nico Aguila
Nerd For Tech
Published in
4 min readDec 27, 2020
Photo by Kalineri on Unsplash

Blob Detection

Blobs are objects of interest in a given image. In order to determine blobs, they must be defined as bright objects in a dark background to ensure that algorithms will be able to properly detect them. Three methods were discussed to detect blobs:

  1. Laplacian of Gaussian (LoG) — Laplacian of a Gaussian smoothed image
  2. Difference of Gaussian (DoG) — Difference of Two Gaussian smoothed images
  3. Determinant of Hessian (DoH) — Maximum value in the matrix of the Determinant of Hessian

The main benefit of transforming images into blobs is when our machine is able to detect the said blobs. In this manner, we can label and measure the properties of the detected objects from any given image. Let’s take a look at a sample image of red blood cells as an example

# library imports
from math import sqrt
import matplotlib.pyplot as plt
import numpy as np
from skimage.io import imread, imshow
from skimage.color import rgb2gray
from skimage.feature import blob_dog, blob_log, blob_doh
from skimage.morphology import (erosion, dilation, closing, opening,
area_closing, area_opening)

# binarizing source image
im2 = rgb2gray(imread('rbc.jpg'))
im2_bw = im2<0.85
imshow(im2_bw)
Original Image (left) and Binarized Image (right

Let’s try cleaning up the patchy look from the images first before applying the three methods of blob detection mentioned above

img_morph = area_closing(area_opening(im2_bw, 200), 200)
imshow(img_morph)
Most of the holes have now been covered up
#Applying the blob detection algorithms
blobs_log2 = blob_log(img_morph, max_sigma=20, num_sigma=10, threshold=.1)
# Compute radii in the 3rd column.
blobs_log2[:, 2] = blobs_log2[:, 2] * sqrt(2)
blobs_dog2 = blob_dog(img_morph, max_sigma=20, threshold=.1)
blobs_dog2[:, 2] = blobs_dog2[:, 2] * sqrt(2)
blobs_doh2 = blob_doh(img_morph, max_sigma=20, threshold=.01)blobs_list2 = [blobs_log2, blobs_dog2, blobs_doh2]
colors = ['blue', 'lime', 'red']
titles = ['Laplacian of Gaussian', 'Difference of Gaussian',
'Determinant of Hessian']
sequence2 = zip(blobs_list2, colors, titles)
fig, axes = plt.subplots(1, 3, figsize=(9, 3), sharex=True, sharey=True)
ax = axes.ravel()
for idx, (blobs, color, title) in enumerate(sequence2):
ax[idx].set_title(title)
ax[idx].imshow(img_morph, interpolation='nearest')
for blob in blobs:
y, x, r = blob
c = plt.Circle((x, y), r, color=color, linewidth=2, fill=False)
ax[idx].add_patch(c)
ax[idx].set_axis_off()
plt.tight_layout()
plt.show()
LoG, DoG, and DoH Blob Detection algorithms, respectively.

Based on the nature of the reference image, LoG would be the best suited algorithm for this case as it properly identifies the shape of the red blood cells, unlike the other two where circles sometimes enclose two cells instead of just one.

Connected Components

Despite LoG appearing accurate in blob detection for our reference image, all three algorithms try to identify the blobs by marking them as circular objects. Since not all objects are circular, and that there are even objects of irregular shape, connected components in an image can be considered as objects of interest instead. However, connected components rely heavily on the image structure, which is why image cleaning is a must, which can be done using morphological operations.

Using our cleaned image earlier, region properties of the connected components can be identified.

from skimage.measure import label, regionprops
label_im2 = label(img_morph)
imshow(label_im2)
Connected components mapped with their corresponding region properties

The connected components are mapped as pixels wrapped again in matrices, just like how filtering and morphological operations to their job, by identifying objects in which to apply their operations on.

Given the coordinates on the image, we can determine the connected components via the regionprop module in Python, and actually try counting how many red blood cells are in the image. Let’s start by checking a reference value to which we can set to start the red blood cell count

area_list = []
for prop in props:
area_list.append(prop.area)
min(area_list)

By using the area parameter of regionprop, we can determine the sizes of the red blood cells identified by the algorithm.

208

We can now set 208 as the threshold value to count all objects identified in the image.

rbc_bw = label(img_morph)
rbc_props = regionprops(rbc_bw)
fig, ax = plt.subplots(figsize=(18, 8))ax.imshow(rbc)rbc_count = 0
for i, prop in enumerate(filter(lambda x: x.area > 207, rbc_props)):
y1, x1, y2, x2 = (prop.bbox[0], prop.bbox[1],
prop.bbox[2], prop.bbox[3])
width = x2 - x1
height = y2 - y1
r = plt.Rectangle((x1, y1), width = width, height=height,
color='b', fill=False)
ax.add_patch(r)
rbc_count += 1
print('Red Blood Cell Count:', rbc_count)
Red Blood Cell Count: 263
Red blood cells identified by the algorithm, with their corresponding bounding boxes

And there you have it, you can now have a general idea on how to count objects identified by your algorithm

--

--