AI Hints
Home›Computer Vision Tutorial›Features and Camera Geometry
Computer Vision · Lesson 11 of 111

Matching Images

The same point in two photos.

⏱ 2 min read▶ Video at 18:21🎓 Free
Watch this lesson in the Computer Vision courseWatch on YouTube ↗Full Computer Vision course

Your phone makes a panorama by finding the same points in overlapping photos, and joining them together. Augmented reality pins objects to the real world in the same way. It all begins with matching.

Matching Images
From the video: Matching Images
  • Phones stitch panoramas
  • AR pins objects to the world
  • It all begins with matching

Matching across views

For each keypoint in the first photo, we look for the closest descriptor in the second. Then lines connect the matching points. Most are correct. A few are wrong, since some patches just look alike. We've got to filter those out.

Matching with a ratio test

We create a rotated and shrunken copy of the photo. We find ORB features in both. For each point, we look up its two best matches. Lowe's ratio test keeps a match only if the best is clearly better than the second best. If they're nearly equal, it's ambiguous, so we drop it. Run it. Lines connect the same points, even with the image rotated and smaller. That was impossible with template matching.

match.pypython
import cv2
import matplotlib.pyplot as plt
from skimage import data

a = cv2.cvtColor(data.astronaut(), cv2.COLOR_RGB2GRAY)
h, w = a.shape
M = cv2.getRotationMatrix2D((w / 2, h / 2), 20, 0.8)
b = cv2.warpAffine(a, M, (w, h))

orb = cv2.ORB_create(800)
p1, d1 = orb.detectAndCompute(a, None)
p2, d2 = orb.detectAndCompute(b, None)

pairs = cv2.BFMatcher(cv2.NORM_HAMMING).knnMatch(d1, d2, k=2)
good = [m for m, n in pairs if m.distance < 0.75 * n.distance]

out = cv2.drawMatches(a, p1, b, p2, good[:40], None, flags=2)
plt.figure(figsize=(9, 4.5)); plt.imshow(out); plt.axis("off")
plt.tight_layout(); plt.savefig("matches.png", dpi=110)
print("All matches:", len(pairs), " good:", len(good))
Output
All matches: 800  good: 405

Fitting a transform with RANSAC

A few bad matches can ruin any calculation. RANSAC solves this beautifully. Pick a few random matches, fit a model, and count how many others agree. Repeat many times, and keep the best. Bad matches simply get outvoted. Here, we warp an image with a known transform, then ask it to find the transform from matches alone. Run it. The numbers it found are very close to the truth. RANSAC is everywhere in vision and robotics.

ransac.pypython
import cv2
import numpy as np
from skimage import data

a = cv2.cvtColor(data.astronaut(), cv2.COLOR_RGB2GRAY)
h, w = a.shape
true = np.array([[0.9, 0.1, 30], [-0.1, 0.9, 50], [0.0001, 0.0002, 1]])
b = cv2.warpPerspective(a, true, (w, h))

orb = cv2.ORB_create(1500)
p1, d1 = orb.detectAndCompute(a, None)
p2, d2 = orb.detectAndCompute(b, None)
good = [m for m, n in cv2.BFMatcher(cv2.NORM_HAMMING).knnMatch(d1, d2, k=2)
        if m.distance < 0.75 * n.distance]

src = np.float32([p1[m.queryIdx].pt for m in good])
dst = np.float32([p2[m.trainIdx].pt for m in good])
H, mask = cv2.findHomography(src, dst, cv2.RANSAC, 4.0)

print("Matches used:", len(good), " agreed:", int(mask.sum()))
print("True: ", (true / true[2, 2])[0].round(2))
print("Found:", H[0].round(2))
Output
Matches used: 642  agreed: 626
True:  [ 0.9  0.1 30. ]
Found: [ 0.9   0.1  29.99]

Summary

Match features, filter with the ratio test, and fit with RANSAC. Next, we leave the flat image, and enter the three dimensional world. How does a camera turn a real scene into pixels?

Key takeaways
  • Ratio test removes ambiguous matches
  • RANSAC ignores bad matches
  • That's how panoramas are made
Next up: How Cameras Work — from the 3D world to pixels