Rotated and deformed object detect by template on python

168 Views Asked by At

I am a python beginner, we have a project where we need to detect and crop out the desired pattern from a photo:

This is the original picture:

This is the original picture

Each picture has such a regular border, but it is not closed, in order to detect the direction (similar to a QR code)

2

The image to be detected is taken by a mobile phone and may be deformed, rotated and scaled, we need to get the pattern in the middle of the box:

image1 image2 image3

My code:

import cv2 as cv
import numpy as np
import math

def getdistance(p1,p2):
    v1=np.array(p1)
    v2=np.array(p2)
    v3=v2-v1
    v4=math.hypot(v3[0],v3[1])
    return v4

img_object = cv.imread('small.png', cv.IMREAD_GRAYSCALE)
img_scene = cv.imread('img2.png', cv.IMREAD_GRAYSCALE)

if img_object is None or img_scene is None:
    print('Unable to read image!')
    exit(0)
minHessian = 400
detector = cv.SIFT_create()
keypoints_obj, descriptors_obj = detector.detectAndCompute(img_object, None)
keypoints_scene, descriptors_scene = detector.detectAndCompute(img_scene, None)
img_2 = cv.drawKeypoints(img_scene,keypoints_scene,img_scene)

matcher = cv.DescriptorMatcher_create(cv.DescriptorMatcher_FLANNBASED)
knn_matches = matcher.knnMatch(descriptors_obj, descriptors_scene, 2)

ratio_thresh = 0.95
good_matches = []
for m,n in knn_matches:
    if m.distance < ratio_thresh * n.distance:
        good_matches.append(m)

img_matches = np.empty((max(img_object.shape[0], img_scene.shape[0]), img_object.shape[1]+img_scene.shape[1], 3), dtype=np.uint8)
cv.drawMatches(img_object, keypoints_obj, img_scene, keypoints_scene, good_matches, img_matches, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

obj = np.empty((len(good_matches),2), dtype=np.float32)
scene = np.empty((len(good_matches),2), dtype=np.float32)
for i in range(len(good_matches)):
    obj[i,0] = keypoints_obj[good_matches[i].queryIdx].pt[0]
    obj[i,1] = keypoints_obj[good_matches[i].queryIdx].pt[1]
    scene[i,0] = keypoints_scene[good_matches[i].trainIdx].pt[0]
    scene[i,1] = keypoints_scene[good_matches[i].trainIdx].pt[1]
H, _ =  cv.findHomography(obj, scene, cv.RANSAC)

obj_corners = np.empty((4,1,2), dtype=np.float32)
obj_corners[0,0,0] = 0
obj_corners[0,0,1] = 0
obj_corners[1,0,0] = img_object.shape[1]
obj_corners[1,0,1] = 0
obj_corners[2,0,0] = img_object.shape[1]
obj_corners[2,0,1] = img_object.shape[0]
obj_corners[3,0,0] = 0
obj_corners[3,0,1] = img_object.shape[0]
scene_corners = cv.perspectiveTransform(obj_corners, H)

q1=(int(scene_corners[0,0,0]), int(scene_corners[0,0,1]))
q2=(int(scene_corners[1,0,0]), int(scene_corners[1,0,1]))
q3=(int(scene_corners[2,0,0]), int(scene_corners[2,0,1]))
q4=(int(scene_corners[3,0,0]), int(scene_corners[3,0,1]))
dist=getdistance(q1, q2)
disti=int(dist)
print('q1: %s, q2: %s, q3: %s, q4: %s, dist: %s'%(q1, q2, q3, q4, dist))
src_points = np.array([q3, q4, q1, q2], dtype = "float32")
dst_points = np.array([[disti,disti], [0, disti], [0, 0], [disti, 0]], dtype = "float32")
M = cv.getPerspectiveTransform(src_points, dst_points)
perspective = cv.warpPerspective(img_scene, M, (disti, disti), cv.INTER_LINEAR)
_, result = cv.threshold(perspective, 0, 255,cv.THRESH_BINARY+cv.THRESH_OTSU)
cv.imshow('result', result)
cv.waitKey()

I have researched for a long time, but the results are still not ideal. I would like to ask if there are better ideas to achieve our needs?

0

There are 0 best solutions below