Home > Software design >  Getting cleaner blobs for counting
Getting cleaner blobs for counting

Time:11-11

still on my journey of learning image masking.

Im trying to count the number of red dots in an image.

Here is the input image image

After masking red, I get this image after masking

The problem is, some of the blobs aren't full, so it does not count all the blobs, for example in this specific image, it does not count number 6 and 9. (assuming top left is 1)

How do I refine the masking process to get a more accurate blob?

Masking Code:

import cv2, os
import numpy as np

os.chdir('C:\Program Files\Python\projects\Blob')

#Get image input
image_input = cv2.imread('realbutwithacrylic.png')
image_input = np.copy(image_input)
rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB)

#Range of color wanted
lower_red = np.array([125, 1, 0])
upper_red = np.array([200, 110, 110])

#Masking the Image
first_mask = cv2.inRange(rgb, lower_red, upper_red)

#Output
cv2.imshow('first_mask', first_mask)
cv2.waitKey()

Masking Code with Blob Counter

import cv2, os
import numpy as np

#Some Visual Studio Code bullshit because it cant find the image????
os.chdir('C:\Program Files\Python\projects\Blob')

#Get image input
image_input = cv2.imread('realbutwithacrylic.png')
image_input = np.copy(image_input)
rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB)

#Range of color wanted
lower_red = np.array([125, 1, 0])
upper_red = np.array([200, 110, 110])

#Masking the Image
first_mask = cv2.inRange(rgb, lower_red, upper_red)

#Initial masking counter
cv2.imshow('first_mask', first_mask)
cv2.waitKey()

#Blob Counter
thresh = cv2.threshold(first_mask,0,255,cv2.THRESH_OTSU   cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=5)

cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

#Couting the blobs
blobs = 0
for c in cnts:
    area = cv2.contourArea(c)
    cv2.drawContours(first_mask, [c], -1, (36,255,12), -1)
    if area > 13000:
        blobs  = 2
    else:
        blobs  = 1

#Blob Number Output
print('blobs:', blobs)

#Masking Output
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image_input)
cv2.imshow('mask', first_mask)
cv2.waitKey()

CodePudding user response:

Since you're looking for bright enough reds, you might have a better time masking things in HSV space:

orig_image = cv2.imread("realbutwithacrylic.jpg")

image = orig_image.copy()
# Blur image to get rid of noise
image = cv2.GaussianBlur(image, (3, 3), cv2.BORDER_DEFAULT)
# Convert to hue-saturation-value
h, s, v = cv2.split(cv2.cvtColor(image, cv2.COLOR_BGR2HSV))
# "Roll" the hue value so reds (which would otherwise be at 0 and 255) are in the middle instead.
# This makes it easier to use `inRange` without needing to AND masks together.
image = cv2.merge(((h   128) % 255, s, v))
# Select the correct hues with saturated-enough, bright-enough colors.
image = cv2.inRange(image, np.array([40, 128, 100]), np.array([140, 255, 255]))

For your image, the output is

enter image description here

which should be more straightforward to work with.

CodePudding user response:

@AKX has a good suggestion, but I would prefer HSI (as described in the images in the code above

To count the dots you can now simply:

lab = dip.Label(dots)
print(dip.MaximumAndMinimum(lab)[1])

...which says 10.

  • Related