DEV Community

Cover image for Detecting and Counting Objects with OpenCV
Furkan Gulsen
Furkan Gulsen

Posted on

Detecting and Counting Objects with OpenCV

What I will tell in this article is very different in real projects. In real projects, object detection is not done with this method. This is just one of the steps to be taken when object detection. Here we will start with object detection and counting from the step. I will consider the more advanced algorithms of this, the method of application in the real world, in more detail in my next article.

First of all, let’s load our libraries.

import cv2
import imutils
import numpy as np
import matplotlib.pyplot as plt
Enter fullscreen mode Exit fullscreen mode

I choose a picture with coins for this job.

Image description

Let’s import this picture.

image = cv2.imread("coins.jpg")
Enter fullscreen mode Exit fullscreen mode

If you notice, you can see the bright spots on the coin. And again, there are sharp lines on the money. This will reduce efficiency when filtering this image. So let’s make our picture available.

image_blur = cv2.medianBlur(image,25)
Enter fullscreen mode Exit fullscreen mode

When applying the medianBlur method, as seen above, the first parameter is the picture itself, and the second parameter is the blurring rate. If you use different pictures, you can adjust this ratio according to your picture.


One of the most important steps in object detection is to make the picture colorless. So we will turn our picture into a black and white tone. This is generally used in all object detection methods. This allows the image to run more efficiently because it reduces the number of scans.

image_blur_gray = cv2.cvtColor(image_blur, cv2.COLOR_BGR2GRAY)
Enter fullscreen mode Exit fullscreen mode

If pixel value is greater than a threshold value, it is assigned one value (may be white), else it is assigned another value (may be black). The function used is cv2.threshold. First argument is the source image, which should be a grayscale image. Second argument is the threshold value which is used to classify the pixel values. Third argument is the maxVal which represents the value to be given if pixel value is more than (sometimes less than) the threshold value.

image_res ,image_thresh = cv2.threshold(image_blur_gray,240,255,cv2.THRESH_BINARY_INV)
Enter fullscreen mode Exit fullscreen mode

I preferred the “THRESH_BINARY_INV” method because I want the coins to remain white here and the rest to be black. You can choose the appropriate values ​​according to your own picture.


Now we will create a kernel here. This kernel will be 3x3 size.

kernel = np.ones((3,3),np.uint8)
Enter fullscreen mode Exit fullscreen mode

Then we will apply this to our picture as follows.

opening = cv2.morphologyEx(image_thresh,cv2.MORPH_OPEN,kernel) 
Enter fullscreen mode Exit fullscreen mode

The reason for creating a kernel and applying it with the morphologyEx method is that although we blur the picture, some small black or white areas (noise) may remain. We used this method to destroy these.


Now it is time to replace the value of each pixel with the distance to the nearest background pixel using distanceTransform. We will do this using the distanceTransform method. When we apply this method, our array type turns into float32. So we will do 2 more steps and convert our array back to uint8 type.

dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, last_image =  cv2.threshold(dist_transform, 0.3*dist_transform.max(),255,0)
last_image = np.uint8(last_image)
Enter fullscreen mode Exit fullscreen mode

We have the last 2 blocks of code left. In this section, we will now process the counting of objects and recording the positions of the objects. We use findContours to detect objects. Then we make our array regular with the grap_contours method.

cnts = cv2.findContours(last_image.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
Enter fullscreen mode Exit fullscreen mode

Finally, we turn our picture.

def display(img,count,cmap="gray"):
    f_image = cv2.imread("coins.jpg")
    f, axs = plt.subplots(1,2,figsize=(12,5))
    axs[0].imshow(f_image,cmap="gray")
    axs[1].imshow(img,cmap="gray")
    axs[1].set_title("Total Money Count = {}".format(count))

for (i, c) in enumerate(cnts):
    ((x, y), _) = cv2.minEnclosingCircle(c)
    cv2.putText(image, "#{}".format(i + 1), (int(x) - 45, int(y)+20),
        cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 5)
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2)

display(image,len(cnts))
Enter fullscreen mode Exit fullscreen mode

Image description

I tried to write as briefly and clearly as possible. For more detailed information, I will add the source documents below in this article. You can read them and get more in-depth information.

Top comments (2)

Collapse
 
vulcanwm profile image
Medea

this is interesting and well explained!

Collapse
 
furkangulsen profile image
Furkan Gulsen

Thank you 🙏