dbdicom 0.2.0__py3-none-any.whl → 0.3.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbdicom/__init__.py +3 -25
- dbdicom/api.py +496 -0
- dbdicom/const.py +144 -0
- dbdicom/database.py +133 -0
- dbdicom/dataset.py +471 -0
- dbdicom/dbd.py +1290 -0
- dbdicom/external/__pycache__/__init__.cpython-311.pyc +0 -0
- dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc +0 -0
- dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc +0 -0
- dbdicom/external/dcm4che/bin/emf2sf +57 -57
- dbdicom/register.py +402 -0
- dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
- dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +206 -160
- dbdicom/sop_classes/mr_image.py +338 -0
- dbdicom/sop_classes/parametric_map.py +381 -0
- dbdicom/sop_classes/secondary_capture.py +140 -0
- dbdicom/sop_classes/segmentation.py +311 -0
- dbdicom/{ds/types → sop_classes}/ultrasound_multiframe_image.py +1 -15
- dbdicom/{ds/types → sop_classes}/xray_angiographic_image.py +2 -17
- dbdicom/utils/arrays.py +142 -0
- dbdicom/utils/files.py +0 -20
- dbdicom/utils/image.py +43 -466
- dbdicom/utils/pydicom_dataset.py +386 -0
- dbdicom-0.3.16.dist-info/METADATA +26 -0
- dbdicom-0.3.16.dist-info/RECORD +54 -0
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/WHEEL +1 -1
- dbdicom/create.py +0 -450
- dbdicom/ds/__init__.py +0 -10
- dbdicom/ds/create.py +0 -63
- dbdicom/ds/dataset.py +0 -841
- dbdicom/ds/dictionaries.py +0 -620
- dbdicom/ds/types/mr_image.py +0 -267
- dbdicom/ds/types/parametric_map.py +0 -226
- dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
- dbdicom/manager.py +0 -2077
- dbdicom/message.py +0 -119
- dbdicom/record.py +0 -1526
- dbdicom/types/database.py +0 -107
- dbdicom/types/instance.py +0 -184
- dbdicom/types/patient.py +0 -40
- dbdicom/types/series.py +0 -816
- dbdicom/types/study.py +0 -58
- dbdicom/utils/variables.py +0 -155
- dbdicom/utils/vreg.py +0 -2626
- dbdicom/wrappers/__init__.py +0 -7
- dbdicom/wrappers/dipy.py +0 -462
- dbdicom/wrappers/elastix.py +0 -855
- dbdicom/wrappers/numpy.py +0 -119
- dbdicom/wrappers/scipy.py +0 -1413
- dbdicom/wrappers/skimage.py +0 -1030
- dbdicom/wrappers/sklearn.py +0 -151
- dbdicom/wrappers/vreg.py +0 -273
- dbdicom-0.2.0.dist-info/METADATA +0 -276
- dbdicom-0.2.0.dist-info/RECORD +0 -81
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info/licenses}/LICENSE +0 -0
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/top_level.txt +0 -0
dbdicom/wrappers/elastix.py
DELETED
|
@@ -1,855 +0,0 @@
|
|
|
1
|
-
# pip install SimpleITK-SimpleElastix
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import SimpleITK as sitk
|
|
5
|
-
import dbdicom.wrappers.scipy as scipy
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def invert_deformation_field(deformation_field, **kwargs):
|
|
9
|
-
|
|
10
|
-
# Get arrays for deformation_field
|
|
11
|
-
deform, headers = deformation_field.array('SliceLocation', pixels_first=True)
|
|
12
|
-
|
|
13
|
-
# Raise an error if the array is empty
|
|
14
|
-
if deform is None:
|
|
15
|
-
msg = 'The deformation field is an empty series. \n'
|
|
16
|
-
msg += 'Please select a valid series and try again.'
|
|
17
|
-
raise ValueError(msg)
|
|
18
|
-
|
|
19
|
-
# Calculate the inverse
|
|
20
|
-
deformation_field.status.message('Calculating inverse..')
|
|
21
|
-
deform_inv = _invert_deformation_field(deform, **kwargs)
|
|
22
|
-
|
|
23
|
-
# Return as new series
|
|
24
|
-
inv = deformation_field.new_sibling(suffix='inverse')
|
|
25
|
-
inv.set_array(deform_inv, headers, pixels_first=True)
|
|
26
|
-
return inv
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def coregister_3d_to_3d(moving, fixed,
|
|
30
|
-
transformation = 'Affine',
|
|
31
|
-
metric = "NormalizedMutualInformation",
|
|
32
|
-
final_grid_spacing = 1.0,
|
|
33
|
-
_ignore_empty_slices = False, # Do not use for now
|
|
34
|
-
):
|
|
35
|
-
|
|
36
|
-
nan = 2**16-1
|
|
37
|
-
fixed_map = scipy.map_to(fixed, moving, cval=nan)
|
|
38
|
-
|
|
39
|
-
# Get arrays for fixed and moving series
|
|
40
|
-
array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
41
|
-
array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
42
|
-
|
|
43
|
-
# If one of the datasets is empty do nothing
|
|
44
|
-
if array_fixed is None or array_moving is None:
|
|
45
|
-
return fixed_map
|
|
46
|
-
|
|
47
|
-
# Remove temporary overlay
|
|
48
|
-
if fixed_map != fixed:
|
|
49
|
-
fixed_map.remove()
|
|
50
|
-
|
|
51
|
-
# # If time series consider only first time point
|
|
52
|
-
# array_fixed = array_fixed[...,0]
|
|
53
|
-
# array_moving = array_moving[...,0]
|
|
54
|
-
# headers_moving = headers_moving[...,0]
|
|
55
|
-
|
|
56
|
-
# Apply coregistration settings
|
|
57
|
-
if transformation == 'Rigid':
|
|
58
|
-
pars = _default_rigid()
|
|
59
|
-
elif transformation == 'Affine':
|
|
60
|
-
pars = _default_affine()
|
|
61
|
-
else:
|
|
62
|
-
pars = _default_bspline()
|
|
63
|
-
|
|
64
|
-
pars["Metric"] = [metric]
|
|
65
|
-
pars["FinalGridSpacingInPhysicalUnits"] = [str(final_grid_spacing)]
|
|
66
|
-
pars["FixedImageDimension"] = ['3']
|
|
67
|
-
pars["MovingImageDimension"] = ['3']
|
|
68
|
-
|
|
69
|
-
# Coregister fixed and moving slice-by-slice
|
|
70
|
-
moving.status.message('Performing coregistration..')
|
|
71
|
-
#deformation = np.empty(array_moving.shape + (2,))
|
|
72
|
-
ind_fixed = np.where(array_fixed==nan)
|
|
73
|
-
array_fixed[ind_fixed] = 0
|
|
74
|
-
array_moving[ind_fixed] = 0
|
|
75
|
-
|
|
76
|
-
# Don't use for now
|
|
77
|
-
# This may lead to an error of too many samples outside moving image buffer
|
|
78
|
-
if _ignore_empty_slices:
|
|
79
|
-
fixed_mask = _coregistration_mask_3d(array_fixed)
|
|
80
|
-
moving_mask = _coregistration_mask_3d(array_moving)
|
|
81
|
-
else:
|
|
82
|
-
fixed_mask = None
|
|
83
|
-
moving_mask = None
|
|
84
|
-
|
|
85
|
-
# get this from series affine instead - more robust
|
|
86
|
-
slice_spacing = headers_moving[0].SpacingBetweenSlices # needs a custom keyword slice_spacing
|
|
87
|
-
if slice_spacing is None:
|
|
88
|
-
slice_spacing = headers_moving[0].SliceThickness
|
|
89
|
-
pixel_spacing = headers_moving[0].PixelSpacing + [slice_spacing]
|
|
90
|
-
|
|
91
|
-
coregistered, deformation = _coregister_arrays(array_fixed, array_moving, pars, pixel_spacing, pixel_spacing, fixed_mask=fixed_mask, moving_mask=moving_mask)
|
|
92
|
-
|
|
93
|
-
# Return new series
|
|
94
|
-
coreg = moving.new_sibling(suffix='coregistered')
|
|
95
|
-
deform = moving.new_sibling(suffix='deformation field')
|
|
96
|
-
|
|
97
|
-
coreg.set_array(coregistered, headers_moving, pixels_first=True)
|
|
98
|
-
for dim in range(deformation.shape[-1]):
|
|
99
|
-
deform.set_array(deformation[...,dim], headers_moving, pixels_first=True)
|
|
100
|
-
# deform_size = moving.new_sibling(SeriesDescription = desc + ' [deformation]')
|
|
101
|
-
# deform_size.set_array( np.linalg.norm(deformation, axis=-1), headers_moving, pixels_first=True)
|
|
102
|
-
moving.status.message('Finished coregistration..')
|
|
103
|
-
return coreg, deform
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def _coregistration_mask_3d(array):
|
|
107
|
-
mask = np.zeros(array.shape, np.uint8)
|
|
108
|
-
for z in range(array.shape[2]):
|
|
109
|
-
if np.count_nonzero(array[:,:,z]) > 0:
|
|
110
|
-
mask[:,:,z] = 1
|
|
111
|
-
return mask
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def coregister_2d_to_2d(moving, fixed,
|
|
115
|
-
transformation = 'Affine',
|
|
116
|
-
metric = "NormalizedMutualInformation",
|
|
117
|
-
final_grid_spacing = 1.0,
|
|
118
|
-
):
|
|
119
|
-
|
|
120
|
-
background = 2**16-1
|
|
121
|
-
fixed_map = scipy.map_to(fixed, moving, cval=background)
|
|
122
|
-
|
|
123
|
-
# Get arrays for fixed and moving series
|
|
124
|
-
array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
125
|
-
array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
126
|
-
|
|
127
|
-
# Raise an error if one of the datasets is empty
|
|
128
|
-
if array_fixed is None or array_moving is None:
|
|
129
|
-
msg = 'One of the series is empty. \n'
|
|
130
|
-
msg += 'Please select a non-empty series and try again.'
|
|
131
|
-
raise ValueError(msg)
|
|
132
|
-
|
|
133
|
-
# Remove temporary overlay
|
|
134
|
-
if fixed_map != fixed:
|
|
135
|
-
fixed_map.remove()
|
|
136
|
-
|
|
137
|
-
# If time series consider only first time point
|
|
138
|
-
# array_fixed = array_fixed[...,0]
|
|
139
|
-
# array_moving = array_moving[...,0]
|
|
140
|
-
# headers_moving = headers_moving[...,0]
|
|
141
|
-
|
|
142
|
-
# Set background pixels to zero for both images
|
|
143
|
-
idx = np.where(array_fixed==background)
|
|
144
|
-
array_fixed[idx] = 0
|
|
145
|
-
array_moving[idx] = 0
|
|
146
|
-
|
|
147
|
-
# Get coregistration settings
|
|
148
|
-
if transformation == 'Rigid':
|
|
149
|
-
pars = _default_rigid()
|
|
150
|
-
elif transformation == 'Affine':
|
|
151
|
-
pars = _default_affine()
|
|
152
|
-
else:
|
|
153
|
-
pars = _default_bspline()
|
|
154
|
-
pars["Metric"] = [metric]
|
|
155
|
-
pars["FinalGridSpacingInPhysicalUnits"] = [str(final_grid_spacing)]
|
|
156
|
-
pars["FixedImageDimension"] = ['2']
|
|
157
|
-
pars["MovingImageDimension"] = ['2']
|
|
158
|
-
|
|
159
|
-
# Coregister fixed and moving slice-by-slice
|
|
160
|
-
deformation = np.empty(array_moving.shape + (2,))
|
|
161
|
-
pixel_spacing = headers_moving[0].PixelSpacing
|
|
162
|
-
for z in range(array_moving.shape[2]):
|
|
163
|
-
moving.status.progress(z+1, array_moving.shape[2], 'Performing coregistration..')
|
|
164
|
-
coreg, deform = _coregister_arrays(array_fixed[:,:,z], array_moving[:,:,z], pars, pixel_spacing, pixel_spacing)
|
|
165
|
-
deformation[:,:,z,:] = deform
|
|
166
|
-
array_moving[:,:,z] = coreg
|
|
167
|
-
|
|
168
|
-
# Create new series
|
|
169
|
-
coreg = moving.new_sibling(suffix='coregistered')
|
|
170
|
-
deform = moving.new_sibling(suffix='deformation field')
|
|
171
|
-
|
|
172
|
-
# Save data
|
|
173
|
-
coreg.set_array(array_moving, headers_moving, pixels_first=True)
|
|
174
|
-
for dim in range(deformation.shape[-1]):
|
|
175
|
-
deform.set_array(deformation[...,dim], headers_moving, pixels_first=True)
|
|
176
|
-
deform[['WindowCenter', 'WindowWidth']] = [0, 10]
|
|
177
|
-
|
|
178
|
-
# Return coregistered image and deformation field
|
|
179
|
-
return coreg, deform
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
# ONLY TESTED FOR RIGID TRANSFORMATION
|
|
183
|
-
# AFFINE AND DEFORMABLE DOES NOT WORK
|
|
184
|
-
def coregister_3d_to_2d(moving_3d, fixed_2d, # moving=3D, fixed=2D
|
|
185
|
-
transformation = 'Affine',
|
|
186
|
-
metric = "NormalizedMutualInformation",
|
|
187
|
-
final_grid_spacing = 1.0,
|
|
188
|
-
):
|
|
189
|
-
|
|
190
|
-
nan = 2**16-1
|
|
191
|
-
moving_map = scipy.map_to(moving_3d, fixed_2d, cval=nan)
|
|
192
|
-
|
|
193
|
-
# Get arrays for fixed and moving series
|
|
194
|
-
array_fixed, headers_fixed = fixed_2d.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
195
|
-
array_moving, _ = moving_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
196
|
-
|
|
197
|
-
# If one of the datasets is empty do nothing
|
|
198
|
-
if array_fixed is None or array_moving is None:
|
|
199
|
-
return moving_map
|
|
200
|
-
|
|
201
|
-
# Remove temporary overlay
|
|
202
|
-
if moving_map != moving_3d:
|
|
203
|
-
moving_map.remove()
|
|
204
|
-
|
|
205
|
-
# # If time series consider only first time point
|
|
206
|
-
# array_fixed = array_fixed[...,0]
|
|
207
|
-
# array_moving = array_moving[...,0]
|
|
208
|
-
# headers_fixed = headers_fixed[...,0]
|
|
209
|
-
|
|
210
|
-
# Get coregistration settings
|
|
211
|
-
if transformation == 'Rigid':
|
|
212
|
-
pars = _default_rigid()
|
|
213
|
-
elif transformation == 'Affine':
|
|
214
|
-
pars = _default_affine()
|
|
215
|
-
else:
|
|
216
|
-
pars = _default_bspline()
|
|
217
|
-
|
|
218
|
-
pars["Metric"] = [metric]
|
|
219
|
-
pars["FinalGridSpacingInPhysicalUnits"] = [str(final_grid_spacing)]
|
|
220
|
-
pars["FixedImageDimension"] = ['3'] # 2D image must be entered as 3D with 3d dimension = 1
|
|
221
|
-
pars["MovingImageDimension"] = ['3']
|
|
222
|
-
|
|
223
|
-
# Coregister fixed and moving slice-by-slice
|
|
224
|
-
deformation = np.empty(array_moving.shape + (3,))
|
|
225
|
-
ind_nan = np.where(array_fixed==nan)
|
|
226
|
-
array_fixed[ind_nan] = 0
|
|
227
|
-
array_moving[ind_nan] = 0
|
|
228
|
-
pixel_spacing = headers_fixed[0].PixelSpacing
|
|
229
|
-
slice_spacing = headers_fixed[0].SpacingBetweenSlices # needs a custom keyword slice_spacing
|
|
230
|
-
if slice_spacing is None:
|
|
231
|
-
slice_spacing = headers_fixed[0].SliceThickness
|
|
232
|
-
spacing = pixel_spacing + [slice_spacing]
|
|
233
|
-
for z in range(array_fixed.shape[2]):
|
|
234
|
-
moving_3d.status.progress(z+1, array_fixed.shape[2], 'Performing coregistration..')
|
|
235
|
-
fixed = array_fixed[:,:,z].reshape(array_fixed.shape[:2]+(1,)) # enter as 3d with 3d dim=1
|
|
236
|
-
coreg, deform = _coregister_arrays(fixed, array_moving, pars, spacing, spacing)
|
|
237
|
-
deformation[:,:,z,:] = np.squeeze(deform) # remove z-dimension of 1 again
|
|
238
|
-
array_fixed[:,:,z] = np.squeeze(coreg)
|
|
239
|
-
|
|
240
|
-
# Return new series
|
|
241
|
-
coreg = moving_3d.new_sibling(suffix='coregistered')
|
|
242
|
-
deform = moving_3d.new_sibling(suffix='deformation field')
|
|
243
|
-
|
|
244
|
-
coreg.set_array(array_fixed, headers_fixed, pixels_first=True)
|
|
245
|
-
for dim in range(deformation.shape[-1]):
|
|
246
|
-
deform.set_array(deformation[...,dim], headers_fixed, pixels_first=True)
|
|
247
|
-
return coreg, deform
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
# THIS DOES NOT WORK
|
|
251
|
-
def coregister_2d_to_3d(moving_2d, fixed_3d, # moving=2D, fixed=3D
|
|
252
|
-
transformation = 'Affine',
|
|
253
|
-
metric = "NormalizedMutualInformation",
|
|
254
|
-
final_grid_spacing = 1.0,
|
|
255
|
-
):
|
|
256
|
-
|
|
257
|
-
nan = 2**16-1
|
|
258
|
-
fixed_map = scipy.map_to(fixed_3d, moving_2d, cval=nan)
|
|
259
|
-
|
|
260
|
-
# Get arrays for fixed and moving series
|
|
261
|
-
array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
262
|
-
array_moving, headers_moving = moving_2d.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
263
|
-
|
|
264
|
-
# If one of the datasets is empty do nothing
|
|
265
|
-
if array_fixed is None or array_moving is None:
|
|
266
|
-
return fixed_map
|
|
267
|
-
|
|
268
|
-
# Remove temporary overlay
|
|
269
|
-
if fixed_map != fixed_3d:
|
|
270
|
-
fixed_map.remove()
|
|
271
|
-
|
|
272
|
-
# # If time series consider only first time point
|
|
273
|
-
# array_fixed = array_fixed[...,0]
|
|
274
|
-
# array_moving = array_moving[...,0]
|
|
275
|
-
# headers_moving = headers_moving[...,0]
|
|
276
|
-
|
|
277
|
-
# Get coregistration settings
|
|
278
|
-
if transformation == 'Rigid':
|
|
279
|
-
#pars = _default_rigid()
|
|
280
|
-
pars = _default_2d_to_3d()
|
|
281
|
-
elif transformation == 'Affine':
|
|
282
|
-
#pars = _default_affine()
|
|
283
|
-
pars = _default_2d_to_3d()
|
|
284
|
-
else:
|
|
285
|
-
#pars = _default_bspline()
|
|
286
|
-
pars = _default_2d_to_3d()
|
|
287
|
-
|
|
288
|
-
pars["Metric"] = [metric]
|
|
289
|
-
pars["FinalGridSpacingInPhysicalUnits"] = [str(final_grid_spacing)]
|
|
290
|
-
pars["FixedImageDimension"] = ['3']
|
|
291
|
-
pars["MovingImageDimension"] = ['3'] # 2D image must be entered as 3D with 3d dimension = 1
|
|
292
|
-
|
|
293
|
-
# Coregister fixed and moving slice-by-slice
|
|
294
|
-
deformation = np.empty(array_moving.shape + (3,))
|
|
295
|
-
ind_nan = np.where(array_fixed==nan)
|
|
296
|
-
array_fixed[ind_nan] = 0
|
|
297
|
-
array_moving[ind_nan] = 0
|
|
298
|
-
pixel_spacing = headers_moving[0].PixelSpacing
|
|
299
|
-
slice_spacing = headers_moving[0].SpacingBetweenSlices
|
|
300
|
-
if slice_spacing is None:
|
|
301
|
-
slice_spacing = headers_moving[0].SliceThickness
|
|
302
|
-
spacing = pixel_spacing + [slice_spacing]
|
|
303
|
-
for z in range(array_moving.shape[2]):
|
|
304
|
-
moving_2d.status.progress(z+1, array_moving.shape[2], 'Performing coregistration..')
|
|
305
|
-
moving = array_moving[:,:,z].reshape(array_moving.shape[:2]+(1,)) # enter as 3d with 3d dim=1
|
|
306
|
-
coreg, deform = _coregister_arrays(array_fixed, moving, pars, spacing, spacing)
|
|
307
|
-
deformation[:,:,z,:] = np.squeeze(deform) # remove z-dimension of 1 again
|
|
308
|
-
array_fixed[:,:,z] = np.squeeze(coreg)
|
|
309
|
-
|
|
310
|
-
# Create new series
|
|
311
|
-
coreg = moving_2d.new_sibling(suffix='coregistered')
|
|
312
|
-
deform = moving_2d.new_sibling(suffix='deformation field')
|
|
313
|
-
|
|
314
|
-
# Set arrays
|
|
315
|
-
coreg.set_array(array_fixed, headers_moving, pixels_first=True)
|
|
316
|
-
for dim in range(deformation.shape[-1]):
|
|
317
|
-
deform.set_array(deformation[...,dim], headers_moving, pixels_first=True)
|
|
318
|
-
|
|
319
|
-
# return coregistered image and deformation field
|
|
320
|
-
return coreg, deform
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
def warp(image, deformation_field):
|
|
324
|
-
|
|
325
|
-
# Get arrays for image and deformation field
|
|
326
|
-
array, headers = image.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
327
|
-
array_deform, _ = deformation_field.array('SliceLocation', pixels_first=True)
|
|
328
|
-
|
|
329
|
-
# Warp array with deformation field
|
|
330
|
-
image.message('Warping image with deformation field..')
|
|
331
|
-
array = _warp_arrays(array, array_deform)
|
|
332
|
-
|
|
333
|
-
# Return as dbdicom series
|
|
334
|
-
warped = image.new_sibling(suffix='warped')
|
|
335
|
-
warped.set_array(array, headers, pixels_first=True)
|
|
336
|
-
return warped
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
# BELOW HERE NON-DICOM FUNCTIONALITY
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def _invert_deformation_field(deform: np.ndarray, smooth=False) -> np.ndarray:
|
|
346
|
-
# deform must have shape (x,y,z,ndim) with ndim=2 or 3
|
|
347
|
-
ndim = deform.shape[-1]
|
|
348
|
-
if ndim==3:
|
|
349
|
-
return _invert_deformation_field_volume(deform, smooth=smooth)
|
|
350
|
-
elif ndim==2:
|
|
351
|
-
nslices = deform.shape[2]
|
|
352
|
-
for z in range(nslices):
|
|
353
|
-
deform[:,:,z,:] = _invert_deformation_field_volume(deform[:,:,z,:], smooth=smooth)
|
|
354
|
-
return deform
|
|
355
|
-
else:
|
|
356
|
-
msg = 'The deformation field must have either 2 or 3 dimensions'
|
|
357
|
-
raise ValueError(msg)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
def _invert_deformation_field_volume(deform: np.ndarray, smooth=False) -> np.ndarray:
|
|
361
|
-
deform = sitk.GetImageFromArray(deform, isVector=True)
|
|
362
|
-
if smooth:
|
|
363
|
-
filter = sitk.InvertDisplacementFieldImageFilter()
|
|
364
|
-
filter.EnforceBoundaryConditionOn()
|
|
365
|
-
deform_inv = filter.Execute(deform)
|
|
366
|
-
else:
|
|
367
|
-
deform_inv = sitk.InverseDisplacementField(deform,
|
|
368
|
-
size = deform.GetSize(),
|
|
369
|
-
outputOrigin = (0.0, 0.0),
|
|
370
|
-
outputSpacing = (1.0, 1.0))
|
|
371
|
-
return sitk.GetArrayFromImage(deform_inv)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
def _warp_arrays(array, deformation_field):
|
|
375
|
-
|
|
376
|
-
# For this function, image and deformation field must be aligned
|
|
377
|
-
if array.shape != deformation_field.shape[:-1]:
|
|
378
|
-
msg = 'The dimensions of image and deformation field are not matching up. \n'
|
|
379
|
-
msg += 'Please select two series with matching dimensions.'
|
|
380
|
-
raise ValueError(msg)
|
|
381
|
-
|
|
382
|
-
ndim = deformation_field.shape[-1]
|
|
383
|
-
if ndim == 3:
|
|
384
|
-
return _warp_volume(array, deformation_field)
|
|
385
|
-
|
|
386
|
-
# if the deformation field is 2D, then loop over the slices
|
|
387
|
-
elif ndim == 2:
|
|
388
|
-
nslices = deformation_field.shape[2]
|
|
389
|
-
for z in range(nslices):
|
|
390
|
-
array[:,:,z] = _warp_volume(array[:,:,z], deformation_field[:,:,z,:])
|
|
391
|
-
return array
|
|
392
|
-
|
|
393
|
-
# Raise an error if the deformation field does not have 2 or 3 components
|
|
394
|
-
else:
|
|
395
|
-
msg = 'The deformation field must have either 2 or 3 dimensions'
|
|
396
|
-
raise ValueError(msg)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
def _warp_volume(volume, displacement):
|
|
401
|
-
# Create an image from the volume numpy array
|
|
402
|
-
volume_sitk = sitk.GetImageFromArray(volume)
|
|
403
|
-
|
|
404
|
-
# Create a displacement field image from the displacement numpy array
|
|
405
|
-
displacement_sitk = sitk.GetImageFromArray(displacement, isVector=True)
|
|
406
|
-
displacement_sitk = sitk.Cast(displacement_sitk, sitk.sitkVectorFloat64)
|
|
407
|
-
|
|
408
|
-
# Set up the transformation object
|
|
409
|
-
displacement_transform = sitk.DisplacementFieldTransform(displacement_sitk)
|
|
410
|
-
|
|
411
|
-
# Warp the volume using the displacement field transform
|
|
412
|
-
warped_sitk = sitk.Resample(volume_sitk, displacement_transform)
|
|
413
|
-
|
|
414
|
-
# Convert the warped image to a numpy array
|
|
415
|
-
warped = sitk.GetArrayFromImage(warped_sitk)
|
|
416
|
-
|
|
417
|
-
return warped
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
# Would prefer to use Transformix for warping but this does not work
|
|
421
|
-
def _wip_warp_volume(array, deformation_field):
|
|
422
|
-
|
|
423
|
-
# Convert the numpy arrays to a SimpleITK images
|
|
424
|
-
input_image = sitk.GetImageFromArray(array)
|
|
425
|
-
displacement_sitk = sitk.GetImageFromArray(deformation_field)
|
|
426
|
-
|
|
427
|
-
# Define transform parameter map for transformation with displacement field
|
|
428
|
-
parameter_map = _default_bspline()
|
|
429
|
-
parameter_map['Transform'] = ['DisplacementFieldTransform']
|
|
430
|
-
parameter_map['DisplacementField'] = [displacement_sitk]
|
|
431
|
-
parameter_map['ResampleInterpolator'] = ['FinalBSplineInterpolator']
|
|
432
|
-
parameter_map['FinalBSplineInterpolationOrder'] = ['3']
|
|
433
|
-
parameter_map['ResultImagePixelType'] = ['float']
|
|
434
|
-
|
|
435
|
-
# Create the Transformix image filter object
|
|
436
|
-
transformix = sitk.TransformixImageFilter()
|
|
437
|
-
transformix.SetTransformParameterMap(parameter_map)
|
|
438
|
-
|
|
439
|
-
# Set the input and deformation images for the Transformix filter
|
|
440
|
-
transformix.SetMovingImage(input_image)
|
|
441
|
-
|
|
442
|
-
warped = transformix.Execute()
|
|
443
|
-
|
|
444
|
-
# Get the warped image as a SimpleITK image
|
|
445
|
-
#warped = transformix.GetResultImage()
|
|
446
|
-
|
|
447
|
-
# Convert the warped image to a numpy array
|
|
448
|
-
warped = sitk.GetArrayFromImage(warped)
|
|
449
|
-
|
|
450
|
-
return warped
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
def _coregister_arrays(fixed, moving, params, fixed_spacing, moving_spacing, fixed_mask=None, moving_mask=None):
|
|
455
|
-
"""
|
|
456
|
-
Coregister two arrays and return coregistered + deformation field
|
|
457
|
-
"""
|
|
458
|
-
|
|
459
|
-
# Convert numpy arrays to sitk images
|
|
460
|
-
moving = sitk.GetImageFromArray(moving)
|
|
461
|
-
moving.SetSpacing(moving_spacing)
|
|
462
|
-
fixed = sitk.GetImageFromArray(fixed)
|
|
463
|
-
fixed.SetSpacing(fixed_spacing)
|
|
464
|
-
if moving_mask is not None:
|
|
465
|
-
moving_mask = sitk.GetImageFromArray(moving_mask)
|
|
466
|
-
moving_mask.SetSpacing(moving_spacing)
|
|
467
|
-
#moving_mask.__SetPixelAsUInt8__
|
|
468
|
-
if fixed_mask is not None:
|
|
469
|
-
fixed_mask = sitk.GetImageFromArray(fixed_mask)
|
|
470
|
-
fixed_mask.SetSpacing(fixed_spacing)
|
|
471
|
-
#fixed_mask.__SetPixelAsUInt8__
|
|
472
|
-
|
|
473
|
-
# Perform registration
|
|
474
|
-
elastixImageFilter = sitk.ElastixImageFilter()
|
|
475
|
-
elastixImageFilter.LogToConsoleOn() # turn on for debugging
|
|
476
|
-
#elastixImageFilter.LogToConsoleOff()
|
|
477
|
-
elastixImageFilter.SetFixedImage(fixed)
|
|
478
|
-
elastixImageFilter.SetMovingImage(moving)
|
|
479
|
-
elastixImageFilter.SetParameterMap(params)
|
|
480
|
-
if fixed_mask is not None:
|
|
481
|
-
elastixImageFilter.SetFixedMask(fixed_mask)
|
|
482
|
-
if moving_mask is not None:
|
|
483
|
-
elastixImageFilter.SetMovingMask(moving_mask)
|
|
484
|
-
elastixImageFilter.Execute()
|
|
485
|
-
|
|
486
|
-
# Calculate deformation field
|
|
487
|
-
transformParameterMap = elastixImageFilter.GetTransformParameterMap()
|
|
488
|
-
transformixImageFilter = sitk.TransformixImageFilter()
|
|
489
|
-
#transformixImageFilter.LogToConsoleOn() # turn on for debugging
|
|
490
|
-
transformixImageFilter.LogToConsoleOff()
|
|
491
|
-
transformixImageFilter.SetTransformParameterMap(transformParameterMap)
|
|
492
|
-
# transformixImageFilter.UpdateLargestPossibleRegion()
|
|
493
|
-
transformixImageFilter.ComputeDeformationFieldOn()
|
|
494
|
-
transformixImageFilter.SetMovingImage(moving)
|
|
495
|
-
transformixImageFilter.Execute()
|
|
496
|
-
|
|
497
|
-
# Collect return values
|
|
498
|
-
# coregistered = transformixImageFilter.GetResultImage() # same result
|
|
499
|
-
coregistered = elastixImageFilter.GetResultImage()
|
|
500
|
-
deformation_field = transformixImageFilter.GetDeformationField()
|
|
501
|
-
|
|
502
|
-
# Convert sitk Images back to numpy arrays
|
|
503
|
-
coregistered = sitk.GetArrayFromImage(coregistered)
|
|
504
|
-
deformation_field = sitk.GetArrayFromImage(deformation_field)
|
|
505
|
-
|
|
506
|
-
return coregistered, deformation_field
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
def _default_bspline():
|
|
512
|
-
|
|
513
|
-
p = sitk.GetDefaultParameterMap("bspline")
|
|
514
|
-
|
|
515
|
-
# *********************
|
|
516
|
-
# * ImageTypes
|
|
517
|
-
# *********************
|
|
518
|
-
p["FixedInternalImagePixelType"] = ["float"]
|
|
519
|
-
p["MovingInternalImagePixelType"] = ["float"]
|
|
520
|
-
## selection based on 3D or 2D image data: newest elastix version does not require input image dimension
|
|
521
|
-
p["FixedImageDimension"] = ["2"]
|
|
522
|
-
p["MovingImageDimension"] = ["2"]
|
|
523
|
-
p["UseDirectionCosines"] = ["true"]
|
|
524
|
-
# *********************
|
|
525
|
-
# * Components
|
|
526
|
-
# *********************
|
|
527
|
-
p["Registration"] = ["MultiResolutionRegistration"]
|
|
528
|
-
# Image intensities are sampled using an ImageSampler, Interpolator and ResampleInterpolator.
|
|
529
|
-
# Image sampler is responsible for selecting points in the image to sample.
|
|
530
|
-
# The RandomCoordinate simply selects random positions.
|
|
531
|
-
p["ImageSampler"] = ["RandomCoordinate"]
|
|
532
|
-
# Interpolator is responsible for interpolating off-grid positions during optimization.
|
|
533
|
-
# The BSplineInterpolator with BSplineInterpolationOrder = 1 used here is very fast and uses very little memory
|
|
534
|
-
p["Interpolator"] = ["BSplineInterpolator"]
|
|
535
|
-
# ResampleInterpolator here chosen to be FinalBSplineInterpolator with FinalBSplineInterpolationOrder = 1
|
|
536
|
-
# is used to resample the result image from the moving image once the final transformation has been found.
|
|
537
|
-
# This is a one-time step so the additional computational complexity is worth the trade-off for higher image quality.
|
|
538
|
-
p["ResampleInterpolator"] = ["FinalBSplineInterpolator"]
|
|
539
|
-
p["Resampler"] = ["DefaultResampler"]
|
|
540
|
-
# Order of B-Spline interpolation used during registration/optimisation.
|
|
541
|
-
# It may improve accuracy if you set this to 3. Never use 0.
|
|
542
|
-
# An order of 1 gives linear interpolation. This is in most
|
|
543
|
-
# applications a good choice.
|
|
544
|
-
p["BSplineInterpolationOrder"] = ["1"]
|
|
545
|
-
# Order of B-Spline interpolation used for applying the final
|
|
546
|
-
# deformation.
|
|
547
|
-
# 3 gives good accuracy; recommended in most cases.
|
|
548
|
-
# 1 gives worse accuracy (linear interpolation)
|
|
549
|
-
# 0 gives worst accuracy, but is appropriate for binary images
|
|
550
|
-
# (masks, segmentations); equivalent to nearest neighbor interpolation.
|
|
551
|
-
p["FinalBSplineInterpolationOrder"] = ["3"]
|
|
552
|
-
# Pyramids found in Elastix:
|
|
553
|
-
# 1) Smoothing -> Smoothing: YES, Downsampling: NO
|
|
554
|
-
# 2) Recursive -> Smoothing: YES, Downsampling: YES
|
|
555
|
-
# If Recursive is chosen and only # of resolutions is given
|
|
556
|
-
# then downsamlping by a factor of 2 (default)
|
|
557
|
-
# 3) Shrinking -> Smoothing: NO, Downsampling: YES
|
|
558
|
-
# p["FixedImagePyramid"] = ["FixedSmoothingImagePyramid"] # Smoothing requires 3d dimension at least 4 pixels
|
|
559
|
-
# p["MovingImagePyramid"] = ["MovingSmoothingImagePyramid"]
|
|
560
|
-
p["FixedImagePyramid"] = ["FixedRecursiveImagePyramid"]
|
|
561
|
-
p["MovingImagePyramid"] = ["MovingRecursiveImagePyramid"]
|
|
562
|
-
p["Optimizer"] = ["AdaptiveStochasticGradientDescent"]
|
|
563
|
-
# Whether transforms are combined by composition or by addition.
|
|
564
|
-
# In generally, Compose is the best option in most cases.
|
|
565
|
-
# It does not influence the results very much.
|
|
566
|
-
p["HowToCombineTransforms"] = ["Compose"]
|
|
567
|
-
p["Transform"] = ["BSplineTransform"]
|
|
568
|
-
# Metric
|
|
569
|
-
# p["Metric"] = ["AdvancedMeanSquares"]
|
|
570
|
-
p["Metric"] = ["NormalizedMutualInformation"]
|
|
571
|
-
# Number of grey level bins in each resolution level,
|
|
572
|
-
# for the mutual information. 16 or 32 usually works fine.
|
|
573
|
-
# You could also employ a hierarchical strategy:
|
|
574
|
-
#(NumberOfHistogramBins 16 32 64)
|
|
575
|
-
p["NumberOfHistogramBins"] = ["32"]
|
|
576
|
-
# *********************
|
|
577
|
-
# * Transformation
|
|
578
|
-
# *********************
|
|
579
|
-
# The control point spacing of the bspline transformation in
|
|
580
|
-
# the finest resolution level. Can be specified for each
|
|
581
|
-
# dimension differently. Unit: mm.
|
|
582
|
-
# The lower this value, the more flexible the deformation.
|
|
583
|
-
# Low values may improve the accuracy, but may also cause
|
|
584
|
-
# unrealistic deformations.
|
|
585
|
-
# By default the grid spacing is halved after every resolution,
|
|
586
|
-
# such that the final grid spacing is obtained in the last
|
|
587
|
-
# resolution level.
|
|
588
|
-
# The grid spacing here is specified in voxel units.
|
|
589
|
-
#(FinalGridSpacingInPhysicalUnits 10.0 10.0)
|
|
590
|
-
#(FinalGridSpacingInVoxels 8)
|
|
591
|
-
#p["FinalGridSpacingInPhysicalUnits"] = ["50.0"]
|
|
592
|
-
p["FinalGridSpacingInPhysicalUnits"] = ["25.0", "25.0"]
|
|
593
|
-
# *********************
|
|
594
|
-
# * Optimizer settings
|
|
595
|
-
# *********************
|
|
596
|
-
# The number of resolutions. 1 Is only enough if the expected
|
|
597
|
-
# deformations are small. 3 or 4 mostly works fine. For large
|
|
598
|
-
# images and large deformations, 5 or 6 may even be useful.
|
|
599
|
-
p["NumberOfResolutions"] = ["4"]
|
|
600
|
-
p["AutomaticParameterEstimation"] = ["true"]
|
|
601
|
-
p["ASGDParameterEstimationMethod"] = ["Original"]
|
|
602
|
-
p["MaximumNumberOfIterations"] = ["500"]
|
|
603
|
-
# The step size of the optimizer, in mm. By default the voxel size is used.
|
|
604
|
-
# which usually works well. In case of unusual high-resolution images
|
|
605
|
-
# (eg histology) it is necessary to increase this value a bit, to the size
|
|
606
|
-
# of the "smallest visible structure" in the image:
|
|
607
|
-
# p["MaximumStepLength"] = ["1.0"]
|
|
608
|
-
p["MaximumStepLength"] = ["0.1"]
|
|
609
|
-
# *********************
|
|
610
|
-
# * Pyramid settings
|
|
611
|
-
# *********************
|
|
612
|
-
# The downsampling/blurring factors for the image pyramids.
|
|
613
|
-
# By default, the images are downsampled by a factor of 2
|
|
614
|
-
# compared to the next resolution.
|
|
615
|
-
#p["ImagePyramidSchedule"] = ["8 8 4 4 2 2 1 1"]
|
|
616
|
-
# *********************
|
|
617
|
-
# * Sampler parameters
|
|
618
|
-
# *********************
|
|
619
|
-
# Number of spatial samples used to compute the mutual
|
|
620
|
-
# information (and its derivative) in each iteration.
|
|
621
|
-
# With an AdaptiveStochasticGradientDescent optimizer,
|
|
622
|
-
# in combination with the two options below, around 2000
|
|
623
|
-
# samples may already suffice.
|
|
624
|
-
p["NumberOfSpatialSamples"] = ["2048"]
|
|
625
|
-
# Refresh these spatial samples in every iteration, and select
|
|
626
|
-
# them randomly. See the manual for information on other sampling
|
|
627
|
-
# strategies.
|
|
628
|
-
p["NewSamplesEveryIteration"] = ["true"]
|
|
629
|
-
p["CheckNumberOfSamples"] = ["true"]
|
|
630
|
-
# *********************
|
|
631
|
-
# * Mask settings
|
|
632
|
-
# *********************
|
|
633
|
-
# If you use a mask, this option is important.
|
|
634
|
-
# If the mask serves as region of interest, set it to false.
|
|
635
|
-
# If the mask indicates which pixels are valid, then set it to true.
|
|
636
|
-
# If you do not use a mask, the option doesn't matter.
|
|
637
|
-
p["ErodeMask"] = ["false"]
|
|
638
|
-
p["ErodeFixedMask"] = ["false"]
|
|
639
|
-
# *********************
|
|
640
|
-
# * Output settings
|
|
641
|
-
# *********************
|
|
642
|
-
#Default pixel value for pixels that come from outside the picture:
|
|
643
|
-
p["DefaultPixelValue"] = ["0"]
|
|
644
|
-
# Choose whether to generate the deformed moving image.
|
|
645
|
-
# You can save some time by setting this to false, if you are
|
|
646
|
-
# not interested in the final deformed moving image, but only
|
|
647
|
-
# want to analyze the deformation field for example.
|
|
648
|
-
p["WriteResultImage"] = ["true"]
|
|
649
|
-
# The pixel type and format of the resulting deformed moving image
|
|
650
|
-
p["ResultImagePixelType"] = ["float"]
|
|
651
|
-
p["ResultImageFormat"] = ["nii"]
|
|
652
|
-
|
|
653
|
-
return p
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
def _default_affine():
|
|
658
|
-
|
|
659
|
-
p = sitk.GetDefaultParameterMap("affine")
|
|
660
|
-
|
|
661
|
-
# ImageTypes
|
|
662
|
-
p["FixedInternalImagePixelType"] = ["float"]
|
|
663
|
-
p["MovingInternalImagePixelType"] = ["float"]
|
|
664
|
-
p["FixedImageDimension"] = ['2']
|
|
665
|
-
p["MovingImageDimension"] = ['2']
|
|
666
|
-
p["UseDirectionCosines"] = ["true"]
|
|
667
|
-
|
|
668
|
-
# Components
|
|
669
|
-
p["Registration"] = ["MultiResolutionRegistration"]
|
|
670
|
-
p["ImageSampler"] = ["Random"]
|
|
671
|
-
p["Interpolator"] = ["BSplineInterpolator"]
|
|
672
|
-
p["ResampleInterpolator"] = ["FinalBSplineInterpolator"]
|
|
673
|
-
p["Resampler"] = ["DefaultResampler"]
|
|
674
|
-
p["BSplineInterpolationOrder"] = ["3"]
|
|
675
|
-
p["FinalBSplineInterpolationOrder"] = ["3"]
|
|
676
|
-
# p["FixedImagePyramid"] = ["FixedSmoothingImagePyramid"] # Smoothing requires 3d dimension at least 4 pixels
|
|
677
|
-
# p["MovingImagePyramid"] = ["MovingSmoothingImagePyramid"]
|
|
678
|
-
p["FixedImagePyramid"] = ["FixedRecursiveImagePyramid"]
|
|
679
|
-
p["MovingImagePyramid"] = ["MovingRecursiveImagePyramid"]
|
|
680
|
-
|
|
681
|
-
# p["Metric"] = ["AdvancedMeanSquares"]
|
|
682
|
-
p["Metric"] = ["AdvancedMattesMutualInformation"]
|
|
683
|
-
p["NumberOfHistogramBins"] = ["32"]
|
|
684
|
-
|
|
685
|
-
# Transformation
|
|
686
|
-
p["Transform"] = ["AffineTransform"]
|
|
687
|
-
p["HowToCombineTransforms"] = ["Compose"]
|
|
688
|
-
p["AutomaticTransformInitialization"] = ["false"]
|
|
689
|
-
p["FinalGridSpacingInPhysicalUnits"] = ["25.0", "25.0"]
|
|
690
|
-
|
|
691
|
-
# Optimizer
|
|
692
|
-
p["Optimizer"] = ["AdaptiveStochasticGradientDescent"]
|
|
693
|
-
p["NumberOfResolutions"] = ["4"]
|
|
694
|
-
p["AutomaticParameterEstimation"] = ["true"]
|
|
695
|
-
p["ASGDParameterEstimationMethod"] = ["Original"]
|
|
696
|
-
p["MaximumNumberOfIterations"] = ["500"]
|
|
697
|
-
p["MaximumStepLength"] = ["1.0"]
|
|
698
|
-
|
|
699
|
-
# Pyramid settings
|
|
700
|
-
#p["ImagePyramidSchedule"] = ["8 8 4 4 2 2 1 1"]
|
|
701
|
-
|
|
702
|
-
# Sampler parameters
|
|
703
|
-
p["NumberOfSpatialSamples"] = ["2048"]
|
|
704
|
-
p["NewSamplesEveryIteration"] = ["true"]
|
|
705
|
-
p["CheckNumberOfSamples"] = ["true"]
|
|
706
|
-
|
|
707
|
-
# Mask settings
|
|
708
|
-
p["ErodeMask"] = ["true"]
|
|
709
|
-
p["ErodeFixedMask"] = ["false"]
|
|
710
|
-
|
|
711
|
-
# Output settings
|
|
712
|
-
p["DefaultPixelValue"] = ["0"]
|
|
713
|
-
p["WriteResultImage"] = ["true"]
|
|
714
|
-
p["ResultImagePixelType"] = ["float"]
|
|
715
|
-
p["ResultImageFormat"] = ["nii"]
|
|
716
|
-
|
|
717
|
-
return p
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
def _default_rigid():
|
|
722
|
-
# https://github.com/SuperElastix/ElastixModelZoo/tree/master/models/Par0064
|
|
723
|
-
|
|
724
|
-
p = sitk.GetDefaultParameterMap("rigid")
|
|
725
|
-
|
|
726
|
-
# ImageTypes
|
|
727
|
-
p["FixedInternalImagePixelType"] = ["float"]
|
|
728
|
-
p["MovingInternalImagePixelType"] = ["float"]
|
|
729
|
-
p["FixedImageDimension"] = ['2']
|
|
730
|
-
p["MovingImageDimension"] = ['2']
|
|
731
|
-
p["UseDirectionCosines"] = ["true"]
|
|
732
|
-
|
|
733
|
-
# Components
|
|
734
|
-
p["Registration"] = ["MultiResolutionRegistration"]
|
|
735
|
-
p["ImageSampler"] = ["Random"]
|
|
736
|
-
p["Interpolator"] = ["BSplineInterpolator"]
|
|
737
|
-
p["ResampleInterpolator"] = ["FinalBSplineInterpolator"]
|
|
738
|
-
p["Resampler"] = ["DefaultResampler"]
|
|
739
|
-
p["BSplineInterpolationOrder"] = ["1"]
|
|
740
|
-
p["FinalBSplineInterpolationOrder"] = ["3"]
|
|
741
|
-
# p["FixedImagePyramid"] = ["FixedSmoothingImagePyramid"] # Smoothing requires 3d dimension at least 4 pixels
|
|
742
|
-
# p["MovingImagePyramid"] = ["MovingSmoothingImagePyramid"]
|
|
743
|
-
p["FixedImagePyramid"] = ["FixedRecursiveImagePyramid"]
|
|
744
|
-
p["MovingImagePyramid"] = ["MovingRecursiveImagePyramid"]
|
|
745
|
-
|
|
746
|
-
# Pyramid settings
|
|
747
|
-
#p["ImagePyramidSchedule"] = ["8 8 4 4 4 2 2 2 1"]
|
|
748
|
-
p["Optimizer"] = ["AdaptiveStochasticGradientDescent"]
|
|
749
|
-
|
|
750
|
-
# Transformation
|
|
751
|
-
p["HowToCombineTransforms"] = ["Compose"]
|
|
752
|
-
p["Transform"] = ["EulerTransform"]
|
|
753
|
-
p["AutomaticTransformInitialization"] = ["true"]
|
|
754
|
-
p["AutomaticTransformInitializationMethod"] = ["GeometricalCenter"]
|
|
755
|
-
p["AutomaticScalesEstimation"] = ["true"]
|
|
756
|
-
p["Metric"] = ["AdvancedMattesMutualInformation"]
|
|
757
|
-
p["NumberOfHistogramBins"] = ["32"]
|
|
758
|
-
|
|
759
|
-
# Optimizer settings
|
|
760
|
-
p["NumberOfResolutions"] = ["3"]
|
|
761
|
-
p["AutomaticParameterEstimation"] = ["true"]
|
|
762
|
-
# p["ASGDParameterEstimationMethod"] = ["Original"]
|
|
763
|
-
p["MaximumNumberOfIterations"] = ["500"]
|
|
764
|
-
p["MaximumStepLength"] = ["1.0"]
|
|
765
|
-
|
|
766
|
-
# Sampler parameters
|
|
767
|
-
p["NumberOfSpatialSamples"] = ["2048"]
|
|
768
|
-
p["NewSamplesEveryIteration"] = ["true"]
|
|
769
|
-
p["NumberOfSamplesForExactGradient"] = ["1024"]
|
|
770
|
-
p["MaximumNumberOfSamplingAttempts"] = ["15"]
|
|
771
|
-
p["CheckNumberOfSamples"] = ["true"]
|
|
772
|
-
|
|
773
|
-
# Mask settings
|
|
774
|
-
p["ErodeMask"] = ["true"]
|
|
775
|
-
# p["ErodeFixedMask"] = ["false"]
|
|
776
|
-
|
|
777
|
-
# Output settings
|
|
778
|
-
p["DefaultPixelValue"] = ["0"]
|
|
779
|
-
p["WriteResultImage"] = ["true"]
|
|
780
|
-
p["ResultImagePixelType"] = ["float"]
|
|
781
|
-
p["ResultImageFormat"] = ["nii"]
|
|
782
|
-
|
|
783
|
-
return p
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
def _default_2d_to_3d():
|
|
787
|
-
# modified from:
|
|
788
|
-
# https://github.com/SuperElastix/ElastixModelZoo/tree/master/models/Par0013
|
|
789
|
-
|
|
790
|
-
p = sitk.GetDefaultParameterMap("rigid")
|
|
791
|
-
|
|
792
|
-
p['FixedInternalImagePixelType'] = ["float"]
|
|
793
|
-
p['MovingInternalImagePixelType'] = ["float"]
|
|
794
|
-
p['FixedImageDimension'] = ['3']
|
|
795
|
-
p['MovingImageDimension'] = ['3']
|
|
796
|
-
p['UseDirectionCosines"'] = ["false"]
|
|
797
|
-
|
|
798
|
-
# **************** Main Components **************************
|
|
799
|
-
|
|
800
|
-
p['Registration'] = ["MultiResolutionRegistration"]
|
|
801
|
-
#p['Interpolator'] = ["RayCastInterpolator"]
|
|
802
|
-
#p['ResampleInterpolator'] = ["FinalRayCastInterpolator"]
|
|
803
|
-
p['Resampler'] = ["DefaultResampler"]
|
|
804
|
-
|
|
805
|
-
p['FixedImagePyramid'] = ["FixedRecursiveImagePyramid"]
|
|
806
|
-
p['MovingImagePyramid'] = ["MovingRecursiveImagePyramid"]
|
|
807
|
-
|
|
808
|
-
#p['Optimizer'] = ["Powell"]
|
|
809
|
-
p['Transform'] = ["EulerTransform"]
|
|
810
|
-
p['Metric'] = ["GradientDifference"]
|
|
811
|
-
|
|
812
|
-
# ***************** Transformation **************************
|
|
813
|
-
|
|
814
|
-
#p['Scales'] = ['57.3']
|
|
815
|
-
#p['AutomaticTransformInitialization'] = ["false"]
|
|
816
|
-
p['AutomaticTransformInitialization'] = ["true"]
|
|
817
|
-
p["AutomaticTransformInitializationMethod"] = ["GeometricalCenter"]
|
|
818
|
-
p["AutomaticScalesEstimation"] = ["true"]
|
|
819
|
-
p['HowToCombineTransforms'] = ["Compose"]
|
|
820
|
-
p['CenterOfRotationPoint'] = ['0.0 0.0 0.0']
|
|
821
|
-
|
|
822
|
-
# ******************* Similarity measure *********************
|
|
823
|
-
|
|
824
|
-
p['UseNormalization'] = ["true"]
|
|
825
|
-
|
|
826
|
-
# ******************** Multiresolution **********************
|
|
827
|
-
|
|
828
|
-
p['NumberOfResolutions'] = ['1']
|
|
829
|
-
|
|
830
|
-
# ******************* Optimizer ****************************
|
|
831
|
-
|
|
832
|
-
p['MaximumNumberOfIterations'] = ['10']
|
|
833
|
-
p['MaximumStepLength'] = ['1.0']
|
|
834
|
-
p['StepTolerance'] = ['0.0001']
|
|
835
|
-
p['ValueTolerance'] = ['0.000001']
|
|
836
|
-
|
|
837
|
-
# **************** Image sampling **********************
|
|
838
|
-
|
|
839
|
-
#p['ImageSampler'] = ["Full"]
|
|
840
|
-
p['NewSamplesEveryIteration'] = ["false"]
|
|
841
|
-
|
|
842
|
-
# ************* Interpolation and Resampling ****************
|
|
843
|
-
|
|
844
|
-
#p['Origin'] = ['-145.498 -146.889 381.766']
|
|
845
|
-
#p['Interpolator0PreParameters'] = ['-0.009475 -0.006807 -0.030067 0.0 0.0 0.0']
|
|
846
|
-
#p['ResampleInterpolator0PreParameters'] = ['-0.009475 -0.006807 -0.030067 0.0 0.0 0.0']
|
|
847
|
-
#p['Interpolator0FocalPoint'] = ['0.54 -0.85 -813.234']
|
|
848
|
-
#p['ResampleInterpolator0FocalPoint'] = ['0.54 -0.85 -813.234']
|
|
849
|
-
p['Threshold'] = ['1000']
|
|
850
|
-
p['DefaultPixelValue'] = ['0']
|
|
851
|
-
p['WriteResultImage'] = ["true"]
|
|
852
|
-
#p['WriteTransformParametersEachIteration'] = ["true"]
|
|
853
|
-
p['ResultImagePixelType'] = ["float"]
|
|
854
|
-
|
|
855
|
-
return p
|