pythonopencvimage-processingcolor-detection

How to count the color detected objects using OpenCV


I am trying to detect objects using color. Below is the code and the image:

import cv2
import numpy as np

img = cv2.imread('image2.jpeg')
img1 = img[157:498, 212:705]

hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
lower_bound = np.array([0, 20, 20])
upper_bound = np.array([20, 255, 255])
origMask = cv2.inRange(hsv, lower_bound, upper_bound)
kernel = np.ones((7, 7), np.uint8)
mask = cv2.morphologyEx(origMask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

cv2.imshow("Mask", mask)
cv2.imshow("Crop Image", img1)
cv2.imshow("Orig Image", img)
    
cv2.waitKey(0)
cv2.destroyAllWindows()

So in the above code, I am loading the image first. Then cropping it to a desired area and then performing the HSV to find orange color objects.

Below is the original image:

enter image description here

Below is the cropped image:

enter image description here

Below is the mask image after hsv:

enter image description here

I want to know how can I count the number of objects in the mask image. For example, in this case it is 3. And after counting it, how can I draw bounding box over these color objects on the original image.


Solution

  • You can use your binary mask to get the contours of the image. Then, you can compute the bounding rectangles belonging to each contour. Assume the input is your binary mask, the script should look like this:

    # imports:
    import cv2
    
    # image path
    path = "D://opencvImages//"
    fileName = "objectsMask.png" # This is your binary mask
    
    # Reading an image in default mode:
    inputImage = cv2.imread(path + fileName)
    
    # Deep copy for results:
    inputImageCopy = inputImage.copy()
    
    # Convert RGB to grayscale:
    grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
    
    # Find the contours on the binary image:
    contours, hierarchy = cv2.findContours(grayscaleImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    # Store bounding rectangles and object id here:
    objectData = []
    
    # ObjectCounter:
    objectCounter = 1
    
    # Look for the outer bounding boxes (no children):
    for _, c in enumerate(contours):
        # Get the contour's bounding rectangle:
        boundRect = cv2.boundingRect(c)
    
        # Store in list:
        objectData.append((objectCounter, boundRect))
    
        # Get the dimensions of the bounding rect:
        rectX = boundRect[0]
        rectY = boundRect[1]
        rectWidth = boundRect[2]
        rectHeight = boundRect[3]
    
        # Draw bounding rect:
        color = (0, 0, 255)
        cv2.rectangle(inputImageCopy, (int(rectX), int(rectY)),
                      (int(rectX + rectWidth), int(rectY + rectHeight)), color, 2)
    
        # Draw object counter:
        font = cv2.FONT_HERSHEY_SIMPLEX
        fontScale = 1
        fontThickness = 2
        color = (0, 255, 0)
        cv2.putText(inputImageCopy, str(objectCounter), (int(rectX), int(rectY)), 
                    font, fontScale, color, fontThickness)
    
        # Increment object counter
        objectCounter += 1
    
        cv2.imshow("Rectangles", inputImageCopy)
        cv2.waitKey(0)
    

    I'm creating a list called objectData. Here, I'm storing the object's "id" (just an object counter) and its bounding rectangle. This is the output:

    enter image description here