我尝试创建一个使用sift来检测和匹配关键点的匹配器。我尝试使用它,但我没有得到我预期的结果。事实证明,在我的实现中,它并不是那么规模和旋转不变。我的代码出了什么问题?
import numpy as np
import cv2
from matplotlib import pyplot as plt
import sys
def drawMatches(img1, kp1, img2, kp2, matches):
# Create a new output image that concatenates the two images together
# (a.k.a) a montage
rows1 = img1.shape[0]
cols1 = img1.shape[1]
rows2 = img2.shape[0]
cols2 = img2.shape[1]
out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8')
# Place the first image to the left
out[:rows1,:cols1] = np.dstack([img1, img1, img1])
# Place the next image to the right of it
out[:rows2,cols1:] = np.dstack([img2, img2, img2])
# For each pair of points we have between both images
# draw circles, then connect a line between them
for mat in matches:
# Get the matching keypoints for each of the images
img1_idx = mat.queryIdx
img2_idx = mat.trainIdx
# x - columns
# y - rows
(x1,y1) = kp1[img1_idx].pt
(x2,y2) = kp2[img2_idx].pt
# Draw a small circle at both co-ordinates
# radius 4
# colour blue
# thickness = 1
cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1)
cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1)
# Draw a line in between the two points
# thickness = 1
# colour blue
cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255, 0, 0), 1)
# Also return the image if you'd like a copy
return out
img2 = []
cap = cv2.VideoCapture(0)
#Capture the template
while True:
ret, img = cap.read()
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
x=220
y=165
w=200
h=150
cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0), 2)
cv2.imshow('Capture it!',img)
if cv2.waitKey(1) & 0xFF == ord('q'):
#Crop out roi
img2 = img[y:y+h, x:x+w]
#Resize for stacking
img2 = cv2.resize(img2, (640, 480))
print "Template OK"
break
cv2.destroyAllWindows()
sift = cv2.SIFT_create()
#Detect and compute keypoints on template image
(kp2,des2) = sift.detectAndCompute(img2,None)
while True:
ret, img1 = cap.read()
img1 = cv2.cvtColor(img1, cv2.cv.CV_BGR2GRAY)
# Detect keypoints of original image
(kp1,des1) = sift.detectAndCompute(img1,None)
# Create matcher
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# Do matching
matches = bf.match(des1,des2)
# Sort the matches based on distance. Least distance
# is better
matches = sorted(matches, key=lambda val: val.distance)
# Show only the top 10 matches - also save a copy for use later
out = drawMatches(img1, kp1, img2, kp2, matches[:10])
# Show the image
cv2.imshow('Matched Features', out)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
您可以在此处查看结果:http://i.giphy.com/26BRyPZpaoNyB0IkE.gif
答案 0 :(得分:0)
您正在使用HAMMING规范,而SIFT不是二进制描述符。
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
使用欧几里德规范,应该会更好。
答案 1 :(得分:0)
正如@taarraas所说,SIFT不是二进制描述符,但我也建议添加它:
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
然后只使用good
而不是所有匹配,这样就有助于消除噪音。
我也从未使用bf.match
,我通常会bf.knnMatch
,我建议尝试一下。对你来说是这样的:
matches = bf.knnMatch(des1,des2, k=2)
P.S。如果您对
感兴趣,.75
会Lowe's paper