Today I want to show you a sweet algorithm with which you can remove objects from the picture. For example, if we have thousands of images where we have some objects that we want to delete, this algorithm can help us complete this task.
We will be using modified Template Matching approach.
We will load the template, convert to grayscale, perform canny edge detection, after that we do load the original image, convert to grayscale
Continuously rescale the image, apply template matching using edges, and keep track of the correlation coefficient (higher value means better match)
Find coordinates of best-fit bounding box then erase unwanted ROI
We'll use the cv2 module and NumPy. You can read about them on these URLs.
We'll use the cv2
module and NumPy
. You can read about them on these URLs, CV2, and Numpy.
Let's start coding
First we will import a module
import cv2
import numpy as np
After that we do resize a image and maintain aspect ratio
def maintain_aspect_ratio_resize(image, width=None, height=None, inter=cv2.INTER_AREA):
then we grab the image size and initialize dimensions
dim = None
(h, w) = image.shape[:2]
then we return original image if no need to resize:
if width is None and height is None:
return image
We are resizing height if width is none
if width is None:
r = height / float(h)
dim = (int(w * r), height)
We are resizing width if height is none
else:
r = width / float(w)
dim = (width, int(h * r))
Return the resized image
return cv2.resize(image, dim, interpolation=inter)
Load template, convert to grayscale, perform canny edge detection
template = cv2.imread('template.png')
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template = cv2.Canny(template, 50, 200)
(tH, tW) = template.shape[:2]
cv2.imshow("template", template)
Load original image, convert to grayscale
original_image = cv2.imread('test.png')
final = original_image.copy()
gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
found = None
Dynamically rescale image for better template matching
for scale in np.linspace(0.2, 1.0, 20)[::-1]:
resized = maintain_aspect_ratio_resize(gray, width=int(gray.shape[1] * scale))
r = gray.shape[1] / float(resized.shape[1])
if resized.shape[0] < tH or resized.shape[1] < tW:
break
canny = cv2.Canny(resized, 50, 200)
detected = cv2.matchTemplate(canny, template, cv2.TM_CCOEFF)
(_, max_val, _, max_loc) = cv2.minMaxLoc(detected)
if found is None or max_val > found[0]:
found = (max_val, max_loc, r)
Compute coordinates of bounding box
(_, max_loc, r) = found
(start_x, start_y) = (int(max_loc[0] * r), int(max_loc[1] * r))
(end_x, end_y) = (int((max_loc[0] + tW) * r), int((max_loc[1] + tH) * r))
Draw bounding box on ROI to remove
cv2.rectangle(original_image, (start_x, start_y), (end_x, end_y), (0,255,0), 2)
cv2.imshow('detected', original_image)
Erase unwanted ROI (Fill ROI with white)
cv2.rectangle(final, (start_x, start_y), (end_x, end_y), (255,255,255), -1)
cv2.imwrite('final.png', final)
cv2.waitKey(0)
Original image:
When we run the script, we get this result
Whole code:
import cv2
import numpy as np
def maintain_aspect_ratio_resize(image, width=None, height=None, inter=cv2.INTER_AREA):
dim = None
(h, w) = image.shape[:2]
if width is None and height is None:
return image
if width is None:
r = height / float(h)
dim = (int(w * r), height)
else:
r = width / float(w)
dim = (width, int(h * r))
return cv2.resize(image, dim, interpolation=inter)
template = cv2.imread('template.png')
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template = cv2.Canny(template, 50, 200)
(tH, tW) = template.shape[:2]
cv2.imshow("template", template)
original_image = cv2.imread('test.png')
final = original_image.copy()
gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
found = None
for scale in np.linspace(0.2, 1.0, 20)[::-1]:
resized = maintain_aspect_ratio_resize(gray, width=int(gray.shape[1] * scale))
r = gray.shape[1] / float(resized.shape[1])
if resized.shape[0] < tH or resized.shape[1] < tW:
break
canny = cv2.Canny(resized, 50, 200)
detected = cv2.matchTemplate(canny, template, cv2.TM_CCOEFF)
(_, max_val, _, max_loc) = cv2.minMaxLoc(detected)
if found is None or max_val > found[0]:
found = (max_val, max_loc, r)
(_, max_loc, r) = found
(start_x, start_y) = (int(max_loc[0] * r), int(max_loc[1] * r))
(end_x, end_y) = (int((max_loc[0] + tW) * r), int((max_loc[1] + tH) * r))
cv2.rectangle(original_image, (start_x, start_y), (end_x, end_y), (0,255,0), 2)
cv2.imshow('detected', original_image)
cv2.rectangle(final, (start_x, start_y), (end_x, end_y), (255,255,255), -1)
cv2.imwrite('final.png', final)
cv2.waitKey(0)
Thank you all