Python Panorama Stitching Using OpenCV and SIFT
This article explains how to create a panoramic image by detecting SIFT keypoints, matching them with KNN, estimating a homography using RANSAC, and warping and blending two overlapping photos with OpenCV in Python.
Panorama stitching combines two overlapping images into a single wide‑view picture by leveraging computer‑vision techniques such as SIFT keypoint detection, local invariant feature extraction, KNN matching, RANSAC‑based homography estimation, and perspective warping.
Specific steps :
Detect SIFT keypoints and extract descriptors from the left and right images.
Use knnMatch to find the two best matches for each descriptor and filter matches with a ratio test.
Compute the homography matrix H from the filtered point pairs and warp the right image to the left image’s coordinate system.
Overlay the left image onto the warped right image to obtain the final panorama.
The complete Python script that implements these steps is shown below. All code lines are kept unchanged and wrapped in a single
block.</p>
<code>import cv2 as cv # import OpenCV package
import numpy as np # import NumPy for matrix operations
# Detect SIFT keypoints
def sift_keypoints_detect(image):
# Convert to grayscale
gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# Instantiate SIFT detector
sift = cv.xfeatures2d.SIFT_create()
# Detect keypoints and compute descriptors
keypoints, features = sift.detectAndCompute(image, None)
# Draw keypoints on the image
keypoints_image = cv.drawKeypoints(gray_image, keypoints, None, flags=cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
return keypoints_image, keypoints, features
# Match features using KNN and ratio test
def get_feature_point_ensemble(features_right, features_left):
bf = cv.BFMatcher()
matches = bf.knnMatch(features_right, features_left, k=2)
matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
good = []
for m, n in matches:
ratio = 0.6
if m.distance < ratio * n.distance:
good.append(m)
return good
# Panorama stitching function
def Panorama_stitching(image_right, image_left):
_, _, features_right = sift_keypoints_detect(image_right)
_, _, features_left = sift_keypoints_detect(image_left)
goodMatch = get_feature_point_ensemble(features_right, features_left)
if len(goodMatch) > 4:
ptsR = np.float32([keypoints_right[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ptsL = np.float32([keypoints_left[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ransacReprojThreshold = 4
Homography, status = cv.findHomography(ptsR, ptsL, cv.RANSAC, ransacReprojThreshold)
Panorama = cv.warpPerspective(image_right, Homography, (image_right.shape[1] + image_left.shape[1], image_right.shape[0]))
Panorama[0:image_left.shape[0], 0:image_left.shape[1]] = image_left
return Panorama
if __name__ == '__main__':
image_left = cv.imread('./Left.jpg')
image_right = cv.imread('./Right.jpg')
# Resize to make dimensions consistent
image_right = cv.resize(image_right, None, fx=0.4, fy=0.24)
image_left = cv.resize(image_left, (image_right.shape[1], image_right.shape[0]))
# Detect and display keypoints
kp_img_right, kp_right, feat_right = sift_keypoints_detect(image_right)
kp_img_left, kp_left, feat_left = sift_keypoints_detect(image_left)
cv.imshow('Left Image Keypoints', np.hstack((image_left, kp_img_left)))
cv.waitKey(0); cv.destroyAllWindows()
cv.imshow('Right Image Keypoints', np.hstack((image_right, kp_img_right)))
cv.waitKey(0); cv.destroyAllWindows()
# Match and draw matches
goodMatch = get_feature_point_ensemble(feat_right, feat_left)
all_goodmatch_image = cv.drawMatches(image_right, kp_right, image_left, kp_left, goodMatch, None, None, None, None, flags=2)
cv.imshow('All SIFT Matches', all_goodmatch_image)
cv.waitKey(0); cv.destroyAllWindows()
# Stitch and save panorama
Panorama = Panorama_stitching(image_right, image_left)
cv.namedWindow('Panorama', cv.WINDOW_AUTOSIZE)
cv.imshow('Panorama', Panorama)
cv.imwrite('./panorama.jpg', Panorama)
cv.waitKey(0); cv.destroyAllWindows()Running the script displays the detected keypoints for each input image, visualizes the matched feature pairs, shows the warped right image, and finally presents the stitched panorama, which may contain black borders on the right side when the overlap is large.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
