我与OpenCV和SIFT的匹配结果不佳。我怎么能改进它?

时间:2016-06-09 19:24:58

标签: python opencv sift

我尝试创建一个使用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

2 个答案:

答案 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。如果您对

感兴趣,.75Lowe's paper