Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform scale and rotation invariant template(feature) matching and object detection in opencv python

I need code for detecting objects that are scale and rotational invariant.There are 8 pen drives in the picture which are varied by size and rotational angle . i am able to detect only few pen drives with matchTemplate() .I need code with SURF,BRIEF or any other algorithm that can detect all 8 pen drives.I have searched other questions they provide only ideas but there is no code for python .

Package that can be used are:

  • opencv-contrib(since surf,brief are moved to contrib package)
  • python3

Input image

Template:

enter image description here

output:

enter image description here

Code :

import cv2
import  numpy as np

image1 = cv2.imread("scale_ri.jpg")

scale_percent = 60  # percent of original size
width = int(image1.shape[1] * scale_percent / 100)
height = int(image1.shape[0] * scale_percent / 100)
dim = (width, height)
# resize image
image1 = cv2.resize(image1, dim, interpolation=cv2.INTER_AREA)

# template matching

# Convert it to grayscale
img_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)

# Read the template
template = cv2.imread('template.jpg', 0)

# Store width and heigth of template in w and h
w, h = template.shape[::-1]

# Perform match operations.
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)

# Specify a threshold
threshold = 0.75

# Store the coordinates of matched area in a numpy array
loc = np.where(res >= threshold)

# Draw a rectangle around the matched region.
num=0

for pt in zip(*loc[::-1]):

    cv2.rectangle(image1, pt, (pt[0] + w, pt[1] + h), (0, 255, 255), 2)


cv2.imwrite("output.jpg",image1)
cv2.imshow("output",image1)
cv2.waitKey(0)

Edit : I have changed the question to scale and rotational invariant template matching(feature matching ) and object detection Example : https://m.youtube.com/watch?v=lcJqinjHb90

I am able to detect a single object with below program but i need to detect multiple objects .

code:

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

MIN_MATCH_COUNT = 2

img1 = cv2.imread('template.jpg',0)          # queryImage
img2 = cv2.imread('scale_ri.jpg',0) # trainImage

# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1,des2,k=2)

# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
    if m.distance < 0.7*n.distance:
        good.append(m)
if len(good)>MIN_MATCH_COUNT:
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts,M)

    img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)

else:
    print("Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT))
    matchesMask = None
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
                   singlePointColor = None,
                   matchesMask = matchesMask, # draw only inliers
                   flags = 2)

img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
#plt.savefig("output_pendrive.png")
plt.imshow(img3, 'gray'),plt.show()

output :

enter image description here

like image 333
Ajith Avatar asked Nov 06 '22 12:11

Ajith


1 Answers

The problem with template matching is that it will not work if the template and desired object to find are not exactly the same in terms of size, rotation, or intensity. Assuming that only desired objects to detect are in the image, here's a very simple contour thresholding + filtering approach.

import cv2

image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area > 10000:
        cv2.drawContours(image, [c], -1, (36,255,12), 3)

cv2.imwrite('thresh.png', thresh)
cv2.imwrite('image.png', image)
cv2.waitKey()
like image 97
nathancy Avatar answered Nov 14 '22 12:11

nathancy