Search code examples
pythonopencvdetection

Counting drop on an image


I have image of drops and I want to calculate the number of it.

Here is the original image : Normal drops

And Here after threshold application : Image ofter threshold

i tried a lot of fonction on OpenCV and it's never right.

Do you have any ideas on how to do ?

Thanks

The best I got, was by using : (img_morph is my binairized image)

rbc_bw = label(img_morph)
rbc_props = regionprops(rbc_bw)
fig, ax = plt.subplots(figsize=(18, 8))
ax.imshow(img_morph)
rbc_count = 0
for i, prop in enumerate(filter(lambda x: x.area > 250, 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)
plt.show()

And all my circles are detected here but also the gap in between. Analysed

A more difficult image : enter image description here


Solution

  • Core idea: matchTemplate.

    Approach:

    • pick a template manually from the picture
      • histogram equalization for badly lit inputs (or always)
    • matchTemplate with suitable matching mode
      • also using copyMakeBorder to catch instances clipping the border
    • thresholding and non-maximum suppression

    I'll skip the boring parts and use the first example input.

    Manually picked template:

    template

    scores = cv.matchTemplate(haystack, template, cv.TM_CCOEFF_NORMED)
    

    Thresholding and NMS:

    levelmask = (scores >= 0.3)
    
    localmax = cv.dilate(scores, None, iterations=26)
    localmax = (scores == localmax)
    
    candidates = levelmask & localmax
    
    (nlabels, labels, stats, centroids) = cv.connectedComponentsWithStats(candidates.astype(np.uint8), connectivity=8)
    print(nlabels-1, "found") # background counted too
    # and then draw a circle for each centroid except label 0
    

    And that finds 766 instances. I see a few false negatives (missed) and saw a false positive too once, but that looks like less than 1%.

    output