Detecting and Counting Objects with OpenCV
Tags: ai, machinelearning, programming, tutorial
Published: 2023-02-16 06:23:44

> 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.

```python
import cv2
import imutils
import numpy as np
import matplotlib.pyplot as plt
```
I choose a picture with coins for this job.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8m1bnm0cdfntmzrk6kth.png)

Let’s import this picture.

```python
image = cv2.imread("coins.jpg")
```

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.

```python
image_blur = cv2.medianBlur(image,25)
```

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.

```python
image_blur_gray = cv2.cvtColor(image_blur, cv2.COLOR_BGR2GRAY)
```

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.

```python
image_res ,image_thresh = cv2.threshold(image_blur_gray,240,255,cv2.THRESH_BINARY_INV)
```

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.

```python
kernel = np.ones((3,3),np.uint8)
```

Then we will apply this to our picture as follows.

```python
opening = cv2.morphologyEx(image_thresh,cv2.MORPH_OPEN,kernel) 
```

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.

```python
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)
```

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.

```python
cnts = cv2.findContours(last_image.copy(), cv2.RETR_EXTERNAL,
	cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
```

Finally, we turn our picture.

```python
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))
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3aoo0w5kzjtkziw4ilux.png)

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.

- https://docs.opencv.org/3.4/d2/dbd/tutorial_distance_transform.html
- https://docs.opencv.org/3.4/d9/d8b/tutorial_py_contours_hierarchy.html
- https://pyimagesearch.com/2016/02/01/opencv-center-of-contour/