gokaygokay commited on
Commit
a90cc5e
·
verified ·
1 Parent(s): 67a4eb4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +212 -0
app.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import scipy as sp
4
+ import scipy.sparse.linalg
5
+ import gradio as gr
6
+ import os
7
+
8
+ def get_image(img, mask=False):
9
+ if mask:
10
+ return np.where(img > 127, 1, 0)
11
+ return cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype('double') / 255.0
12
+
13
+ def neighbours(i, j, max_i, max_j):
14
+ pairs = []
15
+ for n in [-1, 1]:
16
+ if 0 <= i+n <= max_i:
17
+ pairs.append((i+n, j))
18
+ if 0 <= j+n <= max_j:
19
+ pairs.append((i, j+n))
20
+ return pairs
21
+
22
+ def poisson_blend(img_s, mask, img_t):
23
+ img_s_h, img_s_w = img_s.shape
24
+
25
+ nnz = (mask>0).sum()
26
+ im2var = -np.ones(mask.shape[0:2], dtype='int32')
27
+ im2var[mask>0] = np.arange(nnz)
28
+
29
+ ys, xs = np.where(mask==1)
30
+
31
+ A = sp.sparse.lil_matrix((4*nnz, nnz))
32
+ b = np.zeros(4*nnz)
33
+
34
+ e = 0
35
+ for n in range(nnz):
36
+ y, x = ys[n], xs[n]
37
+
38
+ for n_y, n_x in neighbours(y, x, img_s_h-1, img_s_w-1):
39
+ A[e, im2var[y][x]] = 1
40
+ b[e] = img_s[y][x] - img_s[n_y][n_x]
41
+
42
+ if im2var[n_y][n_x] != -1:
43
+ A[e, im2var[n_y][n_x]] = -1
44
+ else:
45
+ b[e] += img_t[n_y][n_x]
46
+ e += 1
47
+
48
+ A = sp.sparse.csr_matrix(A)
49
+ v = sp.sparse.linalg.lsqr(A, b)[0]
50
+
51
+ img_t_out = img_t.copy()
52
+
53
+ for n in range(nnz):
54
+ y, x = ys[n], xs[n]
55
+ img_t_out[y][x] = v[im2var[y][x]]
56
+
57
+ return np.clip(img_t_out, 0, 1)
58
+
59
+ def mixed_blend(img_s, mask, img_t):
60
+ img_s_h, img_s_w = img_s.shape
61
+
62
+ nnz = (mask>0).sum()
63
+ im2var = -np.ones(mask.shape[0:2], dtype='int32')
64
+ im2var[mask>0] = np.arange(nnz)
65
+
66
+ ys, xs = np.where(mask==1)
67
+
68
+ A = sp.sparse.lil_matrix((4*nnz, nnz))
69
+ b = np.zeros(4*nnz)
70
+
71
+ e = 0
72
+ for n in range(nnz):
73
+ y, x = ys[n], xs[n]
74
+
75
+ for n_y, n_x in neighbours(y, x, img_s_h-1, img_s_w-1):
76
+ ds = img_s[y][x] - img_s[n_y][n_x]
77
+ dt = img_t[y][x] - img_t[n_y][n_x]
78
+ d = ds if abs(ds) > abs(dt) else dt
79
+
80
+ A[e, im2var[y][x]] = 1
81
+ b[e] = d
82
+
83
+ if im2var[n_y][n_x] != -1:
84
+ A[e, im2var[n_y][n_x]] = -1
85
+ else:
86
+ b[e] += img_t[n_y][n_x]
87
+ e += 1
88
+
89
+ A = sp.sparse.csr_matrix(A)
90
+ v = sp.sparse.linalg.lsqr(A, b)[0]
91
+
92
+ img_t_out = img_t.copy()
93
+
94
+ for n in range(nnz):
95
+ y, x = ys[n], xs[n]
96
+ img_t_out[y][x] = v[im2var[y][x]]
97
+
98
+ return np.clip(img_t_out, 0, 1)
99
+
100
+ def _2d_gaussian(sigma):
101
+ ksize = np.int(np.ceil(sigma)*6+1)
102
+ gaussian_1d = cv2.getGaussianKernel(ksize, sigma)
103
+ return gaussian_1d * np.transpose(gaussian_1d)
104
+
105
+ def _low_pass_filter(img, sigma):
106
+ return cv2.filter2D(img, -1, _2d_gaussian(sigma))
107
+
108
+ def _high_pass_filter(img, sigma):
109
+ return img - _low_pass_filter(img, sigma)
110
+
111
+ def _gaus_pyramid(img, depth, sigma):
112
+ _im = img.copy()
113
+ pyramid = []
114
+ for d in range(depth-1):
115
+ _im = _low_pass_filter(_im.copy(), sigma)
116
+ pyramid.append(_im)
117
+ _im = cv2.pyrDown(_im)
118
+ return pyramid
119
+
120
+ def _lap_pyramid(img, depth, sigma):
121
+ _im = img.copy()
122
+ pyramid = []
123
+ for d in range(depth-1):
124
+ lap = _high_pass_filter(_im.copy(), sigma)
125
+ pyramid.append(lap)
126
+ _im = cv2.pyrDown(_im)
127
+ return pyramid
128
+
129
+ def _blend(img1, img2, mask):
130
+ return img1 * mask + img2 * (1.0 - mask)
131
+
132
+ def laplacian_blend(img1, img2, mask, depth=5, sigma=25):
133
+ mask_gaus_pyramid = _gaus_pyramid(mask, depth, sigma)
134
+ img1_lap_pyramid, img2_lap_pyramid = _lap_pyramid(img1, depth, sigma), _lap_pyramid(img2, depth, sigma)
135
+
136
+ blended = [_blend(obj, bg, mask) for obj, bg, mask in zip(img1_lap_pyramid, img2_lap_pyramid, mask_gaus_pyramid)][::-1]
137
+
138
+ h, w = blended[0].shape[:2]
139
+
140
+ img1 = cv2.resize(img1, (w, h))
141
+ img2 = cv2.resize(img2, (w, h))
142
+ mask = cv2.resize(mask, (w, h))
143
+
144
+ blanded_img = _blend(img1, img2, mask)
145
+ blanded_img = cv2.resize(blanded_img, blended[0].shape[:2])
146
+
147
+ imgs = []
148
+ for d in range(0, depth-1):
149
+ gaussian_img = _low_pass_filter(blanded_img.copy(), sigma)
150
+ reconstructed_img = cv2.add(blended[d], gaussian_img)
151
+
152
+ imgs.append(reconstructed_img)
153
+ blanded_img = cv2.pyrUp(reconstructed_img)
154
+
155
+ return np.clip(imgs[-1], 0, 1)
156
+
157
+ def load_example_images(bg_path, obj_path, mask_path):
158
+ bg_img = cv2.imread(bg_path)
159
+ bg_img = cv2.cvtColor(bg_img, cv2.COLOR_BGR2RGB)
160
+
161
+ obj_img = cv2.imread(obj_path)
162
+ obj_img = cv2.cvtColor(obj_img, cv2.COLOR_BGR2RGB)
163
+
164
+ mask_img = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
165
+ mask_img = np.where(mask_img > 127, 255, 0).astype(np.uint8)
166
+
167
+ return bg_img, obj_img, mask_img
168
+
169
+ # Modify the blend_images function to accept numpy arrays directly
170
+ def blend_images(bg_img, obj_img, mask_img, blend_method):
171
+ bg_img = get_image(bg_img)
172
+ obj_img = get_image(obj_img)
173
+ mask_img = get_image(mask_img, mask=True)
174
+
175
+ # Resize mask to match object image size
176
+ mask_img = cv2.resize(mask_img, (obj_img.shape[1], obj_img.shape[0]))
177
+
178
+ if blend_method == "Poisson":
179
+ blend_func = poisson_blend
180
+ elif blend_method == "Mixed Gradient":
181
+ blend_func = mixed_blend
182
+ else: # Laplacian
183
+ return laplacian_blend(obj_img, bg_img, np.stack((mask_img,)*3, axis=-1), 5, 25)
184
+
185
+ blend_img = np.zeros(bg_img.shape)
186
+ for b in range(3):
187
+ blend_img[:,:,b] = blend_func(obj_img[:,:,b], mask_img, bg_img[:,:,b].copy())
188
+
189
+ return (blend_img * 255).astype(np.uint8)
190
+
191
+ examples = [
192
+ ["img1.jpg", "img2.jpg", "mask1.jpg", "Poisson"],
193
+ ["img3.jpg", "img4.jpg", "mask2.jpg", "Mixed Gradient"],
194
+ ["img6.jpg", "img9.jpg", "mask3.jpg", "Laplacian"]
195
+ ]
196
+
197
+ iface = gr.Interface(
198
+ fn=blend_images,
199
+ inputs=[
200
+ gr.Image(label="Background Image", type="numpy"),
201
+ gr.Image(label="Object Image", type="numpy"),
202
+ gr.Image(label="Mask Image", type="numpy"),
203
+ gr.Radio(["Poisson", "Mixed Gradient", "Laplacian"], label="Blending Method")
204
+ ],
205
+ outputs=gr.Image(label="Blended Image"),
206
+ title="Image Blending with Examples",
207
+ description="Choose from example images or upload your own to blend using different methods.",
208
+ examples=examples,
209
+ cache_examples=True
210
+ )
211
+
212
+ iface.launch()