Skip to content

Commit a01abc8

Browse files
committed
backup solver
1 parent d8a773b commit a01abc8

5 files changed

+232
-43
lines changed

array.npz

84.7 MB
Binary file not shown.

main.py

+20-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
gx, gy, gxlist, gylist = estimate_watermark('images/fotolia_processed')
44

5-
est, loss = poisson_reconstruct(gx, gy)
5+
# est = poisson_reconstruct(gx, gy, np.zeros(gx.shape)[:,:,0])
66
cropped_gx, cropped_gy = crop_watermark(gx, gy)
7-
W_m, _ = poisson_reconstruct(cropped_gx, cropped_gy)
7+
W_m = poisson_reconstruct(cropped_gx, cropped_gy)
88

99
# random photo
1010
img = cv2.imread('images/fotolia_processed/fotolia_137840645.jpg')
@@ -19,14 +19,30 @@
1919
J, img_paths = get_cropped_images('images/fotolia_processed', num_images, start, end, cropped_gx.shape)
2020
# get a random subset of J
2121
idx = [389, 144, 147, 468, 423, 92, 3, 354, 196, 53, 470, 445, 314, 349, 105, 366, 56, 168, 351, 15, 465, 368, 90, 96, 202, 54, 295, 137, 17, 79, 214, 413, 454, 305, 187, 4, 458, 330, 290, 73, 220, 118, 125, 180, 247, 243, 257, 194, 117, 320, 104, 252, 87, 95, 228, 324, 271, 398, 334, 148, 425, 190, 78, 151, 34, 310, 122, 376, 102, 260]
22-
22+
idx = idx[:50]
2323
# Wm = (255*PlotImage(W_m))
2424
Wm = W_m - W_m.min()
2525

2626
# get threshold of W_m for alpha matte estimate
2727
alph_est = estimate_normalized_alpha(J, Wm)
2828
alph = np.stack([alph_est, alph_est, alph_est], axis=2)
29-
C = estimate_blend_factor(J, Wm, alph)
29+
C, est_Ik = estimate_blend_factor(J, Wm, alph)
30+
31+
alpha = alph.copy()
32+
for i in xrange(3):
33+
alpha[:,:,i] = C[i]*alpha[:,:,i]
34+
35+
Wm = Wm + alpha*est_Ik
36+
37+
W = Wm.copy()
38+
for i in xrange(3):
39+
W[:,:,i]/=C[i]
40+
41+
# now we have the values of alpha, Wm, J
42+
# Solve for all images
43+
44+
45+
3046
# W_m_threshold = (255*PlotImage(np.average(W_m, axis=2))).astype(np.uint8)
3147
# ret, thr = cv2.threshold(W_m_threshold, 127, 255, cv2.THRESH_BINARY)
3248

src/estimate_watermark.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import numpy as np
44
import warnings
55
from matplotlib import pyplot as plt
6+
import math
7+
import numpy
8+
import scipy, scipy.fftpack
69

710
# Variables
811
KERNEL_SIZE = 3
@@ -48,6 +51,46 @@ def PlotImage(image):
4851
return (im - np.min(im))/(np.max(im) - np.min(im))
4952

5053

54+
def poisson_reconstruct2(gradx, grady, boundarysrc):
55+
# Thanks to Dr. Ramesh Raskar for providing the original matlab code from which this is derived
56+
# Dr. Raskar's version is available here: http://web.media.mit.edu/~raskar/photo/code.pdf
57+
58+
# Laplacian
59+
gyy = grady[1:,:-1] - grady[:-1,:-1]
60+
gxx = gradx[:-1,1:] - gradx[:-1,:-1]
61+
f = numpy.zeros(boundarysrc.shape)
62+
f[:-1,1:] += gxx
63+
f[1:,:-1] += gyy
64+
65+
# Boundary image
66+
boundary = boundarysrc.copy()
67+
boundary[1:-1,1:-1] = 0;
68+
69+
# Subtract boundary contribution
70+
f_bp = -4*boundary[1:-1,1:-1] + boundary[1:-1,2:] + boundary[1:-1,0:-2] + boundary[2:,1:-1] + boundary[0:-2,1:-1]
71+
f = f[1:-1,1:-1] - f_bp
72+
73+
# Discrete Sine Transform
74+
tt = scipy.fftpack.dst(f, norm='ortho')
75+
fsin = scipy.fftpack.dst(tt.T, norm='ortho').T
76+
77+
# Eigenvalues
78+
(x,y) = numpy.meshgrid(range(1,f.shape[1]+1), range(1,f.shape[0]+1), copy=True)
79+
denom = (2*numpy.cos(math.pi*x/(f.shape[1]+2))-2) + (2*numpy.cos(math.pi*y/(f.shape[0]+2)) - 2)
80+
81+
f = fsin/denom
82+
83+
# Inverse Discrete Sine Transform
84+
tt = scipy.fftpack.idst(f, norm='ortho')
85+
img_tt = scipy.fftpack.idst(tt.T, norm='ortho').T
86+
87+
# New center + old boundary
88+
result = boundary
89+
result[1:-1,1:-1] = img_tt
90+
91+
return result
92+
93+
5194
def poisson_reconstruct(gradx, grady, kernel_size=KERNEL_SIZE, num_iters=100, h=0.1,
5295
boundary_image=None, boundary_zero=True):
5396
"""
@@ -77,7 +120,7 @@ def poisson_reconstruct(gradx, grady, kernel_size=KERNEL_SIZE, num_iters=100, h=
77120
error = np.sum(np.square(est-old_est))
78121
loss.append(error)
79122

80-
return (est, loss)
123+
return (est)
81124

82125

83126
def image_threshold(image, threshold=0.5):

src/estimate_watermark.pyc

1.23 KB
Binary file not shown.

src/watermark_reconstruct.py

+168-38
Original file line numberDiff line numberDiff line change
@@ -136,42 +136,172 @@ def estimate_normalized_alpha(J, W_m, num_images=30):
136136
return alpha
137137

138138
# estimate the blend factor C
139+
# def estimate_blend_factor(J, W_m, alph, threshold=0.01*255):
140+
# alpha_n = alph
141+
# S = J.copy()
142+
# num_images = S.shape[0]
143+
# # for i in xrange(num_images):
144+
# # S[i] = PlotImage(S[i])
145+
# # R = (S<=threshold).astype(np.float64)
146+
# R = (S>-1).astype(np.float64)
147+
148+
# est_Ik = S.copy()
149+
# # est_Ik[S>threshold] = nan
150+
# est_Ik = np.nanmedian(est_Ik, axis=0)
151+
# est_Ik[isnan(est_Ik)] = 0
152+
153+
# alpha_k = R.copy()
154+
# beta_k = R*J
155+
# for i in xrange(num_images):
156+
# alpha_k[i] *= alpha_n*est_Ik
157+
# beta_k[i] -= R[i]*W_m
158+
# beta_k = np.abs(beta_k)
159+
# # we have alpha and beta, solve for c's now
160+
# c = []
161+
# for i in range(3):
162+
# c_i = np.sum(beta_k[:,:,:,i]*alpha_k[:,:,:,i])/np.sum(np.square(alpha_k[:,:,:,i]))
163+
# c.append(c_i)
164+
# return c
165+
139166
def estimate_blend_factor(J, W_m, alph, threshold=0.01*255):
140-
alpha_n = alph
141-
S = J.copy()
142-
num_images = S.shape[0]
143-
# for i in xrange(num_images):
144-
# S[i] = PlotImage(S[i])
145-
# R = (S<=threshold).astype(np.float64)
146-
R = (S>-1).astype(np.float64)
147-
148-
est_Ik = S.copy()
149-
# est_Ik[S>threshold] = nan
150-
est_Ik = np.nanmedian(est_Ik, axis=0)
151-
est_Ik[isnan(est_Ik)] = 0
152-
153-
alpha_k = R.copy()
154-
beta_k = R*J
155-
for i in xrange(num_images):
156-
alpha_k[i] *= alpha_n*est_Ik
157-
beta_k[i] -= R[i]*W_m
158-
beta_k = np.abs(beta_k)
159-
# we have alpha and beta, solve for c's now
160-
c = []
161-
for i in range(3):
162-
c_i = np.sum(beta_k[:,:,:,i]*alpha_k[:,:,:,i])/np.sum(np.square(alpha_k[:,:,:,i]))
163-
c.append(c_i)
164-
return c
165-
166-
# TODO: Remove the blend factor formulation with something more suitable
167-
# Like taking the edge details instead of sum of squares of intensity
168-
# c=0.1
169-
# ...: while c<1:
170-
# ...: img = (S[61]-c*alph*est_Ik)
171-
# ...: sx = cv2.Sobel(img, cv2.CV_64F, 1, 0, 3)
172-
# ...: sy = cv2.Sobel(img, cv2.CV_64F, 0, 1, 3)
173-
# ...: edge = np.sqrt(sx**2 + sy**2)
174-
# ...: edge = img
175-
# ...: plt.subplot(3,3,int(c*10)); plt.imshow(PlotImage(edge));
176-
# ...: c+=0.1
177-
# ...: print(np.mean(np.square(edge)))
167+
K, m, n, p = J.shape
168+
Jm = (J - W_m)
169+
gx_jm = np.zeros(J.shape)
170+
gy_jm = np.zeros(J.shape)
171+
172+
for i in xrange(K):
173+
gx_jm[i] = cv2.Sobel(Jm[i], cv2.CV_64F, 1, 0, 3)
174+
gy_jm[i] = cv2.Sobel(Jm[i], cv2.CV_64F, 0, 1, 3)
175+
176+
Jm_grad = np.sqrt(gx_jm**2 + gy_jm**2)
177+
178+
est_Ik = alph*np.median(J, axis=0)
179+
gx_estIk = cv2.Sobel(est_Ik, cv2.CV_64F, 1, 0, 3)
180+
gy_estIk = cv2.Sobel(est_Ik, cv2.CV_64F, 0, 1, 3)
181+
estIk_grad = np.sqrt(gx_estIk**2 + gy_estIk**2)
182+
183+
C = []
184+
for i in xrange(3):
185+
c_i = np.sum(Jm_grad[:,:,:,i]*estIk_grad[:,:,i])/np.sum(np.square(estIk_grad[:,:,i]))/K
186+
print(c_i)
187+
C.append(c_i)
188+
189+
return C, est_Ik
190+
191+
192+
def Func_Phi(X, epsilon=1e-3):
193+
return np.sqrt(X + epsilon**2)
194+
195+
def Func_Phi_deriv(X, epsilon=1e-3):
196+
return 0.5/Func_Phi(X, epsilon)
197+
198+
def solve_images(J, W_m, alpha, W_init, gamma=1, beta=0.01, lambda_w=0.01, lambda_i=0.01, lambda_a=0.01, iters=2):
199+
'''
200+
Master solver, follows the algorithm given in the supplementary.
201+
W_init: Initial value of W
202+
Step 1: Image Watermark decomposition
203+
'''
204+
# prepare variables
205+
K, m, n, p = J.shape
206+
size = m*n*p
207+
208+
sobelx = get_xSobel_matrix(m, n, p)
209+
sobely = get_ySobel_matrix(m, n, p)
210+
Ik = np.zeros(J.shape)
211+
Wk = np.zeros(J.shape)
212+
for i in xrange(K):
213+
Ik[i] = J[i] - W_m
214+
Wk[i] = W_init.copy()
215+
216+
# This is for median images
217+
W = W_init.copy()
218+
219+
# Iterations
220+
for _ in xrange(iters):
221+
222+
# Step 1
223+
print("Step 1")
224+
alpha_gx = cv2.Sobel(alpha, cv2.CV_64F, 1, 0, 3)
225+
alpha_gy = cv2.Sobel(alpha, cv2.CV_64F, 0, 1, 3)
226+
227+
Wm_gx = cv2.Sobel(W_m, cv2.CV_64F, 1, 0, 3)
228+
Wm_gy = cv2.Sobel(W_m, cv2.CV_64F, 0, 1, 3)
229+
230+
cx = diags(np.abs(alpha_gx).reshape(-1))
231+
cy = diags(np.abs(alpha_gy).reshape(-1))
232+
233+
alpha_diag = diags(alpha.reshape(-1))
234+
alpha_bar_diag = diags((1-alpha).reshape(-1))
235+
236+
for i in xrange(K):
237+
# prep vars
238+
Wkx = cv2.Sobel(Wk[i], cv2.CV_64F, 1, 0, 3)
239+
Wky = cv2.Sobel(Wk[i], cv2.CV_64F, 0, 1, 3)
240+
241+
Ikx = cv2.Sobel(Ik[i], cv2.CV_64F, 1, 0, 3)
242+
Iky = cv2.Sobel(Ik[i], cv2.CV_64F, 0, 1, 3)
243+
244+
alphaWk = alpha*Wk[i]
245+
alphaWk_gx = cv2.Sobel(alphaWk, cv2.CV_64F, 1, 0, 3)
246+
alphaWk_gy = cv2.Sobel(alphaWk, cv2.CV_64F, 0, 1, 3)
247+
248+
phi_data = diags( Func_Phi_deriv(np.square(alpha*Wk[i] + (1-alpha)*Ik[i] - J[i]).reshape(-1)) )
249+
phi_W = diags( Func_Phi_deriv(np.square( np.abs(alpha_gx)*Wkx + np.abs(alpha_gy)*Wky ).reshape(-1)) )
250+
phi_I = diags( Func_Phi_deriv(np.square( np.abs(alpha_gx)*Ikx + np.abs(alpha_gy)*Iky ).reshape(-1)) )
251+
phi_f = diags( Func_Phi_deriv( ((Wm_gx - alphaWk_gx)**2 + (Wm_gy - alphaWk_gy)**2 ).reshape(-1)) )
252+
phi_aux = diags( Func_Phi_deriv(np.square(Wk[i] - W).reshape(-1)) )
253+
phi_rI = diags( Func_Phi_deriv( np.abs(alpha_gx)*(Ikx**2) + np.abs(alpha_gy)*(Iky**2) ).reshape(-1) )
254+
phi_rW = diags( Func_Phi_deriv( np.abs(alpha_gx)*(Wkx**2) + np.abs(alpha_gy)*(Wky**2) ).reshape(-1) )
255+
256+
L_i = sobelx.T.dot(cx*phi_rI).dot(sobelx) + sobely.T.dot(cy*phi_rI).dot(sobely)
257+
L_w = sobelx.T.dot(cx*phi_rW).dot(sobelx) + sobely.T.dot(cy*phi_rW).dot(sobely)
258+
L_f = sobelx.T.dot(phi_f).dot(sobelx) + sobely.T.dot(phi_f).dot(sobely)
259+
A_f = alpha_diag.T.dot(L_f).dot(alpha_diag) + gamma*phi_aux
260+
261+
bW = alpha_diag.dot(phi_data).dot(J[i].reshape(-1)) + beta*L_f.dot(W_m.reshape(-1)) + gamma*phi_aux.dot(W.reshape(-1))
262+
bI = alpha_bar_diag.dot(phi_data).dot(J[i].reshape(-1))
263+
264+
A = vstack([hstack([(alpha_diag**2)*phi_data + lambda_w*L_w + beta*A_f, alpha_diag*alpha_bar_diag*phi_data]), \
265+
hstack([alpha_diag*alpha_bar_diag*phi_data, (alpha_bar_diag**2)*phi_data + lambda_i*L_i])]).tocsr()
266+
267+
b = np.hstack([bW, bI])
268+
x = linalg.spsolve(A, b)
269+
270+
Wk[i] = x[:size].reshape(m, n, p)
271+
Ik[i] = x[size:].reshape(m, n, p)
272+
plt.subplot(2,1,1); plt.imshow(PlotImage(Wk[i]))
273+
plt.subplot(2,1,2); plt.imshow(PlotImage(Ik[i])); plt.show()
274+
print(i)
275+
276+
# Step 2
277+
print("Step 2")
278+
W = np.median(Wk, axis=0)
279+
280+
# Step 3
281+
print("Step 3")
282+
W_diag = diags(W.reshape(-1))
283+
284+
for i in range(K):
285+
alphaWk = alpha*Wk[i]
286+
alphaWk_gx = cv2.Sobel(alphaWk, cv2.CV_64F, 1, 0, 3)
287+
alphaWk_gy = cv2.Sobel(alphaWk, cv2.CV_64F, 0, 1, 3)
288+
phi_f = diags( Func_Phi_deriv( ((Wm_gx - alphaWk_gx)**2 + (Wm_gy - alphaWk_gy)**2 ).reshape(-1)) )
289+
290+
phi_k = diags(Func_Phi_deriv(((alpha*Wk[i] + (1-alpha)*Ik[i] - J[i])**2)*(W-Ik[i])).reshape(-1))
291+
phi_alpha = diags(Func_Phi_deriv(alpha_gx**2 + alpha_gy**2).reshape(-1))
292+
L_alpha = sobelx.T.dot(phi_alpha.dot(sobelx)) + sobely.T.dot(phi_alpha.dot(sobely))
293+
294+
L_f = sobelx.T.dot(phi_f).dot(sobelx) + sobely.dot(phi_f).dot(sobely)
295+
A_tilde_f = W_diag.dot(L_f).dot(W_diag)
296+
297+
# Ax = b, setting up A
298+
if i==0:
299+
A1 = phi_k + lambda_a*L_alpha + beta*A_tilde_f
300+
b1 = phi_k.dot((J[i]-Ik[i]).reshape(-1)) + beta*W_diag.dot(L_f).dot(W_m.reshape(-1))
301+
else:
302+
A1 += (phi_k + lambda_a*L_alpha + beta*A_tilde_f)
303+
b1 += (phi_k.dot((J[i]-Ik[i]).reshape(-1)) + beta*W_diag.dot(L_f).dot(W_m.reshape(-1)))
304+
305+
alpha = linalg.spsolve(A1, b1).reshape(m,n,p)
306+
307+
return (Wk, Ik, W, alpha)

0 commit comments

Comments
 (0)