2016-06-09 1 views
0

J'ai essayé de créer un matcher qui utilise Sift pour détecter et faire correspondre les points clés. J'ai essayé de l'utiliser mais je n'ai pas obtenu les résultats que j'attendais. Il s'avère que ce n'est pas tellement l'échelle et la rotation invariant dans ma mise en œuvre. Quel est le problème avec mon code?J'ai eu de mauvais résultats avec OpenCV et SIFT. Comment pourrais-je l'améliorer?

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() 

Vous pouvez voir les résultats ici: http://i.giphy.com/26BRyPZpaoNyB0IkE.gif

+0

Dans le code que vous utilisez ORB, pas 'EIPD: = orbe cv2.ORB() #Detect et calculer sur l'image keypoints modèle (kp2, des2) = orb.detectAndCompute (img2, None) '. Essayez d'utiliser SIFT ou KAZE/AKAZE – taarraas

+0

Désolé je viens de télécharger le mauvais code, je vais le corriger très bientôt. – Gabe

+0

Ce résultat me semble tout à fait correct. Ton image a beaucoup de bruit de fond, donc c'est normal qu'elle ait des faux positifs puisque tu n'utilises pas de seuil pour les matchs – ZWiki

Répondre

0

Vous utilisez la norme de Hamming et EIPD n'est pas un descripteur binaire.

bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 

Utiliser la norme euclidean à la place, devrait fonctionner beaucoup mieux.

+0

J'ai essayé mais j'ai eu de meilleurs résultats avec le code que j'ai – Gabe

+0

Etes-vous sûr que ce n'était pas pour ORB? Il est totalement faux de comparer les flottants bit à bit en utilisant la distance de haming. – taarraas

0

Comme mentionné @taarraas SIFT est pas un descripteur binaire, mais je suggère aussi d'ajouter ceci:

good = [] 
for m,n in matches: 
    if m.distance < 0.75*n.distance: 
     good.append([m]) 

Et puis uniquement à l'aide good au lieu de tous vos matches, de cette façon vous aider à éliminer le bruit.

Je n'ai également jamais utilisé bf.match, je fais habituellement bf.knnMatch, je suggère d'essayer cela. Quelque chose comme ceci pour vous:

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

P.S. Le .75 vient pour Lowe's paper si vous êtes intéressé par ce

+0

Il est dit: L'objet 'cv2.DMatch 'n'est pas itérable' – Gabe

+0

@Gabe J'ai mis à jour ma réponse. Aussi 'matches' devrait être une liste d'objets' DMatch' ... vous devriez vérifier pourquoi il en serait autrement – ZWiki

+0

C'est l'erreur que je reçois avec 'knnMatch':' AttributeError: l'objet 'list' n'a pas d'attribut 'distance' ' – Gabe