OpenCV-Python doesn't find one bubble from picture

Question:

I have picture with 9 bubbles. My task is to count them and output the number of bubbles that are in the image. Firstly, I tried to add Gaussian blur to image, then I used Canny edge detection and lastly it should draw countours of detected bubbles. However, one bubble is still missing and I don’t really know why. How can I sort this problem out?
This is my code:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('objects.jpg', cv2.IMREAD_GRAYSCALE)
img_blur = cv2.GaussianBlur(img, (3, 3), 0)

plt.imshow(img_blur, cmap='gray')

# Canny Edge Detection
edge = cv2.Canny(img_blur, 0, 250)

fig, ax = plt.subplots(1, 2, figsize=(18, 6))
ax[0].imshow(img, cmap='gray')
ax[1].imshow(edge, cmap='gray')

(cnt, hierarchy) = cv2.findContours(
    edge.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.drawContours(rgb, cnt, -1, (0, 255, 0), 2)

plt.imshow(rgb)
print("number of objects in the image is: ", len(cnt))

This is my input image: https://imgur.com/a/wKNB5jF

And final output with one missing bubble after drawing the contours: https://imgur.com/a/dyAnKKV

Asked By: cinnamond

||

Answers:

Here is one way. I do not recommend using Canny edges. This is how I suggest doing it in Python/OpenCV.

  • Read the input
  • Threshold on the background color and invert
  • Apply morphology to fill holes and remove small spots
  • Get the external contours and draw them on a copy of the input
  • Count the number of contours
  • Save the results

Input:

enter image description here

import cv2
import numpy as np

# read the input
img = cv2.imread('objects.jpg')

# threshold on background color and invert
lower = (200,180,170)
upper = (240,220,210)
thresh = cv2.inRange(img, lower, upper)
thresh = 255 - thresh

# apply morphology to clean up
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

result = img.copy()
(cnt, hierarchy) = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(result, cnt, -1, (0, 255, 0), 2)

print("number of objects in the image is: ", len(cnt))

# save results
cv2.imwrite('objects_thresh.jpg', thresh)
cv2.imwrite('objects_morph.jpg', morph)
cv2.imwrite('objects_contours.jpg', result)

# show results
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('result', result)
cv2.waitKey(0)

Threshold Image:

enter image description here

Morphology Cleaned Image:

enter image description here

Resulting Contours Image:

enter image description here

number of objects in the image is:  9
Answered By: fmw42
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.