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.
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.