Project: panorama stitching with OpenCV
Before we begin
Stitch two overlapping photos into one panorama using ORB features, ratio-test matching, RANSAC homography, and blending.
Time: ~3 hours.
Requirements
- Two photos of the same scene with 30–50% overlap (phone photos work).
pip install opencv-python numpy matplotlib
Pipeline overview
- Detect ORB keypoints and descriptors.
- Match with BFMatcher + Lowe ratio test.
- Estimate homography with
cv2.findHomography(..., cv2.RANSAC). - Warp image 2 into image 1's plane.
- Blend overlap (simple average or feather).
Starter code
python
import cv2
import numpy as np
img1 = cv2.imread("left.jpg")
img2 = cv2.imread("right.jpg")
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
orb = cv2.ORB_create(5000)
kp1, des1 = orb.detectAndCompute(gray1, None)
kp2, des2 = orb.detectAndCompute(gray2, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING)
raw = bf.knnMatch(des1, des2, k=2)
good = [m for m, n in raw if m.distance < 0.75 * n.distance]
pts1 = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
pts2 = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
H, mask = cv2.findHomography(pts2, pts1, cv2.RANSAC, 5.0)
print("inliers:", mask.sum(), "/", len(good))
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
corners = np.float32([[0,0],[w2,0],[w2,h2],[0,h2]]).reshape(-1,1,2)
warped_corners = cv2.perspectiveTransform(corners, H)
all_pts = np.concatenate((np.float32([[0,0],[w1,0],[w1,h1],[0,h1]]).reshape(-1,1,2), warped_corners), axis=0)
[xmin, ymin] = np.int32(all_pts.min(axis=0).ravel() - 0.5)
[xmax, ymax] = np.int32(all_pts.max(axis=0).ravel() + 0.5)
tx, ty = -xmin, -ymin
T = np.array([[1,0,tx],[0,1,ty],[0,0,1]], dtype=np.float64)
panorama = cv2.warpPerspective(img2, T @ H, (xmax - xmin, ymax - ymin))
panorama[ty:ty+h1, tx:tx+w1] = img1
cv2.imwrite("panorama.jpg", panorama)Deliverables
panorama.jpgoutput.- Visualization of matches (
cv2.drawMatches). - Short write-up: inlier count, what failed if alignment is poor.
Extensions
- Multi-band blending (
cv2.detail.MultiBandBlender). - Use SIFT if ORB struggles on low-texture scenes.
- Auto-crop black borders.