File size: 4,072 Bytes
6cfbe50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import cv2
import numpy as np
import matplotlib.pyplot as plt
import pdb

def rotate_to_horizontal(image):
    # Rotate the image to horizontal (90 degrees counterclockwise)
    rotated_image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
    return rotated_image

def rotate_to_vertical(image):
    # Rotate the image back to vertical (90 degrees clockwise)
    rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
    return rotated_image

def plot_images(images):
    num_images = len(images)
    
    for i, image in enumerate(images):
        plt.figure(figsize=(6, 6))
        plt.imshow(image)
        plt.title(f"Image {i+1}/{num_images}")
        plt.axis('off')
        plt.show()

def image_stitching(image_paths):
    images = [cv2.imread(path) for path in image_paths]

    images = [image.astype(np.uint8) for image in images]
    images = [rotate_to_horizontal(image) for image in images]
    images = list(reversed(images))
    if len(images) == 15:
        images = images[2:12]
    #plot_images(images)
    
    # Create a list to store the stitched images
    stitched_images = []

    # Accumulated homography matrix for stitching
    accumulated_homography = np.eye(3)

    # Iterate through pairs of adjacent images and stitch them together
    for i in range(len(images) - 1):
        # Perform keypoint and feature descriptor extraction
        orb = cv2.ORB_create()
        keypoints_and_descriptors = [orb.detectAndCompute(image, None) for image in [images[i], images[i + 1]]]

        # Match the keypoints using Brute-Force Matcher
        bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
        matches = bf.match(keypoints_and_descriptors[0][1], keypoints_and_descriptors[1][1])

        # Filter the matches to remove outliers using RANSAC
        src_pts = np.float32([keypoints_and_descriptors[0][0][m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
        dst_pts = np.float32([keypoints_and_descriptors[1][0][m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)

        M, _ = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)

        # Accumulate the homography matrices
        accumulated_homography = np.dot(M, accumulated_homography)

        # Warp perspective and stitch the images
        stitched_image = cv2.warpPerspective(images[i + 1], accumulated_homography, 
                                             (images[i].shape[1] + images[i + 1].shape[1], images[i].shape[0]))
        stitched_image[0:images[i].shape[0], 0:images[i].shape[1]] = images[i]

        # Remove the empty pixels and retain maximum image information
        # stitched_image = remove_empty_pixels(stitched_image)

        stitched_images.append(stitched_image)

    # Combine all stitched images into a final panorama
    final_panorama = stitched_images[0]
    for i in range(1, len(stitched_images)):
        final_panorama = cv2.warpPerspective(stitched_images[i], np.eye(3), 
                                             (final_panorama.shape[1] + stitched_images[i].shape[1], final_panorama.shape[0]))
        final_panorama[0:stitched_images[i].shape[0], 0:stitched_images[i].shape[1]] = stitched_images[i]

    gray_images = [cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) for image in images[:2]]

    # Draw the keypoints on the images
    keypoints_drawn = [cv2.drawKeypoints(gray_image, kp[0], None, color=(0, 255, 0), 
                                         flags=cv2.DrawMatchesFlags_DRAW_RICH_KEYPOINTS) for gray_image, kp in 
                                         zip(gray_images, keypoints_and_descriptors[:2])]

    # Draw the matches on the images
    matches_drawn = cv2.drawMatches(images[0], keypoints_and_descriptors[0][0], images[1], 
                                    keypoints_and_descriptors[1][0], matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
    
    # Crop the final image to 512x512 centered around the middle
    cropped_final_panorama = final_panorama[:512, :512]
    rotated_final_panorama = rotate_to_vertical(cropped_final_panorama)


    return rotated_final_panorama