How can i convert sift keypoint.pt to Point2f in python?

I’m trying to use RANSAC to prune false match after SIFT match.

cv.getPerspectiveTransform()

method requires Point2f data ,and in python i got a tuple.

Here is my code

import cv2
import numpy as np


def ransac(pts1, pts2, img_l, img_r, max_iters=500, epsilon=1):
    best_matches = []
    # Number of samples
    N = 4

    for i in range(max_iters):
        # Get 4 random samples from features
        id1 = np.random.randint(0, len(pts1), N)
        id2 = np.random.randint(0, len(pts2), N)
        src = []
        dst = []
        for i in range(N):
            src.append(pts1[id1[i]].pt)
            dst.append(pts2[id2[i]].pt)

        src = np.mat(src)
        dst = np.mat(dst)

        # Calculate the homography matrix H
        H = cv2.getPerspectiveTransform(src, dst)
        Hp = cv2.perspectiveTransform(pts1[None], H)[0]

        # Find the inliers by computing the SSD(p',Hp) and saving inliers (feature pairs) that are SSD(p',Hp) < epsilon
        inliers = []
        for i in range(len(pts1)):
            ssd = np.sum(np.square(pts2[i] - Hp[i]))
            if ssd < epsilon:
                inliers.append([pts1[i], pts2[i]])

        # Keep the largest set of inliers and the corresponding homography matrix
        if len(inliers) > len(best_matches):
            best_matches = inliers

    return best_matches

please highlight, where the current problem is.
(e.g. KeyPoint.pt is already a Point2f)

everything below that looks broken. you probably should convert all keypoints to 2d points before (not only 4), and do calculations on those, not the actual kp.

1 Like

proposal (untested !):

def ransac(pts1, pts2, img_l, img_r, max_iters=500, epsilon=1):
    p1 = cv2.convert(pts1)
    p2 = cv2.convert(pts2)

    best_matches = []
    # Number of samples
    N = 4

    for i in range(max_iters):
        # Get 4 random samples from features
        id1 = np.random.randint(0, len(pts1), N)
        id2 = np.random.randint(0, len(pts2), N)
        src = np.array([p1[i] for i in id1], dtype=np.float32)
        dst = np.array([p2[i] for i in id2], dtype=np.float32)
        # Calculate the homography matrix H
        H = cv2.getPerspectiveTransform(src, dst)
        Hp = cv2.perspectiveTransform(p1, H)

        # Find the inliers by computing the SSD(p',Hp) and saving inliers (feature pairs) that are SSD(p',Hp) < epsilon
        inliers = []
        for i in range(len(p1)):
            ssd = np.sum(np.square(p2[i] - Hp[i]))
            if ssd < epsilon:
                inliers.append([p1[i], p2[i]])

        # Keep the largest set of inliers and the corresponding homography matrix
        if len(inliers) > len(best_matches):
            best_matches = inliers

    return best_matches

however, i dont think it will work properly !
imo, there are 2 broken assumptions here:

        for i in range(len(pts1)):

what if len(p1) > len(p2) ?

            ssd = np.sum(np.square(p2[i] - Hp[i]))

you wrongly assume, that p2[i] is the corresponding point to the projected p1[i], however, it’s an arbitrary kp from the p2 set, you’re comparing apples to pears

IF you did some descriptor matching before, you should re-use the matches here

1 Like

Thanks for replying ! And pointing out the problems ,I’ll fix those problems. I didn’t think much about this approach . I cloned this codes from this repository , code it wrong . I did sift descriptor matching before this , but the result is bad (I only use 2 images for test), only 1 of 6 pairs is the correct match . But I think I got your point. Your proposal and explanation are very helpful ! Also I looked the doc you provide , The convert function is a static function , like this cv2.KeyPoint.convert().