1
- import nibabel as nib
2
1
import matplotlib
3
- matplotlib .use ('agg' )
2
+ import nibabel as nib
3
+
4
4
import matplotlib .pyplot as plt
5
5
import numpy as np
6
- from nipype .utils .filemanip import fname_presuffix
7
6
import os .path as op
8
7
from dipy .segment .mask import median_otsu
9
8
from io import BytesIO
10
9
from nipype .utils .filemanip import save_json
11
10
import base64
12
11
12
+ matplotlib .use ('agg' )
13
+
14
+
13
15
def reorient_array (data , aff ):
14
16
# rearrange the matrix to RAS orientation
15
17
orientation = nib .orientations .io_orientation (aff )
16
18
data_RAS = nib .orientations .apply_orientation (data , orientation )
17
19
# In RAS
18
- return nib .orientations .apply_orientation (data_RAS ,
19
- nib .orientations .axcodes2ornt ("IPL" ))
20
+ return nib .orientations .apply_orientation (
21
+ data_RAS ,
22
+ nib .orientations .axcodes2ornt ("IPL" )
23
+ )
24
+
20
25
21
26
def mplfig (data , outfile = None , as_bytes = False ):
22
27
fig = plt .figure (frameon = False , dpi = data .shape [0 ])
23
28
fig .set_size_inches (float (data .shape [1 ])/ data .shape [0 ], 1 )
24
29
ax = plt .Axes (fig , [0. , 0. , 1. , 1. ])
25
30
ax .set_axis_off ()
26
31
fig .add_axes (ax )
27
- ax .imshow (data , aspect = 1 , cmap = plt .cm .Greys_r ) # used to be aspect="normal"
32
+ ax .imshow (data , aspect = 1 , cmap = plt .cm .Greys_r ) # previous aspect="normal"
28
33
if outfile :
29
34
fig .savefig (outfile , dpi = data .shape [0 ], transparent = True )
30
35
plt .close ()
@@ -43,7 +48,7 @@ def mplfigcontour(data, outfile=None, as_bytes=False):
43
48
ax = plt .Axes (fig , [0. , 0. , 1. , 1. ])
44
49
ax .set_axis_off ()
45
50
fig .add_axes (ax )
46
-
51
+
47
52
bg = np .zeros (data .shape )
48
53
bg [:] = np .nan
49
54
ax .imshow (bg , aspect = 1 , cmap = plt .cm .Greys_r ) # used to be aspect="normal"
@@ -59,23 +64,41 @@ def mplfigcontour(data, outfile=None, as_bytes=False):
59
64
base64_jpgData = base64 .b64encode (IObytes .read ())
60
65
return base64_jpgData .decode ("ascii" )
61
66
67
+
62
68
def load_and_reorient (filename ):
63
69
img = nib .load (filename )
64
70
data , aff = img .get_data (), img .affine
65
71
data = reorient_array (data , aff )
66
72
return data
67
73
74
+
68
75
def reshape3D (data , n = 256 ):
69
- return np .pad (data , (((n - data .shape [0 ])// 2 , ((n - data .shape [0 ]) + (data .shape [0 ]% 2 > 0 ))// 2 ),
70
- ((n - data .shape [1 ])// 2 , ((n - data .shape [1 ]) + (data .shape [1 ]% 2 > 0 ))// 2 ),
71
- (0 ,0 )),
72
- "constant" , constant_values = (0 ,0 ))
76
+ return np .pad (data , (
77
+ (
78
+ (n - data .shape [0 ]) // 2 ,
79
+ ((n - data .shape [0 ]) + (data .shape [0 ] % 2 > 0 )) // 2
80
+ ),
81
+ (
82
+ (n - data .shape [1 ]) // 2 ,
83
+ ((n - data .shape [1 ]) + (data .shape [1 ] % 2 > 0 )) // 2
84
+ ),
85
+ (0 , 0 )
86
+ ), "constant" , constant_values = (0 , 0 ))
87
+
73
88
74
89
def reshape4D (data , n = 256 ):
75
- return np .pad (data , (((n - data .shape [0 ])// 2 , ((n - data .shape [0 ]) + (data .shape [0 ]% 2 > 0 ))// 2 ),
76
- ((n - data .shape [1 ])// 2 , ((n - data .shape [1 ]) + (data .shape [1 ]% 2 > 0 ))// 2 ),
77
- (0 ,0 ), (0 ,0 )),
78
- "constant" , constant_values = (0 ,0 ))
90
+ return np .pad (data , (
91
+ (
92
+ (n - data .shape [0 ]) // 2 ,
93
+ ((n - data .shape [0 ]) + (data .shape [0 ] % 2 > 0 )) // 2
94
+ ),
95
+ (
96
+ (n - data .shape [1 ]) // 2 ,
97
+ ((n - data .shape [1 ]) + (data .shape [1 ] % 2 > 0 )) // 2
98
+ ),
99
+ (0 , 0 ), (0 , 0 )
100
+ ), "constant" , constant_values = (0 , 0 ))
101
+
79
102
80
103
def get_middle_slices (data , slice_direction ):
81
104
slicer = {"ax" : 0 , "cor" : 1 , "sag" : 2 }
@@ -84,13 +107,14 @@ def get_middle_slices(data, slice_direction):
84
107
slice_num = int (num_slices / 2 )
85
108
all_data_slicer [slicer [slice_direction ]] = slice_num
86
109
tile = data [tuple (all_data_slicer )]
87
-
110
+
88
111
# make it a square
89
112
N = max (tile .shape [:2 ])
90
113
tile = reshape3D (tile , N )
91
-
114
+
92
115
return tile
93
116
117
+
94
118
def nearest_square (limit ):
95
119
answer = 0
96
120
while (answer + 1 )** 2 < limit :
@@ -100,7 +124,8 @@ def nearest_square(limit):
100
124
else :
101
125
return answer + 1
102
126
103
- def create_sprite_from_tiles (tile , out_file = None , as_bytes = False ):
127
+
128
+ def create_sprite_from_tiles (tile , out_file = None , as_bytes = False ):
104
129
num_slices = tile .shape [- 1 ]
105
130
N = nearest_square (num_slices )
106
131
M = int (np .ceil (num_slices / N ))
@@ -109,24 +134,24 @@ def create_sprite_from_tiles(tile, out_file = None, as_bytes=False):
109
134
110
135
if len (tile .shape ) == 3 :
111
136
mosaic = np .zeros ((N * tile .shape [0 ], M * tile .shape [0 ]))
112
- else :
137
+ else :
113
138
mosaic = np .zeros ((N * tile .shape [0 ], M * tile .shape [0 ], tile .shape [- 2 ]))
114
-
139
+
115
140
mosaic [:] = np .nan
116
141
helper = np .arange (N * M ).reshape ((N , M ))
117
-
142
+
118
143
for t in range (num_slices ):
119
144
x , y = np .nonzero (helper == t )
120
145
xmin = x [0 ] * pix
121
146
xmax = (x [0 ] + 1 ) * pix
122
147
ymin = y [0 ] * pix
123
148
ymax = (y [0 ] + 1 ) * pix
124
-
149
+
125
150
if len (tile .shape ) == 3 :
126
- mosaic [xmin :xmax , ymin :ymax ] = tile [:,:, t ]
151
+ mosaic [xmin :xmax , ymin :ymax ] = tile [:, :, t ]
127
152
else :
128
- mosaic [xmin :xmax , ymin :ymax , :] = tile [:,:,:, t ]
129
-
153
+ mosaic [xmin :xmax , ymin :ymax , :] = tile [:, :, :, t ]
154
+
130
155
if as_bytes :
131
156
img = mplfig (mosaic , out_file , as_bytes = as_bytes )
132
157
return dict (img = img , N = N , M = M , pix = pix , num_slices = num_slices )
@@ -138,31 +163,31 @@ def create_sprite_from_tiles(tile, out_file = None, as_bytes=False):
138
163
139
164
140
165
def createSprite4D (dwi_file ):
141
-
166
+
142
167
# initialize output dict
143
168
output = []
144
169
145
170
# load the file
146
- dwi = load_and_reorient (dwi_file )[:,:,:, 1 :]
171
+ dwi = load_and_reorient (dwi_file )[:, :, :, 1 :]
147
172
148
173
# create tiles from center slice on each orientation
149
174
for orient in ['sag' , 'ax' , 'cor' ]:
150
175
tile = get_middle_slices (dwi , orient )
151
176
152
- # create sprite images for each
177
+ # create sprite images for each
153
178
results = create_sprite_from_tiles (tile , as_bytes = True )
154
179
results ['img_type' ] = '4dsprite'
155
180
results ['orientation' ] = orient
156
181
output .append (results )
157
182
158
183
return output
159
184
185
+
160
186
def createB0_ColorFA_Mask_Sprites (b0_file , colorFA_file , mask_file ):
161
187
colorfa = load_and_reorient (colorFA_file )
162
- b0 = load_and_reorient (b0_file )[:,:,:, 0 ]
188
+ b0 = load_and_reorient (b0_file )[:, :, :, 0 ]
163
189
anat_mask = load_and_reorient (mask_file )
164
190
165
-
166
191
N = max (* b0 .shape [:2 ])
167
192
168
193
# make a b0 sprite
@@ -173,7 +198,7 @@ def createB0_ColorFA_Mask_Sprites(b0_file, colorFA_file, mask_file):
173
198
174
199
# make a colorFA sprite, masked by b0
175
200
Q = reshape4D (colorfa , N )
176
- Q [mask == False ] = np .nan
201
+ Q [np . logical_not ( mask ) ] = np .nan
177
202
Q = np .moveaxis (Q , - 2 , - 1 )
178
203
outcolorFA = create_sprite_from_tiles (Q , as_bytes = True )
179
204
outcolorFA ['img_type' ] = 'brainsprite'
@@ -186,23 +211,23 @@ def createB0_ColorFA_Mask_Sprites(b0_file, colorFA_file, mask_file):
186
211
return outb0 , outcolorFA , outmask
187
212
188
213
189
- def create_report_json (dwi_corrected_file , eddy_rms , eddy_report ,
190
- color_fa_file , anat_mask_file ,
214
+ def create_report_json (dwi_corrected_file , eddy_rms , eddy_report ,
215
+ color_fa_file , anat_mask_file ,
191
216
outpath = op .abspath ('./report.json' )):
192
217
193
218
report = {}
194
219
report ['dwi_corrected' ] = createSprite4D (dwi_corrected_file )
195
220
196
- b0 , colorFA , mask = createB0_ColorFA_Mask_Sprites (dwi_corrected_file ,
197
- color_fa_file ,
198
- anat_mask_file )
221
+ b0 , colorFA , mask = createB0_ColorFA_Mask_Sprites (dwi_corrected_file ,
222
+ color_fa_file ,
223
+ anat_mask_file )
199
224
report ['b0' ] = b0
200
225
report ['colorFA' ] = colorFA
201
226
report ['anat_mask' ] = mask
202
227
203
228
with open (eddy_report , 'r' ) as f :
204
229
report ['eddy_report' ] = f .readlines ()
205
-
230
+
206
231
report ['eddy_params' ] = np .genfromtxt (eddy_rms ).tolist ()
207
232
208
233
save_json (outpath , report )
0 commit comments