Ask Your Question

more SIFT matches than descriptors

asked 2015-07-02 05:46:14 -0500

erudumeller gravatar image

Hi there,

I am comparing objects by using SIFT features in Python. I am using the FLANN KNN matcher. This works well, but occasionally I get more matches than I had features to match with.

kp, des = sift.detectAndCompute(frame, None)
kp2, des2 = sift.detectAndCompute(frame2, None)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des, des2, k=2)
good = []
for m, n in matches:
    if m.distance < 0.75*n.distance:

So, len(good) can be higher than len(des) or len(des2) in practice. Question is: how can this happen? As per my understanding, there shouldn't be more matching features than features in total.

edit retag flag offensive close merge delete



That is perfectly possible, since each of the original features in frame 1 can or tries to match all the features in frame2. Probably FLANN has an option to keep only the best or the top best? I am guessing you are in the latter case.

StevenPuttemans gravatar imageStevenPuttemans ( 2015-07-02 08:11:31 -0500 )edit

Maybe change to k=1? in c++, K=2 means that you want the 2 best candidate matches for a specific feature...

Doomb0t gravatar imageDoomb0t ( 2015-07-02 09:29:45 -0500 )edit

^--- what @Doomb0t said, missed it but he is right!

StevenPuttemans gravatar imageStevenPuttemans ( 2015-07-02 09:40:41 -0500 )edit

@Doomb0t 's explanation is right, but this is not the solution to the problem. Setting k to 1 means the distance test does not work anymore, making len(good) always equal to the maximum of len(des) and len(des2). For some reason that is unclear to me, the algorithm first finds the longest list of descriptors, and then tries to find a match (or two in this case) in the shorter one. What I want it to do is to only find matches for the shorter one, so there are no duplicates in matching. I have looked through the c++ documentation (the python one is quite lacking), but haven't yet found something that lets me do this.

erudumeller gravatar imageerudumeller ( 2015-07-02 10:53:59 -0500 )edit

I can only speak for the C++ case. knnMatch (from DescriptorMatcher) will match each query descriptor to a train descriptor.

So you will end up with size(matches)=(queryDescriptor.rows,k).

If len(queryDescriptor) > len(trainDescriptor), multiple queryDescriptors will be matched to the same trainDescriptor.

The ratio test is possible in C++, so there should be a mean to do that with Python I think.

Eduardo gravatar imageEduardo ( 2015-07-02 13:14:50 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2015-07-02 13:20:58 -0500

Eduardo gravatar image

updated 2015-07-03 04:12:09 -0500

I never used the Python OpenCV interface but this tutorial shows how to use the ratio test with a FLANN based Matcher.

I copy / paste the tutorial code here:

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

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

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

# FLANN parameters
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary

flann = cv2.FlannBasedMatcher(index_params,search_params)

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

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in xrange(len(matches))]

# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
    if m.distance < 0.7*n.distance:

draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)

edit flag offensive delete link more
Login/Signup to Answer

Question Tools

1 follower


Asked: 2015-07-02 05:46:14 -0500

Seen: 266 times

Last updated: Jul 03 '15