|
a |
|
b/tool/Code/utilities/conform.py |
|
|
1 |
# Copyright 2019 Population Health Sciences and Image Analysis, German Center for Neurodegenerative Diseases(DZNE) |
|
|
2 |
# |
|
|
3 |
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
4 |
# you may not use this file except in compliance with the License. |
|
|
5 |
# You may obtain a copy of the License at |
|
|
6 |
# |
|
|
7 |
# http://www.apache.org/licenses/LICENSE-2.0 |
|
|
8 |
# |
|
|
9 |
# Unless required by applicable law or agreed to in writing, software |
|
|
10 |
# distributed under the License is distributed on an "AS IS" BASIS, |
|
|
11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
12 |
# See the License for the specific language governing permissions and |
|
|
13 |
# limitations under the License. |
|
|
14 |
|
|
|
15 |
import numpy as np |
|
|
16 |
import nibabel as nib |
|
|
17 |
import scipy.ndimage |
|
|
18 |
import os |
|
|
19 |
|
|
|
20 |
|
|
|
21 |
def calculated_new_ornt(iornt,base_ornt): |
|
|
22 |
|
|
|
23 |
new_iornt=iornt[:] |
|
|
24 |
|
|
|
25 |
for axno, direction in np.asarray(base_ornt): |
|
|
26 |
idx=np.where(iornt[:,0] == axno) |
|
|
27 |
idirection=iornt[int(idx[0][0]),1] |
|
|
28 |
if direction == idirection: |
|
|
29 |
new_iornt[int(idx[0][0]), 1] = 1.0 |
|
|
30 |
else: |
|
|
31 |
new_iornt[int(idx[0][0]), 1] = -1.0 |
|
|
32 |
|
|
|
33 |
return new_iornt |
|
|
34 |
|
|
|
35 |
def check_orientation(img,base_ornt=np.array([[0,-1],[1,1],[2,1]])): |
|
|
36 |
|
|
|
37 |
iornt=nib.io_orientation(img.affine) |
|
|
38 |
|
|
|
39 |
if not np.array_equal(iornt,base_ornt): |
|
|
40 |
img = img.as_reoriented(calculated_new_ornt(iornt,base_ornt)) |
|
|
41 |
|
|
|
42 |
return img |
|
|
43 |
|
|
|
44 |
|
|
|
45 |
def resample(image, spacing, new_spacing=[1, 1, 1],order=1,prefilter=True): |
|
|
46 |
# Determine current pixel spacing |
|
|
47 |
|
|
|
48 |
resize_factor = spacing / new_spacing |
|
|
49 |
new_real_shape = image.shape * resize_factor |
|
|
50 |
new_shape = np.round(new_real_shape) |
|
|
51 |
real_resize_factor = new_shape / image.shape |
|
|
52 |
new_spacing = spacing / real_resize_factor |
|
|
53 |
|
|
|
54 |
image = scipy.ndimage.interpolation.zoom(image,real_resize_factor,order=order,prefilter=prefilter) |
|
|
55 |
|
|
|
56 |
return image, new_spacing |
|
|
57 |
|
|
|
58 |
|
|
|
59 |
def define_size(mov_dim,ref_dim): |
|
|
60 |
new_dim=np.zeros(len(mov_dim),dtype=np.int) |
|
|
61 |
borders=np.zeros((len(mov_dim),2),dtype=int) |
|
|
62 |
|
|
|
63 |
padd = [int(mov_dim[0] // 2), int(mov_dim[1] // 2), int(mov_dim[2] // 2)] |
|
|
64 |
|
|
|
65 |
for i in range(len(mov_dim)): |
|
|
66 |
new_dim[i]=int(max(2*mov_dim[i],2*ref_dim[i])) |
|
|
67 |
borders[i,0]= int(new_dim[i] // 2) -padd [i] |
|
|
68 |
borders[i,1]= borders[i,0] +mov_dim[i] |
|
|
69 |
|
|
|
70 |
return list(new_dim),borders |
|
|
71 |
|
|
|
72 |
def map_size(arr,base_shape,axial): |
|
|
73 |
|
|
|
74 |
if axial: |
|
|
75 |
base_shape[2]=arr.shape[2] |
|
|
76 |
|
|
|
77 |
print('Volume will be resize from %s to %s ' % (arr.shape, base_shape)) |
|
|
78 |
|
|
|
79 |
new_shape,borders=define_size(np.array(arr.shape),np.array(base_shape)) |
|
|
80 |
new_arr=np.zeros(new_shape) |
|
|
81 |
final_arr=np.zeros(base_shape) |
|
|
82 |
|
|
|
83 |
new_arr[borders[0,0]:borders[0,1],borders[1,0]:borders[1,1],borders[2,0]:borders[2,1]]= arr[:] |
|
|
84 |
|
|
|
85 |
middle_point = [int(new_arr.shape[0] // 2), int(new_arr.shape[1] // 2), int(new_arr.shape[2] // 2)] |
|
|
86 |
padd = [int(base_shape[0]/2), int(base_shape[1]/2), int(base_shape[2]/2)] |
|
|
87 |
|
|
|
88 |
low_border=np.array((np.array(middle_point)-np.array(padd)),dtype=int) |
|
|
89 |
high_border=np.array(np.array(low_border)+np.array(base_shape),dtype=int) |
|
|
90 |
|
|
|
91 |
final_arr[:,:,:]= new_arr[low_border[0]:high_border[0], |
|
|
92 |
low_border[1]:high_border[1], |
|
|
93 |
low_border[2]:high_border[2]] |
|
|
94 |
|
|
|
95 |
return final_arr |
|
|
96 |
|
|
|
97 |
|
|
|
98 |
def map_image(img_arr,base_zoom,izoom,order,axial): |
|
|
99 |
if axial: |
|
|
100 |
base_zoom[2] = izoom[2] |
|
|
101 |
|
|
|
102 |
print('Volume will be sample from %s to %s ' % (izoom, base_zoom)) |
|
|
103 |
resample_arr, izoom= resample(img_arr, spacing=np.array(izoom), |
|
|
104 |
new_spacing=np.array(base_zoom), order=order) |
|
|
105 |
|
|
|
106 |
resample_arr[resample_arr < 0] = 0 |
|
|
107 |
|
|
|
108 |
return resample_arr,izoom |
|
|
109 |
|
|
|
110 |
def conform(img,flags,order,save_path,mod,axial=False): |
|
|
111 |
""" |
|
|
112 |
Args: |
|
|
113 |
img: nibabel img: Loaded source image |
|
|
114 |
flags: dict : Dictionary containing the image size, spacing and orientation |
|
|
115 |
order: int : interpolation order (0=nearest,1=linear(default),2=quadratic,3=cubic) |
|
|
116 |
Returns: |
|
|
117 |
new_img: nibabel img : conformed nibabel image |
|
|
118 |
""" |
|
|
119 |
save=False |
|
|
120 |
# check orientation LAS |
|
|
121 |
img=check_orientation(img,base_ornt=flags['base_ornt']) |
|
|
122 |
|
|
|
123 |
img_arr=img.get_data() |
|
|
124 |
img_header = img.header |
|
|
125 |
|
|
|
126 |
# check voxel sizer |
|
|
127 |
i_zoom=img.header.get_zooms() |
|
|
128 |
|
|
|
129 |
#check the spacing idx for interpolation |
|
|
130 |
if axial: |
|
|
131 |
idx=2 |
|
|
132 |
else: |
|
|
133 |
idx=3 |
|
|
134 |
if not np.allclose(np.array(i_zoom)[:idx],np.array(flags['spacing'])[:idx],rtol=0.3): |
|
|
135 |
img_arr,i_zoom= map_image(img_arr,flags['spacing'],i_zoom,order,axial) |
|
|
136 |
save=True |
|
|
137 |
|
|
|
138 |
ishape = img_arr.shape |
|
|
139 |
|
|
|
140 |
# check dimensions |
|
|
141 |
if int(ishape[0]) != int(flags['imgSize'][0]) or int(ishape[1]) != int(flags['imgSize'][1]) or int(ishape[2]) != int(flags['imgSize'][2]): |
|
|
142 |
img_arr=map_size(img_arr,flags['imgSize'],axial) |
|
|
143 |
save = True |
|
|
144 |
|
|
|
145 |
img_header.set_data_shape(img_arr.shape) |
|
|
146 |
img_header.set_zooms(i_zoom) |
|
|
147 |
|
|
|
148 |
affine = img_header.get_qform() |
|
|
149 |
affine[0][3] += ((flags['imgSize'][0] - ishape[0]) / 2 * i_zoom[0]) |
|
|
150 |
affine[1][3] -= ((flags['imgSize'][1] - ishape[1]) / 2 * i_zoom[1]) |
|
|
151 |
affine[2][3] -= ((flags['imgSize'][2] - ishape[2]) / 2 * i_zoom[2]) |
|
|
152 |
img_header.set_qform(affine) |
|
|
153 |
|
|
|
154 |
new_img = nib.Nifti1Image(img_arr, affine, img_header) |
|
|
155 |
#save images if modified |
|
|
156 |
|
|
|
157 |
if save: |
|
|
158 |
|
|
|
159 |
if not os.path.isdir(os.path.join(save_path, 'MRI')): |
|
|
160 |
os.mkdir(os.path.join(save_path, 'MRI')) |
|
|
161 |
|
|
|
162 |
mri_path = os.path.join(save_path, 'MRI') |
|
|
163 |
|
|
|
164 |
if mod == 'fat': |
|
|
165 |
new_img_path = os.path.join(mri_path, 'FatImaging_F.nii.gz') |
|
|
166 |
else: |
|
|
167 |
new_img_path = os.path.join(mri_path, 'FatImaging_W.nii.gz') |
|
|
168 |
|
|
|
169 |
nib.save(new_img, new_img_path) |
|
|
170 |
|
|
|
171 |
return new_img |