I have an image of tomato seeds, The number of seeds in the image are 32. I am trying to count those seeds using OpenCV
. The image has some noise which is causing wrong counts.
My approach is to count the centers of the circles. The general idea is to threshold and then flood fill from a background pixel to fill in the background (flood fill works like the paint bucket tool in photo editing apps), that way you only see the centers.
Here is my code:
img = cv2.imread('tomato.jpg', 0)
dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)
img = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
seed_pt = (25, 25)
fill_color = 0
mask = np.zeros_like(img)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
for th in range(60, 120):
prev_mask = mask.copy()
mask = cv2.threshold(img, th, 255, cv2.THRESH_BINARY)[1]
mask = cv2.floodFill(mask, None, seed_pt, fill_color)[1]
mask = cv2.bitwise_or(mask, prev_mask)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
n_centers = cv2.connectedComponents(mask)[0] - 1
print('There are %d cells in the image.'%n_centers)
The output is:
There are 34 cells in the image.
the original count is 32.
How can I fix this?
My solution is to combine RGB mask, with HSV mask using inRange
, there still some points to be improved, but the concept is to do masking in more than one color-space:
output: There are 32 cells in the image.
import cv2
import numpy as np
import matplotlib.pyplot as plt
def HSV_mask(img, hsv_range):
"""
Function: check_HSV, to get the ratio of the marked pixels of specific color in the frame,
using HSV space.
---
Parameters:
@param: img, ndarray, image frame of shape [height, width, 3(BGR)].
@param: hsv_range, tuple of 6, defines the hsv ranges low high for Hue, Saturation, and Value.
---
@return: mask, ndarray, the masked image for the given color.
"""
hsv_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv_img,hsv_range[0::2],hsv_range[1::2])
return mask
img = cv2.imread('001.jpg')
# RGB Mask
rgb_mask = img.copy()
rgb_mask[rgb_mask[...,0]>140]=(0, 0, 0)
rgb_mask[rgb_mask[...,1]>140]=(0, 0, 0)
rgb_mask[rgb_mask[...,2]<70]=(0, 0, 0)
rgb_mask[np.sum(rgb_mask, axis=2)>0]=(1, 1, 1)
masked = img*rgb_mask
# HSV Mask
H1 = (1, 8)
H2 = (175, 180)
S = (40, 255)
V = (100, 150)
myRange1 = (H1 + S + V)
myRange2 = (H2 + S + V)
hsv_mask1 = HSV_mask(masked, myRange1)
hsv_mask2 = HSV_mask(masked, myRange2)
hsv_mask = hsv_mask1#cv2.bitwise_or(hsv_mask1, hsv_mask2)
# Morphology
k = 7
# Get the structuring element:
maxKernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, ksize=(k, k))
# Perform closing:
mask = cv2.morphologyEx(hsv_mask, cv2.MORPH_CLOSE, maxKernel, None, None, 1, cv2.BORDER_CONSTANT)
# Median Filter
filteredMask = cv2.medianBlur(mask,5)
plt.figure(num='Tomato Seeds')
plt.subplot(221)
plt.imshow(img[...,[2, 1, 0]])
plt.title('Original')
plt.subplot(222)
plt.imshow(masked[...,[2,1,0]])
plt.title('rgb masked')
plt.subplot(223)
plt.imshow(hsv_mask)
plt.title('HSV mask')
plt.subplot(224)
plt.imshow(filteredMask)
plt.title('Median Filter')
plt.show()
n_centers = cv2.connectedComponents(filteredMask)[0] - 1
print('There are %d cells in the image.'%n_centers)