/
blend_and_stitch.py
131 lines (107 loc) · 5.49 KB
/
blend_and_stitch.py
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import cv2
import numpy as np
class stitcher():
def LaplacianBlend(self,images, masks, n=5):
"""
Blending the input the input images using Laplacian Blending. Essentially, we reduce the
the image to smaller sizes using OpenCV()'s pyrDown() and obtaining a gaussian pyramid.
Then upsample the images using pyrUp() and finding the difference of Gaussian and hence
the laplacian pyramid. Image mask are used to find the partition and the Laplacian pyramid
images are joined to get the desired result's laplacian pyramid. Next, the pyramid is upsampled
again and add the Gaussians at each level to get the desired result.
"""
# Ensuring the input images are a multiple of 2^n where n is the number of
# layers of the laplacian pyramid.
print(images[0].shape)
assert(images[0].shape[0] % pow(2, n) ==
0 and images[0].shape[1] % pow(2, n) == 0)
# Empty list of Gaussian pyramids and laplacian pyramids for each of the input images
g_pyramids = [None]*len(images)
l_pyramids = [None]*len(images)
_, W, _ = images[0].shape
# Calculating pyramids of the images
for i in range(len(images)):
# Gaussian Pyramids
G = images[i].copy()
g_pyramids[i] = [G] #Storing the pyramids in a list to the corresponding image index
for _ in range(n):
G = cv2.pyrDown(G)
g_pyramids[i].append(np.float32(G))
# Laplacian Pyramids
l_pyramids[i] = [G]
for j in range(len(g_pyramids[i])-2, -1, -1):
G_up = cv2.pyrUp(G)
G = g_pyramids[i][j]
L = G - G_up # Difference of Gaussian (DOG)
l_pyramids[i].append(L) #Storing the pyramids in a list to the corresponding image index
# Making the masks boolean for further operations
for i in range(len(masks)):
masks[i] = masks[i].astype('bool')
common_mask = masks[0].copy() #All masks will be iterated and will be combined to the common mask
common_image = images[0].copy() #All images will be iterated and will be combined to the common image
common_pyramids = [l_pyramids[0][i].copy()
for i in range(len(l_pyramids[0]))] #All pyramids will be iterated and will be combined to the common pyr
final_image = None
# Iterating on the images.
for i in range(1, len(images)):
_, x1 = np.where(common_mask == 1)
_, x2 = np.where(masks[i] == 1)
# Sorting the common image and the image to be added to left and right
if np.max(x1) > np.max(x2):
left_py = l_pyramids[i]
right_py = common_pyramids
else:
left_py = common_pyramids
right_py = l_pyramids[i]
# Finding the region of intersection between the common image and the current image
mask_intersection = np.bitwise_and(common_mask, masks[i])
if True in mask_intersection:
_, x = np.where(mask_intersection == 1)
# finding the coordinate for the verticle line which would helpin overlapping the left and the right image.
x_min, x_max = np.min(x), np.max(x)
midPt = ((x_max-x_min)/2 + x_min)/W
# Finally we add the pyramids
LS = []
for lap_L, lap_R in zip(left_py, right_py):
_, cols, _ = lap_L.shape
ls = np.hstack((lap_L[:, 0:int(midPt*cols)], lap_R[:, int(midPt*cols):]))
LS.append(ls)
# If there is no intersection, simply add the images
else:
LS = []
for lap_L, lap_R in zip(left_py, right_py):
_, cols, _ = lap_L.shape
ls = lap_L + lap_R
LS.append(ls)
# Reconstruct the image
final_image = LS[0]
for j in range(1, n+1):
final_image = cv2.pyrUp(final_image)
final_image = final_image + LS[j]
final_image[final_image>255] = 255; final_image[final_image<0] = 0
common_image = final_image
common_mask = np.sum(common_image.astype(bool), axis=2).astype(bool)
common_pyramids = LS
return np.uint8(final_image)
def stitchOnly(self, images, masks):
'''
Unlike laplacian blending, this doesn't blend, this only stitches
the images using the masks.
'''
for i in range(len(masks)):
masks[i] = masks[i].astype('bool')
_, W, _ = images[0].shape
common_mask = masks[0].copy() #All masks will be iterated and will be combined to the common mask
common_image = images[0].copy() #All images will be iterated and will be combined to the common image
for i in range(len(images)):
mask_intersection = np.bitwise_and(common_mask, masks[i])
if True in mask_intersection:
c = images[i]!=0
common_image[c] = images[i][c]
# If there is no intersection, simply add the images
else:
common_image = common_image+images[i]
common_mask = np.sum(common_image.astype(bool), axis=2).astype(bool)
return common_image
def stictDwise(self, images,masks):
pass