Panorama Stitcher
Create panoramic images by stitching multiple photos.
Overview
Stitch multiple overlapping images into a seamless panorama, like smartphone panorama mode.
Key Techniques:
- Feature detection (ORB/SIFT)
- Feature matching
- Homography estimation (RANSAC)
- Image warping and blending
Pipeline
Images → Detect Features → Match → Homography → Warp → Blend → Panorama
↓ ↓ ↓ ↓ ↓ ↓ ↓
[Multiple] [Keypoints] [Pairs] [Matrix] [Align] [Smooth] [Single]
Key OpenCV Functions
Feature Detection
# ORB (fast, free)
detector = cv2.ORB_create(nfeatures=2000)
kp1, des1 = detector.detectAndCompute(gray1, None)
kp2, des2 = detector.detectAndCompute(gray2, None)
# SIFT (slower, more accurate) - requires opencv-contrib
detector = cv2.SIFT_create()
Feature Matching
# For ORB (Hamming distance)
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = matcher.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)
# For SIFT (L2 distance with ratio test)
matcher = cv2.BFMatcher(cv2.NORM_L2)
matches = matcher.knnMatch(des1, des2, k=2)
good_matches = [m for m, n in matches if m.distance < 0.75 * n.distance]
Homography Estimation
# Extract matched point coordinates
src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
# Find homography with RANSAC
H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
Warping and Blending
# Calculate output canvas size
corners = cv2.perspectiveTransform(corners1, H)
# ... calculate bounds ...
# Warp first image
warped1 = cv2.warpPerspective(img1, H_translated, (output_w, output_h))
# Place second image
warped2 = np.zeros((output_h, output_w, 3), dtype=np.uint8)
warped2[offset_y:offset_y+h2, offset_x:offset_x+w2] = img2
# Blend in overlap region
mask1 = (warped1.sum(axis=2) > 0).astype(float)
mask2 = (warped2.sum(axis=2) > 0).astype(float)
overlap = mask1 * mask2
result = np.where(overlap[:,:,np.newaxis] > 0,
(warped1.astype(float) + warped2.astype(float)) / 2,
np.maximum(warped1, warped2)).astype(np.uint8)
OpenCV Stitcher Class
For easier use, OpenCV provides a built-in Stitcher:
stitcher = cv2.Stitcher_create(cv2.Stitcher_PANORAMA)
status, panorama = stitcher.stitch(images)
if status == cv2.Stitcher_OK:
cv2.imshow("Panorama", panorama)
else:
print(f"Stitching failed: {status}")
Status codes:
cv2.Stitcher_OK- Successcv2.Stitcher_ERR_NEED_MORE_IMGS- Not enough imagescv2.Stitcher_ERR_HOMOGRAPHY_EST_FAIL- Matching failed
Tips for Better Panoramas
- Overlap: 30-50% overlap between images
- Rotation: Rotate camera, don’t translate
- Exposure: Keep exposure consistent
- Static scenes: Moving objects cause artifacts
- Features: Include textured areas, avoid blank walls
Controls
| Key | Action |
|---|---|
c |
Capture frame (webcam mode) |
s |
Stitch captured images |
o |
Use OpenCV Stitcher |
r |
Reset/clear images |
f |
Toggle ORB/SIFT |
q |
Quit |
Running the Application
python curriculum/applications/14_panorama_stitcher.py