Ask Your Question

Filtering SIFT points by y-coordinate with OpenCV + Python

asked 2015-11-03 06:56:01 -0500

Dansag gravatar image

I have the SIFT keypoints of two images (calculated with Python + OpenCV 3). I want to filter them by their y-coordinate.

Specifically, I want to remove all matching points whose difference of y-coordinate is higher than the image height divided by 10, for example: If two matching points are A(x1, y1) and B(x2, y2):

if abs(y2 - y1) > imageHeight / 10 then remove that maching points.

What I have test

Here is the code I have tested. I'm removing keypoints, but not what I want to remove.

# Load the two images
img1 = cv2.imread(PATH + "image1.jpg", -1)
img2 = cv2.imread(PATH + "image2.jpg", -1)

# Get their dimensions
height, width = img1.shape[:2]

# Resize them (they are too big)
img1 = cv2.resize(img1, (width / 4, height / 4))
img2 = cv2.resize(img2, (width / 4, height / 4))

# Get the resized image's dimensions
height, width = img1.shape[:2]

# Initiate SIFT detector
sift = X2D.SIFT_create()

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

# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)

### Here the filtering attempt ###
# Alloc a new vector for filtered matches
filteredMatches = [None] * len(matches)
# Counter that will count how many matches I have at the end
counter = 0

# for each match
for i in range(len(matches)):

    # Get the "img1" heypoint
    leftPoint = kp1[ matches[i][0].queryIdx ].pt   #'left' image
    # Get the "img2" keypoint
    rightPoint = kp2[ matches[i][0].trainIdx ].pt  #'right' image

    # substract the y-coordinate of both points and compare
    # with height / 10
    if( abs(leftPoint[1] - rightPoint[1]) < height / 10):
        # if the difference is lower than higher / 10, add it
        # to the new list and increment the counter:
        filteredMatches[counter] = matches[i]
        counter += 1

# fix the filtered list size
matches = matches[:counter]

I'm not sure if I'm using queryIdx and trainIdxcorrectly, but according with this post ( I think so.

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2015-11-09 13:13:26 -0500

Dansag gravatar image

I have found the solution. First of all, according to drawMatchesKnn documentation:

keypoints1[i] has a corresponding point in keypoints2[matches[i]]

In my code, 'keypoints1' is kp1, 'keypoints2' is kp2 and 'matches' is matches.

The correspondency between kp1 and kp2 is: kp1[i] matches with kp2[ matches[i].trailIdx ].

Here the finally function which filter the keypoints removing all of them which y-coordinate is higher than the image's height * n, where n is a given number (between 0 and 1):

def filterMatches(kp1, kp2, matches, imgHeight, thresFactor = 0.4):
Removes the matches that correspond to a pair of keypoints (kp1, kp2)
which y-coordinate difference is lower than imgHeight * thresFactor.

    kp1 (array of cv2.KeyPoint): Key Points.

    kp2 (array of cv2.KeyPoint): Key Points.

    matches (array of cv2.DMATCH): Matches between kp1 and kp2.

    imgHeight (Integer): height of the image that has produced kp1 or kp2.

    thresFactor (Float): Use to calculate the threshold. Threshold is 
        imgHeight * thresFactor.

    array of cv2.DMATCH: filtered matches.

filteredMatches = [None]*len(matches)
counter = 0
threshold = imgHeight * thresFactor
for i in range(len(kp1)):
    srcPoint = kp1[ matches[i][0].queryIdx ].pt
    dstPoint = kp2[ matches[i][0].trainIdx ].pt
    diff = abs(srcPoint[1] - dstPoint[1])
    if( diff < threshold):
        filteredMatches[counter] = matches[i]
        counter += 1

return filteredMatches[:counter]
edit flag offensive delete link more
Login/Signup to Answer

Question Tools



Asked: 2015-11-03 06:56:01 -0500

Seen: 1,795 times

Last updated: Nov 09 '15