Commit a69fee9dc89a6dab5b4bf4a28b23d945e8182504
1 parent
08ada8c2
added python script for 3D phantom creation for 2D images
Showing
2 changed files
with
78 additions
and
5 deletions
Show diff stats
1 | +# -*- coding: utf-8 -*- | |
2 | +""" | |
3 | +Created on Thu May 18 15:56:20 2017 | |
4 | + | |
5 | +@author: david | |
6 | +""" | |
7 | + | |
8 | +import numpy as np | |
9 | +import scipy as sp | |
10 | +import scipy.misc | |
11 | +import scipy.ndimage | |
12 | +import matplotlib.pyplot as plt | |
13 | +import os | |
14 | + | |
15 | +#calculate a 3D image from a 2D binary mask | |
16 | +def binary(infile, sigma=2): | |
17 | + | |
18 | + I = sp.misc.imread(infile).astype(np.bool) | |
19 | + | |
20 | + #if the image has more than one channel, just keep the first one | |
21 | + if(I.ndim == 3): | |
22 | + I = I[:, :, 0] | |
23 | + | |
24 | + L = [] | |
25 | + while np.count_nonzero(I) != 0: | |
26 | + L.append(I) | |
27 | + I = sp.ndimage.binary_erosion(I) | |
28 | + | |
29 | + #create a 3D image representing the new stack | |
30 | + S = np.zeros( (I.shape[0], I.shape[1], len(L) * 2 - 1) ) | |
31 | + | |
32 | + #for each image in the list | |
33 | + for i in range(0, len(L)): | |
34 | + if(i == 0): | |
35 | + S[:, :, len(L) - 1] = L[0] | |
36 | + else: | |
37 | + S[:, :, len(L) - 1 + i] = L[i] | |
38 | + S[:, :, len(L) - 1 - i] = L[i] | |
39 | + | |
40 | + S = sp.ndimage.filters.gaussian_filter(S, sigma) | |
41 | + return S | |
42 | + | |
43 | +#generate a 3D image stack from a 2D binary mask | |
44 | +def binary_stack(infile, outdir, sigma=2): | |
45 | + outfile_base = os.path.basename(infile) | |
46 | + outfile_prefix, outfile_ext = os.path.splitext(outfile_base) | |
47 | + | |
48 | + S = binary(infile, sigma) | |
49 | + | |
50 | + zcount = len(str(S.shape[2])) | |
51 | + for f in range(0, S.shape[2]): | |
52 | + fname = outdir + "/" + outfile_prefix + str(f).zfill(zcount) + outfile_ext | |
53 | + | |
54 | + sp.misc.imsave(fname, S[:, :, f]) | |
55 | + | |
56 | + | |
57 | + | |
58 | + | ... | ... |
python/structen.py
... | ... | @@ -17,9 +17,7 @@ def st2(I, s=1, dtype=np.float32): |
17 | 17 | |
18 | 18 | #calculate the gradient |
19 | 19 | dI = np.gradient(I.astype(dtype)) |
20 | - | |
21 | - #print(dI[1][20, 164]) | |
22 | - | |
20 | + | |
23 | 21 | #calculate the dimensions of the tensor field |
24 | 22 | field_dims = [dI[0].shape[0], dI[0].shape[1], 3] |
25 | 23 | |
... | ... | @@ -33,6 +31,10 @@ def st2(I, s=1, dtype=np.float32): |
33 | 31 | Tg[:, :, ti] = dI[j] * dI[i] |
34 | 32 | ti = ti + 1 |
35 | 33 | |
34 | + #if the user does not want a blurred field | |
35 | + if(s == 0): | |
36 | + return Tg | |
37 | + | |
36 | 38 | #blur the tensor field |
37 | 39 | T = np.zeros(field_dims, dtype=dtype) |
38 | 40 | |
... | ... | @@ -125,7 +127,7 @@ def sym2mat(T): |
125 | 127 | |
126 | 128 | return R |
127 | 129 | |
128 | -def st2vec(S, vector=0): | |
130 | +def vec(S, vector=0): | |
129 | 131 | |
130 | 132 | if(S.ndim != 3): |
131 | 133 | print("ERROR: a 2D slice is expected") |
... | ... | @@ -238,7 +240,20 @@ def fa(S): |
238 | 240 | FA = np.sqrt(3./2.) * np.sqrt(fa_num) / np.sqrt(fa_den) |
239 | 241 | return FA |
240 | 242 | |
241 | -def st2amira(filename, T): | |
243 | +#calculate the specified eigenvalue for the tensor field | |
244 | +def eigenval(S, ev): | |
245 | + Sf = sym2mat(S) | |
246 | + | |
247 | + #calculate the eigenvectors and eigenvalues | |
248 | + l, v = np.linalg.eig(Sf) | |
249 | + | |
250 | + #store the sorted eigenvalues | |
251 | + ls = np.sort(l) | |
252 | + evals = ls[:, :, ev] | |
253 | + | |
254 | + return evals | |
255 | + | |
256 | +def amira(filename, T): | |
242 | 257 | #generates a tensor field that can be imported into Amira |
243 | 258 | |
244 | 259 | # 0 dx dx ----> 0 | ... | ... |