Commit a296b8336c3250b59c0d8847ff948276ef158b8c
1 parent
9127f47e
added the muve alignment Python script
Showing
2 changed files
with
161 additions
and
324 deletions
Show diff stats
python/coupledwave.py deleted
1 | -# -*- coding: utf-8 -*- | ||
2 | -""" | ||
3 | -Created on Thu Sep 6 22:14:36 2018 | ||
4 | - | ||
5 | -@author: david | ||
6 | -""" | ||
7 | - | ||
8 | -import numpy as np | ||
9 | -import matplotlib.pyplot as plt | ||
10 | - | ||
11 | -#evaluate a plane wave for all points in R = [Rx, Ry, Rz] | ||
12 | -# E0 [Ex, Ey, Ez] is the electric field vector | ||
13 | -# k is the k vector | ||
14 | -# n is the refractive index of the material | ||
15 | -# R is a list of coordinates in x, y, and z | ||
16 | -def planewave2field(E0, k, n, R): | ||
17 | - knr = n * (k[0] * R[0] + k[1] * R[1] + k[2] + R[2]) | ||
18 | - exp_2pknr = np.exp(1j * 2 * np.pi * knr) | ||
19 | - Ex = E0[0] * exp_2pknr | ||
20 | - Ey = E0[1] * exp_2pknr | ||
21 | - Ez = E0[2] * exp_2pknr | ||
22 | - | ||
23 | - return [Ex, Ey, Ez] | ||
24 | - | ||
25 | -def orthogonalize(E, k): | ||
26 | - s = np.cross(E, k) | ||
27 | - return np.cross(k, s) | ||
28 | - | ||
29 | -class layersample: | ||
30 | - | ||
31 | - #generate a layered sample based on a list of layer refractive indices | ||
32 | - # layer_ri is a list of complex refractive indices for each layer | ||
33 | - # z is the list of boundary positions along z | ||
34 | - def __init__(self, layer_ri, z): | ||
35 | - self.n = np.array(layer_ri).astype(np.complex128) | ||
36 | - self.z = np.array(z) | ||
37 | - | ||
38 | - #calculate the index of the field component associated with a layer | ||
39 | - # l is the layer index [0, L) | ||
40 | - # c is the component (x=0, y=1, z=2) | ||
41 | - # d is the direction (0 = transmission, 1 = reflection) | ||
42 | - def idx(self, l, c, d): | ||
43 | - i = l * 6 + d * 3 + c - 3 | ||
44 | - print(i) | ||
45 | - return i | ||
46 | - | ||
47 | - #create a matrix for a single plane wave specified by k and E | ||
48 | - def solve(self, k, E): | ||
49 | - | ||
50 | - #calculate the wavenumber | ||
51 | - kn = np.linalg.norm(k) | ||
52 | - | ||
53 | - #s is the plane wave direction scaled by the refractive index | ||
54 | - s = k / kn * self.n[0] | ||
55 | - | ||
56 | - #allocate space for the matrix | ||
57 | - L = len(self.n) | ||
58 | - M = np.zeros((6*(L-1), 6*(L-1)), dtype=np.complex128) | ||
59 | - | ||
60 | - #allocate space for the RHS vector | ||
61 | - b = np.zeros(6*(L-1), dtype=np.complex128) | ||
62 | - | ||
63 | - #initialize a counter for the equation number | ||
64 | - ei = 0 | ||
65 | - | ||
66 | - #calculate the sz component for each layer | ||
67 | - self.sz = np.zeros(L, dtype=np.complex128) | ||
68 | - for l in range(L): | ||
69 | - self.sz[l] = np.sqrt(self.n[l]**2 - s[0]**2 - s[1]**2) | ||
70 | - | ||
71 | - #set constraints based on Gauss' law | ||
72 | - for l in range(0, L): | ||
73 | - #sz = np.sqrt(self.n[l]**2 - s[0]**2 - s[1]**2) | ||
74 | - | ||
75 | - #set the upward components for each layer | ||
76 | - # note that layer L-1 does not have a downward component | ||
77 | - # David I, Equation 7 | ||
78 | - if l != L-1: | ||
79 | - M[ei, self.idx(l, 0, 1)] = s[0] | ||
80 | - M[ei, self.idx(l, 1, 1)] = s[1] | ||
81 | - M[ei, self.idx(l, 2, 1)] = -self.sz[l] | ||
82 | - ei = ei+1 | ||
83 | - | ||
84 | - #set the downward components for each layer | ||
85 | - # note that layer 0 does not have a downward component | ||
86 | - # Davis I, Equation 6 | ||
87 | - if l != 0: | ||
88 | - M[ei, self.idx(l, 0, 0)] = s[0] | ||
89 | - M[ei, self.idx(l, 1, 0)] = s[1] | ||
90 | - M[ei, self.idx(l, 2, 0)] = self.sz[l] | ||
91 | - ei = ei+1 | ||
92 | - | ||
93 | - #enforce a continuous field across boundaries | ||
94 | - for l in range(1, L): | ||
95 | - sz0 = self.sz[l-1] | ||
96 | - sz1 = self.sz[l] | ||
97 | - A = np.exp(1j * kn * sz0 * (self.z[l] - self.z[l-1])) | ||
98 | - if l < L - 1: | ||
99 | - B = np.exp(-1j * kn * sz1 * (self.z[l] - self.z[l+1])) | ||
100 | - | ||
101 | - | ||
102 | - #if this is the second layer, use the simplified equations that account for the incident field | ||
103 | - if l == 1: | ||
104 | - M[ei, self.idx(0, 0, 1)] = 1 | ||
105 | - M[ei, self.idx(1, 0, 0)] = -1 | ||
106 | - if L > 2: | ||
107 | - M[ei, self.idx(1, 0, 1)] = -B | ||
108 | - | ||
109 | - b[ei] = -A * E[0] | ||
110 | - ei = ei + 1 | ||
111 | - | ||
112 | - M[ei, self.idx(0, 1, 1)] = 1 | ||
113 | - M[ei, self.idx(1, 1, 0)] = -1 | ||
114 | - if L > 2: | ||
115 | - M[ei, self.idx(1, 1, 1)] = -B | ||
116 | - b[ei] = -A * E[1] | ||
117 | - ei = ei + 1 | ||
118 | - | ||
119 | - M[ei, self.idx(0, 2, 1)] = s[1] | ||
120 | - M[ei, self.idx(0, 1, 1)] = sz0 | ||
121 | - M[ei, self.idx(1, 2, 0)] = -s[1] | ||
122 | - M[ei, self.idx(1, 1, 0)] = sz1 | ||
123 | - if L > 2: | ||
124 | - M[ei, self.idx(1, 2, 1)] = -B*s[1] | ||
125 | - M[ei, self.idx(1, 1, 1)] = -B*sz1 | ||
126 | - b[ei] = A * sz0 * E[1] - A * s[1]*E[2] | ||
127 | - ei = ei + 1 | ||
128 | - | ||
129 | - M[ei, self.idx(0, 0, 1)] = -sz0 | ||
130 | - M[ei, self.idx(0, 2, 1)] = -s[0] | ||
131 | - M[ei, self.idx(1, 0, 0)] = -sz1 | ||
132 | - M[ei, self.idx(1, 2, 0)] = s[0] | ||
133 | - if L > 2: | ||
134 | - M[ei, self.idx(1, 0, 1)] = B*sz1 | ||
135 | - M[ei, self.idx(1, 2, 1)] = B*s[0] | ||
136 | - b[ei] = A * s[0] * E[2] - A * sz0 * E[0] | ||
137 | - ei = ei + 1 | ||
138 | - | ||
139 | - #if this is the last layer, use the simplified equations that exclude reflections from the last layer | ||
140 | - elif l == L-1: | ||
141 | - M[ei, self.idx(l-1, 0, 0)] = A | ||
142 | - M[ei, self.idx(l-1, 0, 1)] = 1 | ||
143 | - M[ei, self.idx(l, 0, 0)] = -1 | ||
144 | - ei = ei + 1 | ||
145 | - | ||
146 | - M[ei, self.idx(l-1, 1, 0)] = A | ||
147 | - M[ei, self.idx(l-1, 1, 1)] = 1 | ||
148 | - M[ei, self.idx(l, 1, 0)] = -1 | ||
149 | - ei = ei + 1 | ||
150 | - | ||
151 | - M[ei, self.idx(l-1, 2, 0)] = A*s[1] | ||
152 | - M[ei, self.idx(l-1, 1, 0)] = -A*sz0 | ||
153 | - M[ei, self.idx(l-1, 2, 1)] = s[1] | ||
154 | - M[ei, self.idx(l-1, 1, 1)] = sz0 | ||
155 | - M[ei, self.idx(l, 2, 0)] = -s[1] | ||
156 | - M[ei, self.idx(l, 1, 0)] = sz1 | ||
157 | - ei = ei + 1 | ||
158 | - | ||
159 | - M[ei, self.idx(l-1, 0, 0)] = A*sz0 | ||
160 | - M[ei, self.idx(l-1, 2, 0)] = -A*s[0] | ||
161 | - M[ei, self.idx(l-1, 0, 1)] = -sz0 | ||
162 | - M[ei, self.idx(l-1, 2, 1)] = -s[0] | ||
163 | - M[ei, self.idx(l, 0, 0)] = -sz1 | ||
164 | - M[ei, self.idx(l, 2, 0)] = s[0] | ||
165 | - ei = ei + 1 | ||
166 | - #otherwise use the full set of boundary conditions | ||
167 | - else: | ||
168 | - M[ei, self.idx(l-1, 0, 0)] = A | ||
169 | - M[ei, self.idx(l-1, 0, 1)] = 1 | ||
170 | - M[ei, self.idx(l, 0, 0)] = -1 | ||
171 | - M[ei, self.idx(l, 0, 1)] = -B | ||
172 | - ei = ei + 1 | ||
173 | - | ||
174 | - M[ei, self.idx(l-1, 1, 0)] = A | ||
175 | - M[ei, self.idx(l-1, 1, 1)] = 1 | ||
176 | - M[ei, self.idx(l, 1, 0)] = -1 | ||
177 | - M[ei, self.idx(l, 1, 1)] = -B | ||
178 | - ei = ei + 1 | ||
179 | - | ||
180 | - M[ei, self.idx(l-1, 2, 0)] = A*s[1] | ||
181 | - M[ei, self.idx(l-1, 1, 0)] = -A*sz0 | ||
182 | - M[ei, self.idx(l-1, 2, 1)] = s[1] | ||
183 | - M[ei, self.idx(l-1, 1, 1)] = sz0 | ||
184 | - M[ei, self.idx(l, 2, 0)] = -s[1] | ||
185 | - M[ei, self.idx(l, 1, 0)] = sz1 | ||
186 | - M[ei, self.idx(l, 2, 1)] = -B*s[1] | ||
187 | - M[ei, self.idx(l, 1, 1)] = -B*sz1 | ||
188 | - ei = ei + 1 | ||
189 | - | ||
190 | - M[ei, self.idx(l-1, 0, 0)] = A*sz0 | ||
191 | - M[ei, self.idx(l-1, 2, 0)] = -A*s[0] | ||
192 | - M[ei, self.idx(l-1, 0, 1)] = -sz0 | ||
193 | - M[ei, self.idx(l-1, 2, 1)] = -s[0] | ||
194 | - M[ei, self.idx(l, 0, 0)] = -sz1 | ||
195 | - M[ei, self.idx(l, 2, 0)] = s[0] | ||
196 | - M[ei, self.idx(l, 0, 1)] = B*sz1 | ||
197 | - M[ei, self.idx(l, 2, 1)] = B*s[0] | ||
198 | - ei = ei + 1 | ||
199 | - | ||
200 | - #store the matrix and RHS vector (for debugging) | ||
201 | - self.M = M | ||
202 | - self.b = b | ||
203 | - | ||
204 | - #evaluate the linear system | ||
205 | - P = np.linalg.solve(M, b) | ||
206 | - | ||
207 | - #save the results (also for debugging) | ||
208 | - self.P = P | ||
209 | - | ||
210 | - #store the coefficients for each layer | ||
211 | - self.Ptrans = [] | ||
212 | - self.Prefl = [] | ||
213 | - for l in range(L): | ||
214 | - if l == 0: | ||
215 | - self.Ptrans.append((E[0], E[1], E[2])) | ||
216 | - else: | ||
217 | - px = P[self.idx(l, 0, 0)] | ||
218 | - py = P[self.idx(l, 1, 0)] | ||
219 | - pz = P[self.idx(l, 2, 0)] | ||
220 | - self.Ptrans.append((px, py, pz)) | ||
221 | - | ||
222 | - if l == L-1: | ||
223 | - self.Prefl.append((0, 0, 0)) | ||
224 | - else: | ||
225 | - px = P[self.idx(l, 0, 1)] | ||
226 | - py = P[self.idx(l, 1, 1)] | ||
227 | - pz = P[self.idx(l, 2, 1)] | ||
228 | - self.Prefl.append((px, py, pz)) | ||
229 | - | ||
230 | - #this converts the coefficients into a NumPy array for convenience later on | ||
231 | - self.Ptrans = np.array(self.Ptrans) | ||
232 | - self.Prefl = np.array(self.Prefl) | ||
233 | - | ||
234 | - #store values required for evaluation | ||
235 | - #store k | ||
236 | - self.k = kn | ||
237 | - | ||
238 | - #store sx and sy | ||
239 | - self.s = np.array([s[0], s[1]]) | ||
240 | - | ||
241 | - self.solved = True | ||
242 | - | ||
243 | - #evaluate a solved homogeneous substrate | ||
244 | - def evaluate(self, X, Y, Z): | ||
245 | - | ||
246 | - if not self.solved: | ||
247 | - print("ERROR: the layered substrate hasn't been solved") | ||
248 | - return | ||
249 | - | ||
250 | - #this code is a bit cumbersome and could probably be optimized | ||
251 | - # Basically, it vectorizes everything by creating an image | ||
252 | - # such that the value at each pixel is the corresponding layer | ||
253 | - # that the pixel resides in. That index is then used to calculate | ||
254 | - # the field within the layer | ||
255 | - | ||
256 | - #allocate space for layer indices | ||
257 | - LI = np.zeros(Z.shape, dtype=np.int) | ||
258 | - | ||
259 | - #find the layer index for each sample point | ||
260 | - L = len(self.z) | ||
261 | - LI[Z < self.z[0]] = 0 | ||
262 | - for l in range(L-1): | ||
263 | - idx = np.logical_and(Z > self.z[l], Z <= self.z[l+1]) | ||
264 | - LI[idx] = l | ||
265 | - LI[Z > self.z[-1]] = L - 1 | ||
266 | - | ||
267 | - #calculate the appropriate phase shift for the wave transmitted through the layer | ||
268 | - Ph_t = np.exp(1j * self.k * self.sz[LI] * (Z - self.z[LI])) | ||
269 | - | ||
270 | - #calculate the appropriate phase shift for the wave reflected off of the layer boundary | ||
271 | - LIp = LI + 1 | ||
272 | - LIp[LIp >= L] = 0 | ||
273 | - Ph_r = np.exp(-1j * self.k * self.sz[LI] * (Z - self.z[LIp])) | ||
274 | - Ph_r[LI >= L-1] = 0 | ||
275 | - | ||
276 | - #calculate the phase shift based on the X and Y positions | ||
277 | - Ph_xy = np.exp(1j * self.k * (self.s[0] * X + self.s[1] * Y)) | ||
278 | - | ||
279 | - #apply the phase shifts | ||
280 | - Et = self.Ptrans[LI] * Ph_t[:, :, None] | ||
281 | - Er = self.Prefl[LI] * Ph_r[:, :, None] | ||
282 | - | ||
283 | - #add everything together coherently | ||
284 | - E = (Et + Er) * Ph_xy[:, :, None] | ||
285 | - | ||
286 | - #return the electric field | ||
287 | - return E | ||
288 | - | ||
289 | - | ||
290 | -#This sample code produces a field similar to Figure 2 in Davis et al., 2010 | ||
291 | -#set the material properties | ||
292 | -depths = [-50, -15, 15, 40] | ||
293 | -n = [1.0, 1.4+1j*0.05, 1.4, 1.0] | ||
294 | - | ||
295 | -#create a layered sample | ||
296 | -layers = layersample(n, depths) | ||
297 | - | ||
298 | -#set the input light parameters | ||
299 | -d = np.array([0.2, 0, 1]) | ||
300 | -d = d / np.linalg.norm(d) | ||
301 | -l = 5.0 | ||
302 | -k = 2 * np.pi / l * d | ||
303 | -E0 = [0, 1, 0] | ||
304 | -E0 = orthogonalize(E0, d) | ||
305 | - | ||
306 | -#solve for the substrate field | ||
307 | -layers.solve(k, E0) | ||
308 | - | ||
309 | -#set the simulation domain | ||
310 | -N = 512 | ||
311 | -M = 1024 | ||
312 | -D = [-50, 80] | ||
313 | - | ||
314 | -x = np.linspace(D[0], D[1], N) | ||
315 | -z = np.linspace(D[0], D[1], M) | ||
316 | -[X, Z] = np.meshgrid(x, z) | ||
317 | -Y = np.zeros(X.shape) | ||
318 | -E = layers.evaluate(X, Y, Z) | ||
319 | - | ||
320 | -Er = np.real(E) | ||
321 | -I = Er[..., 0] ** 2 + Er[..., 1] **2 + Er[..., 2] ** 2 | ||
322 | -plt.figure() | ||
323 | -plt.set_cmap("afmhot") | ||
324 | -plt.imshow(Er[..., 1]) |
1 | +# -*- coding: utf-8 -*- | ||
2 | +""" | ||
3 | +Created on Fri May 4 17:15:07 2018 | ||
4 | + | ||
5 | +@author: david | ||
6 | +""" | ||
7 | + | ||
8 | +import imagestack | ||
9 | +import numpy | ||
10 | +import matplotlib.pyplot as plt | ||
11 | +import cv2 | ||
12 | +import progressbar | ||
13 | +import scipy.ndimage | ||
14 | +import sys | ||
15 | + | ||
16 | + | ||
17 | +def press(event): | ||
18 | + global i | ||
19 | + global ax | ||
20 | + global fig | ||
21 | + if event.key == 'z': | ||
22 | + i = i - 1 | ||
23 | + if i < 0: | ||
24 | + i = 0 | ||
25 | + if event.key == 'x': | ||
26 | + i = i + 1 | ||
27 | + if i == S.shape[0]: | ||
28 | + i = S.shape[0] | ||
29 | + if event.key == "up": | ||
30 | + for n in range(i, S.shape[0]): | ||
31 | + warps[n][1, 2] = warps[n][1, 2] + 1 | ||
32 | + if event.key == "down": | ||
33 | + for n in range(i, S.shape[0]): | ||
34 | + warps[n][1, 2] = warps[n][1, 2] - 1 | ||
35 | + if event.key == "left": | ||
36 | + for n in range(i, S.shape[0]): | ||
37 | + warps[n][0, 2] = warps[n][0, 2] + 1 | ||
38 | + if event.key == "right": | ||
39 | + for n in range(i, S.shape[0]): | ||
40 | + warps[n][0, 2] = warps[n][0, 2] - 1 | ||
41 | + aligned = cv2.warpAffine(S[i, :, :, :], warps[i], (S.shape[2], S.shape[1]), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP); | ||
42 | + ax.cla() | ||
43 | + ax.imshow(aligned.astype(numpy.uint8)) | ||
44 | + ax.set_title('Slice ' + str(i)) | ||
45 | + fig.canvas.draw() | ||
46 | + sys.stdout.flush | ||
47 | + | ||
48 | +#apply the alignment adjustments to I based on the list of warp matrices in t | ||
49 | +def apply_alignment(I, t): | ||
50 | + A = numpy.zeros(I.shape, dtype=numpy.uint8) | ||
51 | + for i in range(0, I.shape[0]): | ||
52 | + A[i, :, :, :] = cv2.warpAffine(I[i, :, :, :], t[i], (I.shape[2], I.shape[1]), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP); | ||
53 | + | ||
54 | + return A | ||
55 | + | ||
56 | +#get the transform that aligns image B to image A | ||
57 | +def align(A, B, max_power=5): | ||
58 | + # Define the motion model | ||
59 | + warp_mode = cv2.MOTION_TRANSLATION | ||
60 | + | ||
61 | + # Specify the number of iterations. | ||
62 | + number_of_iterations = 5000; | ||
63 | + | ||
64 | + # Specify the threshold of the increment | ||
65 | + # in the correlation coefficient between two iterations | ||
66 | + termination_eps = 1e-10; | ||
67 | + | ||
68 | + # Define termination criteria | ||
69 | + criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations, termination_eps) | ||
70 | + | ||
71 | + #attempt to fit the image, increasing the blur as necessary | ||
72 | + i = 0 | ||
73 | + while i <= max_power: | ||
74 | + #blur the image used for fitting | ||
75 | + im1_blur = scipy.ndimage.filters.gaussian_filter(A, (2 ** i, 2 ** i), mode='constant') | ||
76 | + im2_blur = scipy.ndimage.filters.gaussian_filter(B, (2 ** i, 2 ** i), mode='constant') | ||
77 | + | ||
78 | + # Run the ECC algorithm. The results are stored in warp_matrix. | ||
79 | + # Define 2x3 matrix and initialize the matrix to identity | ||
80 | + warp_matrix = numpy.eye(2, 3, dtype=numpy.float32) | ||
81 | + try: | ||
82 | + (cc, warp_matrix) = cv2.findTransformECC (im1_blur,im2_blur,warp_matrix, warp_mode, criteria) | ||
83 | + except: | ||
84 | + #print("Error aligning at p = " + str(i)) | ||
85 | + i = i + 1 | ||
86 | + else: | ||
87 | + #print("Successful alignment at p = " + str(i)) | ||
88 | + break | ||
89 | + #enforce the fact that the x-axis is already aligned | ||
90 | + #warp_matrix[0, 2] = 0 | ||
91 | + return warp_matrix | ||
92 | + | ||
93 | + #if i > 0: | ||
94 | + # (cc, warp_matrix) = cv2.findTransformECC (A,B,warp_matrix, warp_mode, criteria) | ||
95 | + #warp_matrix[0, 2] = 0 | ||
96 | + # return warp_matrix | ||
97 | + | ||
98 | +if len(sys.argv) < 3: | ||
99 | + print("usage: muve-align input_mask output_directory") | ||
100 | + print("ex: muve-align *.bmp ./aligned") | ||
101 | + return | ||
102 | + | ||
103 | +fmask = sys.argv[1] | ||
104 | +out_dir = sys.argv[2] | ||
105 | + | ||
106 | +if not os.path.isdir(out_dir): | ||
107 | + os.mkdir(out_dir) | ||
108 | + | ||
109 | +#read the image stack for alignment | ||
110 | +print("Loading image stack...") | ||
111 | +S = imagestack.load(fmask, dtype=numpy.float32) | ||
112 | +#convert to grayscale | ||
113 | +G = imagestack.rgb2gray(S) | ||
114 | + | ||
115 | +# Define the motion model | ||
116 | +warp_mode = cv2.MOTION_TRANSLATION | ||
117 | + | ||
118 | +# Define the motion model | ||
119 | +warp_mode = cv2.MOTION_TRANSLATION | ||
120 | + | ||
121 | +# Specify the number of iterations. | ||
122 | +number_of_iterations = 5000 | ||
123 | + | ||
124 | +# Specify the threshold of the increment | ||
125 | +# in the correlation coefficient between two iterations | ||
126 | +termination_eps = 1e-10 | ||
127 | + | ||
128 | +# Define termination criteria | ||
129 | +criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, number_of_iterations, termination_eps) | ||
130 | + | ||
131 | +print("\n\nCalculating alignment transformations...") | ||
132 | +bar = progressbar.ProgressBar(max_value=G.shape[0]) | ||
133 | +#for each image in the stack, calculate a transformation matrix to align it to the previous image | ||
134 | +warps = [numpy.eye(2, 3, dtype=numpy.float32)] | ||
135 | +for i in range(1, G.shape[0]): | ||
136 | + warps.append(align(G[i-1, :, :], G[i, :, :])) | ||
137 | + bar.update(i+1) | ||
138 | + | ||
139 | + | ||
140 | +print("\n\nApplying alignment transformation...") | ||
141 | +# Define 2x3 matrix and initialize the matrix to identity | ||
142 | +for i in range(1, G.shape[0]): | ||
143 | + warps[i][0, 2] = warps[i][0, 2] + warps[i-1][0, 2] | ||
144 | + warps[i][1, 2] = warps[i][1, 2] + warps[i-1][1, 2] | ||
145 | + | ||
146 | + | ||
147 | + | ||
148 | +i = 0 | ||
149 | +aligned = cv2.warpAffine(S[i, :, :, :], warps[i], (S.shape[2], S.shape[1]), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP) | ||
150 | + | ||
151 | +fig, ax = plt.subplots() | ||
152 | + | ||
153 | +fig.canvas.mpl_connect('key_press_event', press) | ||
154 | + | ||
155 | +ax.imshow(aligned.astype(numpy.uint8)) | ||
156 | +ax.set_title('Slice ' + str(i)) | ||
157 | +ax.set_xlabel("Press 'z' and 'x' to change slices and arrow keys to align") | ||
158 | +plt.show() | ||
159 | + | ||
160 | +I = apply_alignment(S, warps) | ||
161 | +imagestack.save(I, out_dir + "/aligned_", ".bmp") | ||
0 | \ No newline at end of file | 162 | \ No newline at end of file |