more SIFT matches than descriptors
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:
good.append(m)
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.
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.
Maybe change to k=1? in c++, K=2 means that you want the 2 best candidate matches for a specific feature...
^--- what @Doomb0t said, missed it but he is right!
@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.
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.