# importing the libraries
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
Image Stitching from Scratch
Importing the Libraries and defining the helper functions
# function to open and image and resize it
def open_resize(img, w, h):
= cv2.imread(img) # read the image
image = cv2.resize(image, (w, h)) # resize the image
image return image # return the image
# function to display an image
def show_image(img, w=0, h=0, axis=False, title=''):
if w == 0 or h == 0: plt.figure()
else: plt.figure(figsize=(w, h)) # set the size of the figure
# set the title of the figure
plt.title(title) # show the image
plt.imshow(img) if axis == False: plt.axis('off') # turn off the axis
# show the image
plt.show()
# function to convert BGR to RGB
def BGR2RGB(img):
return cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # convert the image from BGR to RGB
#### TEST THE FUNCTIONS ####
= open_resize('Dataset/scene1/I11.jpg', 600, 400)
test =True) show_image(BGR2RGB(test), axis
Step 1
Detect, extract, and match features
Using SIFT detector to detect the features, and Brute-Force matcher to match the features. The result is shown below.
# function to get the keypoints and descriptors
def get_keypoints_descriptors(img):
= cv2.SIFT_create() # create a SIFT object
sift = sift.detectAndCompute(img, None) # get the keypoints and descriptors
kp, des = des.astype(np.uint8)
des return kp, des # return the keypoints and descriptors
# function to draw the keypoints
def draw_keypoints(img, kp):
return cv2.drawKeypoints(img, kp, None) # draw the keypoints
# functio to get the src and dst points
def get_src_dst_points(image1, image2):
= cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY) # convert the image to grayscale
gray1 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY) # convert the image to grayscale
gray2 = get_keypoints_descriptors(gray1) # get the keypoints and descriptors
keypoints1, descriptors1 = get_keypoints_descriptors(gray2) # get the keypoints and descriptors
keypoints2, descriptors2 = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) # create a BFMatcher object
bf = bf.match(descriptors1, descriptors2) # get the matches
matches = sorted(matches, key=lambda x: x.distance) # sort the matches
matches # Draw the matches between the 2 images
= cv2.drawMatches(image1, keypoints1, image2, keypoints2, matches, outImg=None)
matching_result # get the coordinates of the matched points
= np.float32([keypoints1[m.queryIdx].pt for m in matches]).reshape(-1, 2)
src_pts = np.float32([keypoints2[m.trainIdx].pt for m in matches]).reshape(-1, 2)
dst_pts return src_pts, dst_pts, matching_result # return the src and dst points and the matching result
#### TEST THE FUNCTIONS ####
= open_resize('Dataset/scene1/I12.jpg', 600, 400)
image1 = open_resize('Dataset/scene1/I13.jpg', 600, 400)
image2 = get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =10, h=5) show_image(BGR2RGB(matching_result), w
Step 2
Estimate homography matrix between two images using RANSAC.
Given the source points and destination points compute_homography() function computes the homography matrix. The best homography matrix is selected by RANSAC algorithm, implemented as ransac_homography() function. The result is shown below.
# function to compute the homography
def compute_homography(src_pts, dst_pts):
= src_pts.shape[0] # get the number of points
num_points = [] # matrix A for homography calculation
A_matrix for i in range(num_points):
= src_pts[i, 0], src_pts[i, 1]
src_x, src_y = dst_pts[i, 0], dst_pts[i, 1]
dst_x, dst_y # Constructing the rows of the A matrix
1, 0, 0, 0, -dst_x * src_x, -dst_x * src_y, -dst_x])
A_matrix.append([src_x, src_y, 0, 0, 0, src_x, src_y, 1, -dst_y * src_x, -dst_y * src_y, -dst_y])
A_matrix.append([= np.asarray(A_matrix) # convert the matrix to numpy array
A_matrix = np.linalg.svd(A_matrix) # perform SVD
U, S, Vh = Vh[-1, :] / Vh[-1, -1] # calculate the homography
L = L.reshape(3, 3) # reshape the homography
H return H # return the homography
#### TEST THE FUNCTION ####
= open_resize('Dataset/scene1/I11.jpg', 600, 400)
image1 = open_resize('Dataset/scene1/I12.jpg', 600, 400)
image2 = get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = np.random.choice(src_pts.shape[0], 4, replace=False)
idx = compute_homography(src_pts[idx], dst_pts[idx])
H print('Homography Matrix:')
print(H)
Homography Matrix:
[[ 3.91213361e-01 -1.56540855e-01 -7.96598341e+01]
[-1.76497515e-01 3.67446603e-01 9.76646463e+01]
[-7.92663451e-04 -7.74891393e-04 1.00000000e+00]]
# RANSAC to find the best homography matrix
def ransac_homography(src_pts, dst_pts, n_iter=1000, threshold=0.5):
= src_pts.shape[0] # get the number of points
n = None # initialize the best homography matrix
best_H = 0 # initialize the maximum number of inliers
max_inliers for i in range(n_iter):
= np.random.choice(n, 4, replace=False) # randomly select 4 points
idx = compute_homography(src_pts[idx], dst_pts[idx]) # compute the homography matrix
H = np.hstack((src_pts, np.ones((n, 1)))) # convert to homogeneous coordinates
src_pts_hat = np.hstack((dst_pts, np.ones((n, 1)))) # convert to homogeneous coordinates
dst_pts_hat = np.matmul(H, src_pts_hat.T).T # apply the homography matrix
dst_pts_hat_hat = dst_pts_hat_hat[:, :2] / dst_pts_hat_hat[:, 2:] # convert back to non-homogeneous coordinates
dst_pts_hat_hat = np.linalg.norm(dst_pts_hat_hat - dst_pts, axis=1) # compute the difference between the predicted and actual coordinates
diff = np.sum(diff < threshold) # count the number of inliers
inliers if inliers > max_inliers: # update the best homography matrix
= inliers
max_inliers = H
best_H return best_H # return the best homography matrix
#### TEST THE FUNCTION ####
= open_resize('Dataset/scene1/I12.jpg', 600, 400)
image1 = open_resize('Dataset/scene1/I13.jpg', 600, 400)
image2 = get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H print('Best Homography Matrix:')
print(best_H)
Best Homography Matrix:
[[ 1.10942139e+00 1.24788612e-03 -2.86918367e+02]
[ 1.51381324e-02 1.07799975e+00 -1.47459874e+01]
[ 1.83085652e-04 -3.87132426e-06 1.00000000e+00]]
Step 3
Stitch color images of each scene from the dataset using the homography matrix estimated in step (2) to create a panorama.
Defining the helper functions for stitching
# function to align the images
def align_images(image, H, factor):
= image.shape # get the shape of image
h, w, _ = factor*h, factor*w # create a canvas that is 4 times larger than image
_h, _w = np.zeros((_h, _w, 3), dtype=np.uint8) # initialize the output image
aligned_image
# Loop through each pixel in the output image
for y in range(-h, _h-h):
for x in range(-w, _w-w):
# Apply the homography transformation to find the corresponding pixel in image
= np.dot(H, np.array([x, y, 1]))
pt = pt / pt[2] # Normalize the coordinates
pt # Check if the transformed coordinates are within the bounds of image
if 0 <= pt[0] < image.shape[1] and 0 <= pt[1] < image.shape[0]:
# Interpolate the pixel color value using bilinear interpolation
= int(pt[0]), int(pt[1])
x0, y0 = x0 + 1, y0 + 1
x1, y1 = pt[0] - x0
alpha = pt[1] - y0
beta # Check if the neighboring pixels are within the bounds of image
if 0 <= x0 < image.shape[1] and 0 <= x1 < image.shape[1] and \
0 <= y0 < image.shape[0] and 0 <= y1 < image.shape[0]:
# Bilinear interpolation
= (1 - alpha) * (1 - beta) * image[y0, x0] + \
interpolated_color * (1 - beta) * image[y0, x1] + \
alpha 1 - alpha) * beta * image[y1, x0] + \
(* beta * image[y1, x1]
alpha +h, x+w] = interpolated_color.astype(np.uint8) # Set the pixel value in the canvas as transformed pixel value
aligned_image[yreturn aligned_image, h, w # return the aligned image and canvas parameters
# function to remove the black background
def remove_black_background(img):
= img.sum(axis=2) > 0 # create a mask to remove black pixels
mask = np.where(mask) # get the coordinates of the non-black pixels
y, x = x.min(), x.max() # get the minimum and maximum x coordinates
x_min, x_max = y.min(), y.max() # get the minimum and maximum y coordinates
y_min, y_max = img[y_min:y_max+1, x_min:x_max+1, :] # crop the image
img return img # return the image
# function to align the images
def get_transformed_images(img1, img2, H, focus=2, blend=True, factor=4, b_region=5):
= img1.shape[:2] # height and width of the first image
h1, w1 = img2.shape[:2] # height and width of the second image
h2, w2 = np.array([[0, 0], [0, h1], [w1, h1], [w1, 0]], dtype=np.float32) # corners of the first image
corners1 = np.array([[0, 0], [0, h2], [w2, h2], [w2, 0]], dtype=np.float32) # corners of the second image
corners2
# coordinates of the four corners of the transformed image
= cv2.perspectiveTransform(corners2.reshape(1, -1, 2), H).reshape(-1, 2)
corners2_transformed # coordinates of the four corners of the new image
= np.concatenate((corners1, corners2_transformed), axis=0)
corners = np.int32(corners.min(axis=0).ravel() - 0.5)
x_min, y_min = np.int32(corners.max(axis=0).ravel() + 0.5)
x_max, y_max
= np.array([[1, 0, -x_min], [0, 1, -y_min], [0, 0, 1]]) # translation matrix
T = np.linalg.inv(T.dot(H)) # inverse of the homography matrix
H_inv
if focus == 1: # wrap the second image into the first image
= align_images(img2, H, factor) # align the second image
img_transformed, h_, w_ = img_transformed.copy() # copy the transformed image
img_res + h_, w_ : w1 + w_] = img1 # paste the first image
img_res[h_ : h1
if blend == True: # blend around the edges
= img_res[h_ : h_ + h1 , -b_region + w_ : w_ + b_region] # right edge
img_reg +h1 , -b_region + w_ : w_ + b_region] = cv2.GaussianBlur(img_reg, (3, 1), b_region, b_region)
img_res[h_:h_= img_res[h_ : h_ + h1 , w2 - b_region + w_ : w_ + b_region + w2] # left edge
img_reg + h1 , w2 - b_region + w_ : w_ + b_region + w2] = cv2.GaussianBlur(img_reg, (3, 1), b_region, b_region)
img_res[h_ : h_ = img_res[-b_region + h_ : h_ + b_region , w_ : w_ + w1] # top edge
img_reg -b_region + h_ : h_ + b_region , w_ : w_ + w1] = cv2.GaussianBlur(img_reg, (1, 3), b_region, b_region)
img_res[= img_res[h2 - b_region + h_ : h_ + b_region + h2, + w_ : w_ + w1] # bottom edge
img_reg - b_region + h_ : h_ + b_region + h2, w_ : w_ + w1] = cv2.GaussianBlur(img_reg, (1, 3), b_region, b_region)
img_res[h2
else: # wrap the first image into the second image
= align_images(img1, H_inv, factor) # align the first image
img_transformed, h_, w_ = img_transformed.copy() # copy the transformed image
img_res -y_min + h_ : h2 - y_min + h_, -x_min + w_ : w2 - x_min + w_] = img2 # paste the second image
img_res[
if blend == True: # blend around the edges
= img_res[-y_min + h_ : h_ + h2 - y_min, -x_min - b_region + w_ : w_ + b_region - x_min] # right edge
img_reg -y_min + h_:h_+h2 - y_min, -x_min -b_region+ w_:w_+b_region - x_min] = cv2.GaussianBlur(img_reg, (3, 1), b_region, b_region)
img_res[= img_res[-y_min + h_ : h_ + h2 - y_min, -x_min + w2 - b_region+ w_ : w_ + b_region - x_min + w2] # left edge
img_reg -y_min + h_ : h_ + h2 - y_min, - x_min + w2 - b_region+ w_ : w_ + b_region - x_min + w2] = cv2.GaussianBlur(img_reg, (3, 1), b_region, b_region)
img_res[= img_res[-y_min - b_region + h_ : h_ + b_region - y_min, -x_min + w_ : w_ + w2 - x_min] # top edge
img_reg -y_min - b_region + h_ : h_ + b_region - y_min, - x_min + w_ : w_ + w2 - x_min] = cv2.GaussianBlur(img_reg, (1, 3), b_region, b_region)
img_res[= img_res[-y_min + h2 - b_region + h_ : h_ + b_region - y_min + h2, - x_min + w_ : w_ + w2 - x_min] # bottom edge
img_reg -y_min + h2 - b_region + h_ : h_ + b_region - y_min + h2, -x_min + w_ : w_ + w2 - x_min] = cv2.GaussianBlur(img_reg, (1, 3), b_region, b_region)
img_res[
return img_res # return the transformed image
#### TEST THE FUNCTIONS ####
= open_resize('Dataset/scene4/I41.jpg', 600, 400)
image1 = open_resize('Dataset/scene4/I42.jpg', 600, 400)
image2 = get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =6, h=3)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=1000, threshold=0.5)
best_H
= get_transformed_images(image1, image2, best_H, focus=1)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3)
show_image(aligned_image_1, w
= get_transformed_images(image1, image2, best_H, focus=2)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =6, h=3) show_image(aligned_image_2, w
Scene 1
# creating folder for scene1
if not os.path.exists('Results/scene1'):
'Results/scene1')
os.makedirs(
# operning the images
= open_resize('Dataset/scene1/I11.jpg', 600, 400)
image1 = open_resize('Dataset/scene1/I12.jpg', 600, 400)
image2 = open_resize('Dataset/scene1/I13.jpg', 600, 400)
image3 = open_resize('Dataset/scene1/I14.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =6, h=3)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitiching image3 and image4
= get_src_dst_points(image3, image4)
src_pts, dst_pts, matching_result =6, h=3)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(image3, image4, best_H, focus=1, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =6, h=3) show_image(aligned_image_2, w
# stitiching aligned_image_1 and aligned_image_2
= BGR2RGB(aligned_image_1)
aligned_1 = BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_1, (800, 400))
aligned_1 = cv2.resize(aligned_2, (800, 400))
aligned_2
= get_src_dst_points(aligned_1, aligned_2)
src_pts, dst_pts, matching_result =12, h=6)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(aligned_1, aligned_2, best_H, focus=2)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene1/scene1.jpg', aligned_image_3) cv2.imwrite(
True
Scene 2
# creating folder for scene1
if not os.path.exists('Results/scene2'):
'Results/scene2')
os.makedirs(
# operning the images
= open_resize('Dataset/scene2/I21.jpg', 600, 400)
image1 = open_resize('Dataset/scene2/I22.jpg', 600, 400)
image2 = open_resize('Dataset/scene2/I23.jpg', 600, 400)
image3 = open_resize('Dataset/scene2/I24.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =6, h=3)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=1000, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=1, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitiching aligned_image_1 and image3
= BGR2RGB(aligned_image_1)
aligned_1 = cv2.resize(aligned_1, (800, 400))
aligned_1
= get_src_dst_points(aligned_1, image3)
src_pts, dst_pts, matching_result =10, h=5)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=5)
best_H = get_transformed_images(aligned_1, image3, best_H, focus=2, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =10, h=5) show_image(aligned_image_2, w
# stitiching aligned_image_2 and image4
= BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_2, (1000, 400))
aligned_2
= get_src_dst_points(aligned_2, image4)
src_pts, dst_pts, matching_result =12, h=6)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(aligned_2, image4, best_H, focus=1, blend=True)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene2/scene2.jpg', aligned_image_3) cv2.imwrite(
True
Scene 3
# creating folder for scene1
if not os.path.exists('Results/scene3'):
'Results/scene3')
os.makedirs(
# operning the images
= open_resize('Dataset/scene3/I31.jpg', 600, 400)
image1 = open_resize('Dataset/scene3/I32.jpg', 600, 400)
image2 = open_resize('Dataset/scene3/I33.jpg', 600, 400)
image3 = open_resize('Dataset/scene3/I34.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =6, h=3)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=1000, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitching aligned_image_1 and image3
= BGR2RGB(aligned_image_1)
aligned_1 = cv2.resize(aligned_1, (800, 400))
aligned_1
= get_src_dst_points(aligned_1, image3)
src_pts, dst_pts, matching_result =10, h=5)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(aligned_1, image3, best_H, focus=2, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =10, h=5) show_image(aligned_image_2, w
# stitching aligned_image_2 and image4
= BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_2, (1000, 400))
aligned_2
= get_src_dst_points(aligned_2, image4)
src_pts, dst_pts, matching_result =12, h=6)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(aligned_2, image4, best_H, focus=1, blend=False)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene3/scene3.jpg', aligned_image_3) cv2.imwrite(
True
Scene 4
# creating folder for scene1
if not os.path.exists('Results/scene4'):
'Results/scene4')
os.makedirs(
# operning the images
= open_resize('Dataset/scene4/I41.jpg', 600, 400)
image1 = open_resize('Dataset/scene4/I42.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =10, h=5)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=10)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene4/scene4.jpg', aligned_image_1) cv2.imwrite(
True
Scene 5
# creating folder for scene1
if not os.path.exists('Results/scene5'):
'Results/scene5')
os.makedirs(
# operning the images
= open_resize('Dataset/scene5/I51.jpg', 600, 400)
image1 = open_resize('Dataset/scene5/I52.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =10, h=5)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=8)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene5/scene5.jpg', aligned_image_1) cv2.imwrite(
True
Scene 6
# creating folder for scene1
if not os.path.exists('Results/scene6'):
'Results/scene6')
os.makedirs(
# operning the images
= open_resize('Dataset/scene6/I61.jpg', 600, 400)
image1 = open_resize('Dataset/scene6/I62.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result =10, h=5)
show_image(BGR2RGB(matching_result), w= ransac_homography(src_pts, dst_pts, n_iter=10000, threshold=5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=8)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene6/scene6.jpg', aligned_image_1) cv2.imwrite(
True
Step 4
Stitch the images used as input in step (3) using in-built command for homography estimation and compare it with the panorama obtained in step (3).
Helper function
# function for finding the best homography matrix using cv2 library
def cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=5):
= cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, threshold) # find the best homography matrix
H, mask return H # return the best homography matrix
Scene 1
# operning the images
= open_resize('Dataset/scene1/I11.jpg', 600, 400)
image1 = open_resize('Dataset/scene1/I12.jpg', 600, 400)
image2 = open_resize('Dataset/scene1/I13.jpg', 600, 400)
image3 = open_resize('Dataset/scene1/I14.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitiching image3 and image4
= get_src_dst_points(image3, image4)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(image3, image4, best_H, focus=1, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =6, h=3) show_image(aligned_image_2, w
# stitiching aligned_image_1 and aligned_image_2
= BGR2RGB(aligned_image_1)
aligned_1 = BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_1, (800, 400))
aligned_1 = cv2.resize(aligned_2, (800, 400))
aligned_2
= get_src_dst_points(aligned_1, aligned_2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(aligned_1, aligned_2, best_H, focus=2)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene1/scene1_cv2.jpg', aligned_image_3) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene1/scene1.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene1/scene1_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
Scene 2
# operning the images
= open_resize('Dataset/scene2/I21.jpg', 600, 400)
image1 = open_resize('Dataset/scene2/I22.jpg', 600, 400)
image2 = open_resize('Dataset/scene2/I23.jpg', 600, 400)
image3 = open_resize('Dataset/scene2/I24.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=1, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitiching aligned_image_1 and image3
= BGR2RGB(aligned_image_1)
aligned_1 = cv2.resize(aligned_1, (800, 400))
aligned_1
= get_src_dst_points(aligned_1, image3)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=5)
best_H = get_transformed_images(aligned_1, image3, best_H, focus=2, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =10, h=5) show_image(aligned_image_2, w
# stitiching aligned_image_2 and image4
= BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_2, (1000, 400))
aligned_2
= get_src_dst_points(aligned_2, image4)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(aligned_2, image4, best_H, focus=1, blend=True)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene2/scene2_cv2.jpg', aligned_image_3) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene2/scene2.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene2/scene2_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
Scene 3
# operning the images
= open_resize('Dataset/scene3/I31.jpg', 600, 400)
image1 = open_resize('Dataset/scene3/I32.jpg', 600, 400)
image2 = open_resize('Dataset/scene3/I33.jpg', 600, 400)
image3 = open_resize('Dataset/scene3/I34.jpg', 600, 400) image4
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =6, h=3) show_image(aligned_image_1, w
# stitching aligned_image_1 and image3
= BGR2RGB(aligned_image_1)
aligned_1 = cv2.resize(aligned_1, (800, 400))
aligned_1
= get_src_dst_points(aligned_1, image3)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=2)
best_H = get_transformed_images(aligned_1, image3, best_H, focus=2, blend=False)
aligned_image_2 = remove_black_background(BGR2RGB(aligned_image_2))
aligned_image_2 =10, h=5) show_image(aligned_image_2, w
# stitching aligned_image_2 and image4
= BGR2RGB(aligned_image_2)
aligned_2 = cv2.resize(aligned_2, (1000, 400))
aligned_2
= get_src_dst_points(aligned_2, image4)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(aligned_2, image4, best_H, focus=1, blend=False)
aligned_image_3 = remove_black_background(BGR2RGB(aligned_image_3))
aligned_image_3 =12, h=6)
show_image(aligned_image_3, w
# saving the stitched image
= BGR2RGB(aligned_image_3)
aligned_image_3 'Results/scene3/scene3_cv2.jpg', aligned_image_3) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene3/scene3.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene3/scene3_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
Scene 4
# operning the images
= open_resize('Dataset/scene4/I41.jpg', 600, 400)
image1 = open_resize('Dataset/scene4/I42.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=10)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene4/scene4_cv2.jpg', aligned_image_1) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene4/scene4.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene4/scene4_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
Scene 5
# operning the images
= open_resize('Dataset/scene5/I51.jpg', 600, 400)
image1 = open_resize('Dataset/scene5/I52.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=0.5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=8)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene5/scene5_cv2.jpg', aligned_image_1) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene5/scene5.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene5/scene5_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
Scene 6
# operning the images
= open_resize('Dataset/scene6/I61.jpg', 600, 400)
image1 = open_resize('Dataset/scene6/I62.jpg', 600, 400) image2
# stitiching image1 and image2
= get_src_dst_points(image1, image2)
src_pts, dst_pts, matching_result = cv2_get_RANSAC_Homography(src_pts, dst_pts, threshold=5)
best_H = get_transformed_images(image1, image2, best_H, focus=2, blend=True)
aligned_image_1 = remove_black_background(BGR2RGB(aligned_image_1))
aligned_image_1 =10, h=8)
show_image(aligned_image_1, w
# saving the stitched image
= BGR2RGB(aligned_image_1)
aligned_image_1 'Results/scene6/scene6_cv2.jpg', aligned_image_1) cv2.imwrite(
True
Comparing the results of the two methods
= cv2.imread('Results/scene6/scene6.jpg')
custom =12, h=6, title='Custom Homography and RANSAC')
show_image(BGR2RGB(custom), w
= cv2.imread('Results/scene6/scene6_cv2.jpg')
inbuilt =12, h=6, title='Inbuilt Homography and RANSAC') show_image(BGR2RGB(inbuilt), w
The image obtained through a custom implementation of homography computation and RANSAC looks similar to the image obtained through the built-in function for homography estimation.
References
- Image stitching, https://en.wikipedia.org/wiki/Image_stitching
- Perspective Transformation, https://www.tutorialspoint.com/dip/perspective_transformation.htm
- First Principles of Computer Vision, Columbia Engineering, https://fpcv.cs.columbia.edu
- Feature Based Panoramic Image Stitching, https://in.mathworks.com/help/vision/ug/feature-based-panoramic-image-stitching.html