Skip to content

ierolsen/Object-Detection-with-OpenCV

Repository files navigation

Object Detection with OpenCV

In this repo, I've worked on Object Detection with OpenCV, I've just aimed to get coordinates, width and height of object using traditional OpenCV algoritms, so this repo doesn't contain what that objects are. Firstly, I started with Edge Detection, Corner Detection and then Colorful Object Detection.


Here, I am going to explain some important topics:

1- Object Detection with Color

2- Watershed

You can find explanations below.


Object Detection with Color

Using HSV color range which is determined as Lower and Upper, I detected colorful object. Here I prefered blue objects.

# blue HSV
blueLower = (84,  98,  0)
blueUpper = (179, 255, 255)

When I got the color range, I set capture size and then I read the capture.

First I apply Gaussian Blurring for decreasing the noises and details in capture.

#blur
blurred = cv2.GaussianBlur(imgOriginal, (11,11), 0)

After Gaussian Blurring, I convert that into HSV color format.

# HSV
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

To detect Blue Object, I define a mask.

# mask for blue
mask = cv2.inRange(hsv, blueLower, blueUpper)

After mask, I have to clean around of masked object. Therefor I apply first Erosion and then Dilation

# deleting noises which are in area of mask
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

After removing noises, the Contours have to be found

contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
center = None

If the Contours have been found, I'll get the biggest contour due to be well.

# get max contour
c = max(contours, key=cv2.contourArea)

The Contours which are found have to be turned into rectangle deu to put rectangle their around. This cv2.minAreaRect() function returns a rectangle which is smallest to cover the area of object.

rect = cv2.minAreaRect(c)

In the screen, I want to print the information of rectangle, therefor I need to reach its inform.

((x,y), (width, height), rotation) = rect
s = f"x {np.round(x)}, y: {np.round(y)}, width: {np.round(width)}, height: {np.round(height)}, rotation: {np.round(rotation)}"

Using this rectangle I found, I want to get a Box. In the next, I will use this Box for drawing Rectangle.

# box
box = cv2.boxPoints(rect)
box = np.int64(box)

Image Moment is a certain particular weighted average (moment) of the image pixels' intensities. To find Momentum, I use Max. Contour named as "c". After that, I find Center point.

# moment
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

Now, I will draw the center which is found.

# point in center
cv2.circle(imgOriginal, center, 5, (255, 0, 255), -1)

After Center Point, I draw Contour

# draw contour
cv2.drawContours(imgOriginal, [box], 0, (0, 255, 255), 2)

I want to print coordinators etc. in the screen

# print inform
cv2.putText(imgOriginal, s, (25, 50), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (255, 255, 255), 2)

And Final:

detected_img

detected2_img


Introduction to Watershed Algorithm

Previously, I worked on Object Detection algorithm and I make detected coordinaters, rotations and dimension of objects. This project is about Watershed. Basically Watershed algoritm is used for seperating the other objects in image. After apply this algorithm, I need to apply some Low-Pass Filtering and Morphological Operations deu to determine area and edge of objects.

In Watershed Algoritm, I will apply this techniques:

1- Median Blurring

2- Gray Scale

3- Binary Threshold

4- Opening

5- Distance Transform

6- Threshold for foreground

7- Dilation for enlarging image to use for background

8- Connected Components

9- Watershed

10- Find and Draw Contours around of objects

I'll explain these subjects again when I explain code cells.


First of all I must import my libraries I'll use:

import cv2
import numpy as np
import matplotlib.pyplot as plt

After that, I need to read my image I want to apply Watershed:

coin = cv2.imread("data/coins.jpg")

plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");

original

By the way, the semicolon (;) which is in end of plt.axis("off") is a trick for ingoring some inputs of matplotlib.

To remove the noises which are on image I will apply one of Low-Pass Filtering methods called MedianBlurring

coin_blur = cv2.medianBlur(src=coin, ksize=13)

plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");

Low Pass Filtering (Blurring)

After that, I need to convert color of image to Gray

coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)

plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");

Gray Scale

Using Binary Threshold I will make image specific between coins and background

ret, coin_thres = cv2.threshold(src=coin_gray, thresh=75, maxval=255, type=cv2.THRESH_BINARY)

plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"), plt.axis("off");

Binary Threshold

As you can see after Thresholding it is almostly clear between coins and background.

Now, I will try to draw these Contours

contour, hierarchy = cv2.findContours(image=coin_thres.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):
    
    if hierarchy[0][i][3] == -1: # external contour
        cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(0,255,0), thickness=10)
        
plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"), 
plt.axis("off");

After Contour1

But as you can see it doesn't work, I couldn't seperate their edge.

I will use other method called Watershed for seperating and draw their edge. First method is not Watershed


Before Watershed, I need to apply all of this techniques. For that:

# read data
coin = cv2.imread("data/coins.jpg")
plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");

# Blurring
coin_blur = cv2.medianBlur(src=coin, ksize=15)
plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");

# Gray Scale
coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)
plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");

# Binary Threshold
ret, coin_thres = cv2.threshold(src=coin_gray, thresh=65, maxval=255, type=cv2.THRESH_BINARY)
plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"), 
plt.axis("off");

original Low Pass Filtering (Blurring) Gray Scale Binary Threshold

First I need to remove connetion between coins. Almostly every coins connetc other self, therefor using Opening from Morphological Operations, I will Open them

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

opening = cv2.morphologyEx(coin_thres, cv2.MORPH_OPEN, kernel=kernel, iterations=2)

plt.figure(), plt.title("Opening"), plt.imshow(opening, cmap="gray"), plt.axis("off");

Opening

To romevo the connection of between coins I will use Distance Transform. After that I can see Distance between objects (coins)

dist_transform = cv2.distanceTransform(src=opening, distanceType=cv2.DIST_L2, maskSize=5)

plt.figure(), plt.title("Distance Transform"), plt.imshow(dist_transform, cmap="gray"), plt.axis("off");

Distance Transform

After finding distance, to find image which is in foreground what it is, I'll minimizing that using Threshold.

ret, sure_foreground = cv2.threshold(src=dist_transform, thresh=0.4*np.max(dist_transform), maxval=255, type=0)

plt.figure(), plt.title("Fore Ground"), plt.imshow(sure_foreground, cmap="gray"), plt.axis("off");

Fore Ground

To find background what it is, I will enlarging image using Dilate.

sure_background = cv2.dilate(src=opening, kernel=kernel, iterations=1) #int

sure_foreground = np.uint8(sure_foreground) # change its format to int

And now, I can Subtrack them eachothers (BackGround - ForeGround) so that, the image can be more understandable. Here is the result of Opened and Dilated image

unknown = cv2.subtract(sure_background, sure_foreground)

plt.figure(), plt.title("BackGround - ForeGround = "), plt.imshow(unknown, cmap="gray"), plt.axis("off");

BackGround - ForeGround =

After these steps, I need to find Markers for giving inputs for Watershed algorithm. And now I'll provide Connection between Components.

ret, marker = cv2.connectedComponents(sure_foreground)

marker = marker + 1

marker[unknown == 255] = 0 # White area is turned into Black to find island for watershed

plt.figure(), plt.title("Connection"), plt.imshow(marker, cmap="gray"), plt.axis("off");

Connection

After that, now I can apply Watershed Algorithm and I can make segmentation

marker = cv2.watershed(image=coin, markers=marker)

plt.figure(), plt.title("Watershed"), plt.imshow(marker, cmap="gray"), plt.axis("off");

Watershed

As a last step, I'll find and Draw Contours around of Coins.

contour, hierarchy = cv2.findContours(image=marker.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):
    
    if hierarchy[0][i][3] == -1:
        cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(255,0,0), thickness=3)
        
plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"), plt.axis("off");

After Contour2


About

This repo contains some object detection algorithms and techniques (Not ML algorithms). This is aimed to get coordinates, width, height, and rotation of objects.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published