How to apply RANSAC in Python OpenCV

Free Tyler1 picture Free Tyler1 · Jul 21, 2016 · Viewed 22.5k times · Source

Can someone show me how to apply RANSAC to find the best 4 feature matching points and their corresponding (x,y) coordinate so I can use them in my homography code?

The feature matching points were obtained by SIFT and here is the code:

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

def drawMatches(img1, kp1, img2, kp2, matches):
    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)


    # Show the image
    cv2.imshow('Matched Features', out)
    cv2.waitKey(0)
    cv2.destroyWindow('Matched Features')

    # Also return the image if you'd like a copy
    return out

img1 = cv2.imread("C://Users//user//Desktop//research//img1.2.jpg")
img2 = cv2.imread("C://Users//user//Desktop//research//img3.jpg")

name = cv2.COLOR_YUV2BGRA_YV12
print name
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
sift = cv2.SIFT()
kp1,des1 = sift.detectAndCompute(gray1, None)
kp2,des2 = sift.detectAndCompute(gray2, None)
bf = cv2.BFMatcher()
matches=bf.match(des1,des2)
matches=sorted(matches,key=lambda x:x.distance)
img3 = drawMatches(gray1,kp1,gray2,kp2,matches[:100])
plt.imshow(img3),plt.show()

print(matches)




cv2.imwrite('sift_matching1.png',img3)

And here is the outcome: click here

Here is my homography code:

import cv2
import numpy as np

if __name__ == '__main__' :

    # Read source image.
    im_src = cv2.imread('C://Users//user//Desktop//research//img1.2.jpg')

    pts_src = np.array([[141, 131], [480, 159], [493, 630],[64, 601]])


    # Read destination image.
    im_dst = cv2.imread('C://Users//user//Desktop//research//img3.jpg')

    pts_dst = np.array([[318, 256],[534, 372],[316, 670],[73, 473]])

    # Calculate Homography
    h, status = cv2.findHomography(pts_src, pts_dst, cv2.RANSAC,5.0)

    # Warp source image to destination based on homography
    im_out = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))

    # Display images

    cv2.imshow("Warped Source Image", im_out)

    cv2.waitKey(0)

The four points that I chose randomly:

pts_src = np.array([[141, 131], [480, 159], [493, 630],[64, 601]])

same thing here:

pts_dst = np.array([[318, 256],[534, 372],[316, 670],[73, 473]])

So yeah, basically, I just need to replace those random points with the best feature matching points that will be obtainned by RANSAC.

Answer

Sunreef picture Sunreef · Jul 21, 2016

You don't have to use RANSAC before findHomography. RANSAC is applied inside the function. Just pass two arrays of features that match each other (no need to only pass the four best).

However, what you can do is filter out the matches that have large distances. Usually, you try to find two matches for each feature and check if the distance with the first match is greatly inferior to the distance with the second match. Take a look at this OpenCV tutorial to see some code on how to do that.