dbdicom 0.2.6__py3-none-any.whl → 0.3.1__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.
Potentially problematic release.
This version of dbdicom might be problematic. Click here for more details.
- dbdicom/__init__.py +1 -28
- dbdicom/api.py +287 -0
- dbdicom/const.py +144 -0
- dbdicom/dataset.py +721 -0
- dbdicom/dbd.py +736 -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/register.py +527 -0
- dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
- dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +153 -26
- dbdicom/{ds/types → sop_classes}/mr_image.py +185 -140
- dbdicom/sop_classes/parametric_map.py +310 -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 +36 -0
- dbdicom/utils/files.py +0 -20
- dbdicom/utils/image.py +10 -629
- dbdicom-0.3.1.dist-info/METADATA +28 -0
- dbdicom-0.3.1.dist-info/RECORD +53 -0
- dbdicom/create.py +0 -457
- dbdicom/dro.py +0 -174
- dbdicom/ds/__init__.py +0 -10
- dbdicom/ds/create.py +0 -63
- dbdicom/ds/dataset.py +0 -869
- dbdicom/ds/dictionaries.py +0 -620
- dbdicom/ds/types/parametric_map.py +0 -226
- dbdicom/extensions/__init__.py +0 -9
- dbdicom/extensions/dipy.py +0 -448
- dbdicom/extensions/elastix.py +0 -503
- dbdicom/extensions/matplotlib.py +0 -107
- dbdicom/extensions/numpy.py +0 -271
- dbdicom/extensions/scipy.py +0 -1512
- dbdicom/extensions/skimage.py +0 -1030
- dbdicom/extensions/sklearn.py +0 -243
- dbdicom/extensions/vreg.py +0 -1390
- dbdicom/manager.py +0 -2132
- dbdicom/message.py +0 -119
- dbdicom/pipelines.py +0 -66
- dbdicom/record.py +0 -1893
- dbdicom/types/database.py +0 -107
- dbdicom/types/instance.py +0 -231
- dbdicom/types/patient.py +0 -40
- dbdicom/types/series.py +0 -2874
- dbdicom/types/study.py +0 -58
- dbdicom-0.2.6.dist-info/METADATA +0 -72
- dbdicom-0.2.6.dist-info/RECORD +0 -66
- {dbdicom-0.2.6.dist-info → dbdicom-0.3.1.dist-info}/WHEEL +0 -0
- {dbdicom-0.2.6.dist-info → dbdicom-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {dbdicom-0.2.6.dist-info → dbdicom-0.3.1.dist-info}/top_level.txt +0 -0
dbdicom/extensions/elastix.py
DELETED
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
# pip install SimpleITK-SimpleElastix
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import itk
|
|
5
|
-
from skimage.measure import block_reduce
|
|
6
|
-
from dbdicom.extensions import vreg
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def coregister_3d_to_3d(moving, fixed,
|
|
10
|
-
transformation = 'Affine',
|
|
11
|
-
metric = "NormalizedMutualInformation",
|
|
12
|
-
final_grid_spacing = 1.0,
|
|
13
|
-
apply_to = []):
|
|
14
|
-
|
|
15
|
-
background = 2**16-1
|
|
16
|
-
fixed_map = vreg.map_to(fixed, moving, cval=background)
|
|
17
|
-
|
|
18
|
-
# Get arrays for fixed and moving series
|
|
19
|
-
array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
20
|
-
array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
21
|
-
|
|
22
|
-
# Remove temporary overlay
|
|
23
|
-
if fixed_map != fixed:
|
|
24
|
-
fixed_map.remove()
|
|
25
|
-
|
|
26
|
-
# Set background pixels to zero for both images
|
|
27
|
-
idx = np.where(array_fixed==background)
|
|
28
|
-
array_fixed[idx] = 0
|
|
29
|
-
array_moving[idx] = 0
|
|
30
|
-
|
|
31
|
-
# Apply coregistration settings
|
|
32
|
-
moving.message('Preparing coregistration..')
|
|
33
|
-
if transformation == 'Rigid':
|
|
34
|
-
pars = _default_rigid('3')
|
|
35
|
-
elif transformation == 'Affine':
|
|
36
|
-
pars = _default_affine('3')
|
|
37
|
-
else:
|
|
38
|
-
pars = _default_bspline('3')
|
|
39
|
-
pars.SetParameter("Metric", metric)
|
|
40
|
-
pars.SetParameter("FinalGridSpacingInPhysicalUnits", str(final_grid_spacing))
|
|
41
|
-
|
|
42
|
-
# Get slice spacing
|
|
43
|
-
slice_spacing = headers_moving[0].SpacingBetweenSlices
|
|
44
|
-
if slice_spacing is None:
|
|
45
|
-
slice_spacing = headers_moving[0].SliceThickness
|
|
46
|
-
pixel_spacing = headers_moving[0].PixelSpacing + [slice_spacing]
|
|
47
|
-
|
|
48
|
-
# Coregister and save as DICOM
|
|
49
|
-
coregistered, params = _coregister_arrays_3d(
|
|
50
|
-
array_fixed, array_moving,
|
|
51
|
-
pars, pixel_spacing,
|
|
52
|
-
return_deformation_field=False)
|
|
53
|
-
coreg = moving.new_sibling(suffix='coreg')
|
|
54
|
-
coreg.set_array(coregistered, headers_moving, pixels_first=True)
|
|
55
|
-
|
|
56
|
-
# Apply the transformation to other series
|
|
57
|
-
apply_to_coreg = []
|
|
58
|
-
for s, series in enumerate(apply_to):
|
|
59
|
-
moving.progress(s+1, len(apply_to), 'Applying transformation..')
|
|
60
|
-
array, headers = series.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
61
|
-
if array.shape != array_moving.shape:
|
|
62
|
-
msg = 'Cannot apply the same transformation to other series with a different shape'
|
|
63
|
-
raise ValueError(msg)
|
|
64
|
-
array = _apply_3d_transformation(array, params, pixel_spacing)
|
|
65
|
-
new = series.new_sibling(suffix='coreg')
|
|
66
|
-
new.set_array(array, headers, pixels_first=True)
|
|
67
|
-
apply_to_coreg.append(new)
|
|
68
|
-
|
|
69
|
-
return coreg, apply_to_coreg
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def coregister_2d_to_2d(moving, fixed,
|
|
75
|
-
transformation = 'Affine',
|
|
76
|
-
metric = "NormalizedMutualInformation",
|
|
77
|
-
final_grid_spacing = 1.0,
|
|
78
|
-
):
|
|
79
|
-
|
|
80
|
-
background = 2**16-1
|
|
81
|
-
fixed_map = vreg.map_to(fixed, moving, cval=background)
|
|
82
|
-
|
|
83
|
-
# Get arrays for fixed and moving series
|
|
84
|
-
array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
85
|
-
array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
|
|
86
|
-
|
|
87
|
-
# Remove temporary overlay
|
|
88
|
-
if fixed_map != fixed:
|
|
89
|
-
fixed_map.remove()
|
|
90
|
-
|
|
91
|
-
# Set background pixels to zero for both images
|
|
92
|
-
idx = np.where(array_fixed==background)
|
|
93
|
-
array_fixed[idx] = 0
|
|
94
|
-
array_moving[idx] = 0
|
|
95
|
-
|
|
96
|
-
# Get coregistration settings
|
|
97
|
-
moving.message('Setting up coregistration..')
|
|
98
|
-
if transformation == 'Rigid':
|
|
99
|
-
pars = _default_rigid('2')
|
|
100
|
-
elif transformation == 'Affine':
|
|
101
|
-
pars = _default_affine('2')
|
|
102
|
-
else:
|
|
103
|
-
pars = _default_bspline('2')
|
|
104
|
-
pars.SetParameter("Metric", metric)
|
|
105
|
-
pars.SetParameter("FinalGridSpacingInPhysicalUnits", str(final_grid_spacing))
|
|
106
|
-
|
|
107
|
-
# Coregister fixed and moving slice-by-slice
|
|
108
|
-
pixel_spacing = headers_moving[0].PixelSpacing
|
|
109
|
-
for z in range(array_moving.shape[2]):
|
|
110
|
-
moving.status.progress(z+1, array_moving.shape[2], 'Performing coregistration..')
|
|
111
|
-
coreg = _coregister_arrays(array_fixed[:,:,z], array_moving[:,:,z], pars, pixel_spacing, return_deformation_field=False)
|
|
112
|
-
array_moving[:,:,z] = coreg
|
|
113
|
-
|
|
114
|
-
# Save as DICOM
|
|
115
|
-
coreg = moving.new_sibling(suffix='coregistered')
|
|
116
|
-
coreg.set_array(array_moving, headers_moving, pixels_first=True)
|
|
117
|
-
return coreg
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
# BELOW HERE NON-DICOM FUNCTIONALITY
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# 3D version does not have the downsampling option
|
|
129
|
-
# some bug involving the image shaping
|
|
130
|
-
def _coregister_arrays_3d(
|
|
131
|
-
target, source,
|
|
132
|
-
elastix_model_parameters,
|
|
133
|
-
spacing,
|
|
134
|
-
log=False,
|
|
135
|
-
return_deformation_field=False):
|
|
136
|
-
|
|
137
|
-
# Convert to itk images
|
|
138
|
-
source = itk.GetImageFromArray(np.array(source, np.float32))
|
|
139
|
-
target = itk.GetImageFromArray(np.array(target, np.float32))
|
|
140
|
-
source.SetSpacing(spacing)
|
|
141
|
-
target.SetSpacing(spacing)
|
|
142
|
-
|
|
143
|
-
# Coregister source to target
|
|
144
|
-
coreg, result_transform_parameters = itk.elastix_registration_method(
|
|
145
|
-
target, source,
|
|
146
|
-
parameter_object=elastix_model_parameters,
|
|
147
|
-
log_to_console=log)
|
|
148
|
-
coreg = itk.GetArrayFromImage(coreg)
|
|
149
|
-
|
|
150
|
-
if not return_deformation_field:
|
|
151
|
-
return coreg, result_transform_parameters
|
|
152
|
-
|
|
153
|
-
# Get deformation field
|
|
154
|
-
deformation_field = itk.transformix_deformation_field(
|
|
155
|
-
target, result_transform_parameters,
|
|
156
|
-
log_to_console=log)
|
|
157
|
-
deformation_field = itk.GetArrayFromImage(deformation_field)
|
|
158
|
-
return coreg, result_transform_parameters, deformation_field
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def _apply_3d_transformation(
|
|
162
|
-
source, result_transform_parameters,
|
|
163
|
-
spacing, log=False):
|
|
164
|
-
|
|
165
|
-
source = itk.GetImageFromArray(np.array(source, np.float32))
|
|
166
|
-
source.SetSpacing(spacing)
|
|
167
|
-
coreg = itk.transformix_filter(
|
|
168
|
-
source, result_transform_parameters,
|
|
169
|
-
log_to_console=log)
|
|
170
|
-
return itk.GetArrayFromImage(coreg)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
def _coregister_arrays(
|
|
176
|
-
target_large,
|
|
177
|
-
source_large,
|
|
178
|
-
elastix_model_parameters,
|
|
179
|
-
spacing_large,
|
|
180
|
-
log=False,
|
|
181
|
-
downsample:int=1,
|
|
182
|
-
return_deformation_field=False):
|
|
183
|
-
|
|
184
|
-
# Downsample source and target
|
|
185
|
-
# The origin of an image is the center of the voxel in the lower left corner
|
|
186
|
-
# The origin of the large image is (0,0).
|
|
187
|
-
# The original of the small image is therefore:
|
|
188
|
-
# spacing_large/2 + (spacing_small/2 - spacing_large)
|
|
189
|
-
# = (spacing_small - spacing_large)/2
|
|
190
|
-
target_small = block_reduce(target_large, block_size=downsample, func=np.mean)
|
|
191
|
-
source_small = block_reduce(source_large, block_size=downsample, func=np.mean)
|
|
192
|
-
spacing_small = [spacing*downsample for spacing in spacing_large]
|
|
193
|
-
origin_large = [0] * len(spacing_large)
|
|
194
|
-
origin_small = [(spacing_small[i] - spacing_large[i])/2 for i in range(len(spacing_small))]
|
|
195
|
-
|
|
196
|
-
# Coregister downsampled source to target
|
|
197
|
-
source_small = itk.GetImageFromArray(np.array(source_small, np.float32))
|
|
198
|
-
target_small = itk.GetImageFromArray(np.array(target_small, np.float32))
|
|
199
|
-
source_small.SetSpacing(spacing_small)
|
|
200
|
-
target_small.SetSpacing(spacing_small)
|
|
201
|
-
source_small.SetOrigin(origin_small)
|
|
202
|
-
target_small.SetOrigin(origin_small)
|
|
203
|
-
coreg_small, result_transform_parameters = itk.elastix_registration_method(
|
|
204
|
-
target_small, source_small,
|
|
205
|
-
parameter_object=elastix_model_parameters,
|
|
206
|
-
log_to_console=log)
|
|
207
|
-
|
|
208
|
-
# Get coregistered image at original size
|
|
209
|
-
result_transform_parameters.SetParameter(0, "Size", [str(dim) for dim in source_large.shape])
|
|
210
|
-
result_transform_parameters.SetParameter(0, "Spacing", [str(dim) for dim in spacing_large])
|
|
211
|
-
source_large = itk.GetImageFromArray(np.array(source_large, np.float32))
|
|
212
|
-
source_large.SetSpacing(spacing_large)
|
|
213
|
-
source_large.SetOrigin(origin_large)
|
|
214
|
-
coreg_large = itk.transformix_filter(
|
|
215
|
-
source_large,
|
|
216
|
-
result_transform_parameters,
|
|
217
|
-
log_to_console=log)
|
|
218
|
-
coreg_large = itk.GetArrayFromImage(coreg_large)
|
|
219
|
-
if coreg_large.ndim==3:
|
|
220
|
-
coreg_large = np.transpose(coreg_large, (1,2,0))
|
|
221
|
-
|
|
222
|
-
if not return_deformation_field:
|
|
223
|
-
return coreg_large
|
|
224
|
-
|
|
225
|
-
# Get deformation field at original size
|
|
226
|
-
target_large = itk.GetImageFromArray(np.array(target_large, np.float32))
|
|
227
|
-
target_large.SetSpacing(spacing_large)
|
|
228
|
-
target_large.SetOrigin(origin_large)
|
|
229
|
-
deformation_field = itk.transformix_deformation_field(
|
|
230
|
-
target_large,
|
|
231
|
-
result_transform_parameters,
|
|
232
|
-
log_to_console=log)
|
|
233
|
-
deformation_field = itk.GetArrayFromImage(deformation_field)
|
|
234
|
-
if deformation_field.ndim==4:
|
|
235
|
-
deformation_field = np.transpose(deformation_field, (1,2,0,3))
|
|
236
|
-
else:
|
|
237
|
-
deformation_field = np.reshape(deformation_field, target_large.shape + (len(target_large.shape), ))
|
|
238
|
-
return coreg_large, deformation_field
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
def _default_bspline(d):
|
|
242
|
-
param_obj = itk.ParameterObject.New()
|
|
243
|
-
parameter_map_bspline = param_obj.GetDefaultParameterMap('bspline')
|
|
244
|
-
## add parameter map file to the parameter object: required in itk-elastix
|
|
245
|
-
param_obj.AddParameterMap(parameter_map_bspline)
|
|
246
|
-
#OPTIONAL: Write the default parameter file to output file
|
|
247
|
-
# param_obj.WriteParameterFile(parameter_map_bspline, "bspline.default.txt")
|
|
248
|
-
# *********************
|
|
249
|
-
# * ImageTypes
|
|
250
|
-
# *********************
|
|
251
|
-
param_obj.SetParameter("FixedInternalImagePixelType", "float")
|
|
252
|
-
param_obj.SetParameter("MovingInternalImagePixelType", "float")
|
|
253
|
-
## selection based on 3D or 2D image data: newest elastix version does not require input image dimension
|
|
254
|
-
param_obj.SetParameter("FixedImageDimension", d)
|
|
255
|
-
param_obj.SetParameter("MovingImageDimension", d)
|
|
256
|
-
param_obj.SetParameter("UseDirectionCosines", "true")
|
|
257
|
-
# *********************
|
|
258
|
-
# * Components
|
|
259
|
-
# *********************
|
|
260
|
-
param_obj.SetParameter("Registration", "MultiResolutionRegistration")
|
|
261
|
-
# Image intensities are sampled using an ImageSampler, Interpolator and ResampleInterpolator.
|
|
262
|
-
# Image sampler is responsible for selecting points in the image to sample.
|
|
263
|
-
# The RandomCoordinate simply selects random positions.
|
|
264
|
-
param_obj.SetParameter("ImageSampler", "RandomCoordinate")
|
|
265
|
-
# Interpolator is responsible for interpolating off-grid positions during optimization.
|
|
266
|
-
# The BSplineInterpolator with BSplineInterpolationOrder = 1 used here is very fast and uses very little memory
|
|
267
|
-
param_obj.SetParameter("Interpolator", "BSplineInterpolator")
|
|
268
|
-
# ResampleInterpolator here chosen to be FinalBSplineInterpolator with FinalBSplineInterpolationOrder = 1
|
|
269
|
-
# is used to resample the result image from the moving image once the final transformation has been found.
|
|
270
|
-
# This is a one-time step so the additional computational complexity is worth the trade-off for higher image quality.
|
|
271
|
-
param_obj.SetParameter("ResampleInterpolator", "FinalBSplineInterpolator")
|
|
272
|
-
param_obj.SetParameter("Resampler", "DefaultResampler")
|
|
273
|
-
# Order of B-Spline interpolation used during registration/optimisation.
|
|
274
|
-
# It may improve accuracy if you set this to 3. Never use 0.
|
|
275
|
-
# An order of 1 gives linear interpolation. This is in most
|
|
276
|
-
# applications a good choice.
|
|
277
|
-
param_obj.SetParameter("BSplineInterpolationOrder", "1")
|
|
278
|
-
# Order of B-Spline interpolation used for applying the final
|
|
279
|
-
# deformation.
|
|
280
|
-
# 3 gives good accuracy; recommended in most cases.
|
|
281
|
-
# 1 gives worse accuracy (linear interpolation)
|
|
282
|
-
# 0 gives worst accuracy, but is appropriate for binary images
|
|
283
|
-
# (masks, segmentations); equivalent to nearest neighbor interpolation.
|
|
284
|
-
param_obj.SetParameter("FinalBSplineInterpolationOrder", "3")
|
|
285
|
-
# Pyramids found in Elastix:
|
|
286
|
-
# 1) Smoothing -> Smoothing: YES, Downsampling: NO
|
|
287
|
-
# 2) Recursive -> Smoothing: YES, Downsampling: YES
|
|
288
|
-
# If Recursive is chosen and only # of resolutions is given
|
|
289
|
-
# then downsamlping by a factor of 2 (default)
|
|
290
|
-
# 3) Shrinking -> Smoothing: NO, Downsampling: YES
|
|
291
|
-
param_obj.SetParameter("FixedImagePyramid", "FixedSmoothingImagePyramid")
|
|
292
|
-
param_obj.SetParameter("MovingImagePyramid", "MovingSmoothingImagePyramid")
|
|
293
|
-
param_obj.SetParameter("Optimizer", "AdaptiveStochasticGradientDescent")
|
|
294
|
-
# Whether transforms are combined by composition or by addition.
|
|
295
|
-
# In generally, Compose is the best option in most cases.
|
|
296
|
-
# It does not influence the results very much.
|
|
297
|
-
param_obj.SetParameter("HowToCombineTransforms", "Compose")
|
|
298
|
-
param_obj.SetParameter("Transform", "BSplineTransform")
|
|
299
|
-
# Metric
|
|
300
|
-
param_obj.SetParameter("Metric", "NormalizedMutualInformation")
|
|
301
|
-
# Number of grey level bins in each resolution level,
|
|
302
|
-
# for the mutual information. 16 or 32 usually works fine.
|
|
303
|
-
# You could also employ a hierarchical strategy:
|
|
304
|
-
#(NumberOfHistogramBins 16 32 64)
|
|
305
|
-
param_obj.SetParameter("NumberOfHistogramBins", "32")
|
|
306
|
-
# *********************
|
|
307
|
-
# * Transformation
|
|
308
|
-
# *********************
|
|
309
|
-
# The control point spacing of the bspline transformation in
|
|
310
|
-
# the finest resolution level. Can be specified for each
|
|
311
|
-
# dimension differently. Unit: mm.
|
|
312
|
-
# The lower this value, the more flexible the deformation.
|
|
313
|
-
# Low values may improve the accuracy, but may also cause
|
|
314
|
-
# unrealistic deformations.
|
|
315
|
-
# By default the grid spacing is halved after every resolution,
|
|
316
|
-
# such that the final grid spacing is obtained in the last
|
|
317
|
-
# resolution level.
|
|
318
|
-
# The grid spacing here is specified in voxel units.
|
|
319
|
-
#(FinalGridSpacingInPhysicalUnits 10.0 10.0)
|
|
320
|
-
#(FinalGridSpacingInVoxels 8)
|
|
321
|
-
#param_obj.SetParameter("FinalGridSpacingInPhysicalUnits", ["50.0", "50.0"])
|
|
322
|
-
param_obj.SetParameter("FinalGridSpacingInPhysicalUnits", "25.0")
|
|
323
|
-
# *********************
|
|
324
|
-
# * Optimizer settings
|
|
325
|
-
# *********************
|
|
326
|
-
# The number of resolutions. 1 Is only enough if the expected
|
|
327
|
-
# deformations are small. 3 or 4 mostly works fine. For large
|
|
328
|
-
# images and large deformations, 5 or 6 may even be useful.
|
|
329
|
-
param_obj.SetParameter("NumberOfResolutions", "4")
|
|
330
|
-
param_obj.SetParameter("AutomaticParameterEstimation", "true")
|
|
331
|
-
param_obj.SetParameter("ASGDParameterEstimationMethod", "Original")
|
|
332
|
-
param_obj.SetParameter("MaximumNumberOfIterations", "500")
|
|
333
|
-
# The step size of the optimizer, in mm. By default the voxel size is used.
|
|
334
|
-
# which usually works well. In case of unusual high-resolution images
|
|
335
|
-
# (eg histology) it is necessary to increase this value a bit, to the size
|
|
336
|
-
# of the "smallest visible structure" in the image:
|
|
337
|
-
param_obj.SetParameter("MaximumStepLength", "0.1")
|
|
338
|
-
# *********************
|
|
339
|
-
# * Pyramid settings
|
|
340
|
-
# *********************
|
|
341
|
-
# The downsampling/blurring factors for the image pyramids.
|
|
342
|
-
# By default, the images are downsampled by a factor of 2
|
|
343
|
-
# compared to the next resolution.
|
|
344
|
-
#param_obj.SetParameter("ImagePyramidSchedule", "8 8 4 4 2 2 1 1")
|
|
345
|
-
# *********************
|
|
346
|
-
# * Sampler parameters
|
|
347
|
-
# *********************
|
|
348
|
-
# Number of spatial samples used to compute the mutual
|
|
349
|
-
# information (and its derivative) in each iteration.
|
|
350
|
-
# With an AdaptiveStochasticGradientDescent optimizer,
|
|
351
|
-
# in combination with the two options below, around 2000
|
|
352
|
-
# samples may already suffice.
|
|
353
|
-
param_obj.SetParameter("NumberOfSpatialSamples", "2048")
|
|
354
|
-
# Refresh these spatial samples in every iteration, and select
|
|
355
|
-
# them randomly. See the manual for information on other sampling
|
|
356
|
-
# strategies.
|
|
357
|
-
param_obj.SetParameter("NewSamplesEveryIteration", "true")
|
|
358
|
-
param_obj.SetParameter("CheckNumberOfSamples", "true")
|
|
359
|
-
# *********************
|
|
360
|
-
# * Mask settings
|
|
361
|
-
# *********************
|
|
362
|
-
# If you use a mask, this option is important.
|
|
363
|
-
# If the mask serves as region of interest, set it to false.
|
|
364
|
-
# If the mask indicates which pixels are valid, then set it to true.
|
|
365
|
-
# If you do not use a mask, the option doesn't matter.
|
|
366
|
-
param_obj.SetParameter("ErodeMask", "false")
|
|
367
|
-
param_obj.SetParameter("ErodeFixedMask", "false")
|
|
368
|
-
# *********************
|
|
369
|
-
# * Output settings
|
|
370
|
-
# *********************
|
|
371
|
-
#Default pixel value for pixels that come from outside the picture:
|
|
372
|
-
param_obj.SetParameter("DefaultPixelValue", "0")
|
|
373
|
-
# Choose whether to generate the deformed moving image.
|
|
374
|
-
# You can save some time by setting this to false, if you are
|
|
375
|
-
# not interested in the final deformed moving image, but only
|
|
376
|
-
# want to analyze the deformation field for example.
|
|
377
|
-
param_obj.SetParameter("WriteResultImage", "true")
|
|
378
|
-
# The pixel type and format of the resulting deformed moving image
|
|
379
|
-
param_obj.SetParameter("ResultImagePixelType", "float")
|
|
380
|
-
param_obj.SetParameter("ResultImageFormat", "nii")
|
|
381
|
-
|
|
382
|
-
return param_obj
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
def _default_affine(d):
|
|
386
|
-
param_obj = itk.ParameterObject.New()
|
|
387
|
-
parameter_map_bspline = param_obj.GetDefaultParameterMap('affine')
|
|
388
|
-
param_obj.AddParameterMap(parameter_map_bspline)
|
|
389
|
-
|
|
390
|
-
# ImageTypes
|
|
391
|
-
param_obj.SetParameter("FixedInternalImagePixelType", "float")
|
|
392
|
-
param_obj.SetParameter("MovingInternalImagePixelType", "float")
|
|
393
|
-
param_obj.SetParameter("FixedImageDimension", d)
|
|
394
|
-
param_obj.SetParameter("MovingImageDimension", d)
|
|
395
|
-
param_obj.SetParameter("UseDirectionCosines", "true")
|
|
396
|
-
|
|
397
|
-
# Components
|
|
398
|
-
param_obj.SetParameter("Registration", "MultiResolutionRegistration")
|
|
399
|
-
param_obj.SetParameter("ImageSampler", "Random")
|
|
400
|
-
param_obj.SetParameter("Interpolator", "BSplineInterpolator")
|
|
401
|
-
param_obj.SetParameter("ResampleInterpolator", "FinalBSplineInterpolator")
|
|
402
|
-
param_obj.SetParameter("Resampler", "DefaultResampler")
|
|
403
|
-
param_obj.SetParameter("BSplineInterpolationOrder", "3")
|
|
404
|
-
param_obj.SetParameter("FinalBSplineInterpolationOrder", "3")
|
|
405
|
-
param_obj.SetParameter("FixedImagePyramid", "FixedRecursiveImagePyramid")
|
|
406
|
-
param_obj.SetParameter("MovingImagePyramid", "MovingRecursiveImagePyramid")
|
|
407
|
-
|
|
408
|
-
# Metric
|
|
409
|
-
param_obj.SetParameter("Metric", "AdvancedMattesMutualInformation")
|
|
410
|
-
param_obj.SetParameter("NumberOfHistogramBins", "32")
|
|
411
|
-
|
|
412
|
-
# Transformation
|
|
413
|
-
param_obj.SetParameter("Transform", "AffineTransform")
|
|
414
|
-
param_obj.SetParameter("HowToCombineTransforms", "Compose")
|
|
415
|
-
param_obj.SetParameter("AutomaticTransformInitialization", "false")
|
|
416
|
-
param_obj.SetParameter("FinalGridSpacingInPhysicalUnits", "25.0")
|
|
417
|
-
|
|
418
|
-
# Optimizer
|
|
419
|
-
param_obj.SetParameter("Optimizer", "AdaptiveStochasticGradientDescent")
|
|
420
|
-
param_obj.SetParameter("NumberOfResolutions", "4")
|
|
421
|
-
param_obj.SetParameter("AutomaticParameterEstimation", "true")
|
|
422
|
-
param_obj.SetParameter("ASGDParameterEstimationMethod", "Original")
|
|
423
|
-
param_obj.SetParameter("MaximumNumberOfIterations", "500")
|
|
424
|
-
param_obj.SetParameter("MaximumStepLength", "1.0")
|
|
425
|
-
|
|
426
|
-
# Pyramid settings
|
|
427
|
-
param_obj.SetParameter("NumberOfSpatialSamples", "2048")
|
|
428
|
-
param_obj.SetParameter("NewSamplesEveryIteration", "true")
|
|
429
|
-
param_obj.SetParameter("CheckNumberOfSamples", "true")
|
|
430
|
-
|
|
431
|
-
# Mask settings
|
|
432
|
-
param_obj.SetParameter("ErodeMask", "false")
|
|
433
|
-
param_obj.SetParameter("ErodeFixedMask", "false")
|
|
434
|
-
|
|
435
|
-
# Output settings
|
|
436
|
-
param_obj.SetParameter("DefaultPixelValue", "0")
|
|
437
|
-
param_obj.SetParameter("WriteResultImage", "true")
|
|
438
|
-
param_obj.SetParameter("ResultImagePixelType", "float")
|
|
439
|
-
param_obj.SetParameter("ResultImageFormat", "nii")
|
|
440
|
-
|
|
441
|
-
return param_obj
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
def _default_rigid(d):
|
|
445
|
-
param_obj = itk.ParameterObject.New()
|
|
446
|
-
parameter_map_bspline = param_obj.GetDefaultParameterMap('rigid')
|
|
447
|
-
param_obj.AddParameterMap(parameter_map_bspline)
|
|
448
|
-
|
|
449
|
-
# ImageTypes
|
|
450
|
-
param_obj.SetParameter("FixedInternalImagePixelType", "float")
|
|
451
|
-
param_obj.SetParameter("MovingInternalImagePixelType", "float")
|
|
452
|
-
param_obj.SetParameter("FixedImageDimension", d)
|
|
453
|
-
param_obj.SetParameter("MovingImageDimension", d)
|
|
454
|
-
param_obj.SetParameter("UseDirectionCosines", "true")
|
|
455
|
-
|
|
456
|
-
# Components
|
|
457
|
-
param_obj.SetParameter("Registration", "MultiResolutionRegistration")
|
|
458
|
-
param_obj.SetParameter("ImageSampler", "Random")
|
|
459
|
-
param_obj.SetParameter("Interpolator", "BSplineInterpolator")
|
|
460
|
-
param_obj.SetParameter("ResampleInterpolator", "FinalBSplineInterpolator")
|
|
461
|
-
param_obj.SetParameter("Resampler", "DefaultResampler")
|
|
462
|
-
param_obj.SetParameter("BSplineInterpolationOrder", "1")
|
|
463
|
-
param_obj.SetParameter("FinalBSplineInterpolationOrder", "3")
|
|
464
|
-
param_obj.SetParameter("FixedImagePyramid", "FixedRecursiveImagePyramid")
|
|
465
|
-
param_obj.SetParameter("MovingImagePyramid", "MovingRecursiveImagePyramid")
|
|
466
|
-
param_obj.SetParameter("Optimizer", "AdaptiveStochasticGradientDescent")
|
|
467
|
-
|
|
468
|
-
# Transformation
|
|
469
|
-
param_obj.SetParameter("HowToCombineTransforms", "Compose")
|
|
470
|
-
param_obj.SetParameter("Transform", "EulerTransform")
|
|
471
|
-
param_obj.SetParameter("AutomaticTransformInitialization", "true")
|
|
472
|
-
param_obj.SetParameter("AutomaticTransformInitializationMethod", "GeometricalCenter")
|
|
473
|
-
param_obj.SetParameter("AutomaticScalesEstimation", "true")
|
|
474
|
-
|
|
475
|
-
# Metric
|
|
476
|
-
param_obj.SetParameter("Metric", "AdvancedMattesMutualInformation")
|
|
477
|
-
param_obj.SetParameter("NumberOfHistogramBins", "32")
|
|
478
|
-
|
|
479
|
-
# Optimizer settings
|
|
480
|
-
param_obj.SetParameter("NumberOfResolutions", "3")
|
|
481
|
-
param_obj.SetParameter("AutomaticParameterEstimation", "true")
|
|
482
|
-
#param_obj.SetParameter("ASGDParameterEstimationMethod", "Original")
|
|
483
|
-
param_obj.SetParameter("MaximumNumberOfIterations", "500")
|
|
484
|
-
param_obj.SetParameter("MaximumStepLength", "1.0")
|
|
485
|
-
|
|
486
|
-
# Sampler parameters
|
|
487
|
-
param_obj.SetParameter("NumberOfSpatialSamples", "2048")
|
|
488
|
-
param_obj.SetParameter("NewSamplesEveryIteration", "true")
|
|
489
|
-
param_obj.SetParameter("NumberOfSamplesForExactGradient", "1024")
|
|
490
|
-
param_obj.SetParameter("MaximumNumberOfSamplingAttempts", "15")
|
|
491
|
-
param_obj.SetParameter("CheckNumberOfSamples", "true")
|
|
492
|
-
|
|
493
|
-
# Mask settings
|
|
494
|
-
param_obj.SetParameter("ErodeMask", "false")
|
|
495
|
-
param_obj.SetParameter("ErodeFixedMask", "false")
|
|
496
|
-
|
|
497
|
-
# Output settings
|
|
498
|
-
param_obj.SetParameter("DefaultPixelValue", "0")
|
|
499
|
-
param_obj.SetParameter("WriteResultImage", "true")
|
|
500
|
-
param_obj.SetParameter("ResultImagePixelType", "float")
|
|
501
|
-
param_obj.SetParameter("ResultImageFormat", "nii")
|
|
502
|
-
|
|
503
|
-
return param_obj
|
dbdicom/extensions/matplotlib.py
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import matplotlib.pyplot as plt
|
|
3
|
-
from matplotlib.figure import Figure
|
|
4
|
-
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
|
|
5
|
-
from mpl_toolkits.mplot3d.axes3d import Axes3D
|
|
6
|
-
from skimage import measure
|
|
7
|
-
|
|
8
|
-
from dbdicom.utils.image import as_mosaic
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def plot_mosaic(series, zdim='InstanceNumber', rows:int=None, colorbar=True, clim:tuple=None, gridspacing=100, size=10):
|
|
12
|
-
"""Show a 3D array as a mosaic
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
zdim (str, optional): slice dimension. Defaults to 'InstanceNumber'
|
|
16
|
-
series (dbdicom.Series): Series with the array to be plotted.
|
|
17
|
-
rows (int, optional): Number of rows of the mosaic. If set to None the mosaic will be chosen to be approximately square. Defaults to None.
|
|
18
|
-
colorbar (bool, optional): If True, a color bar is shown next to the mosaic. Defaults to True.
|
|
19
|
-
clim (tuple of 2 elements, optional): if provided, this determines the minimal and maximal signal values shown. If it is set to None or not provided, it will be taken from the WindowCenter and WindowWidth values in the DICOM header. Defaults to None.
|
|
20
|
-
gridspacing (int, optional): spacing in mm between gridlines on the plot. Defaults to 100 mm.
|
|
21
|
-
size (float, optional): size of the largest dimension of the image in inches. Defaults to 10 inch
|
|
22
|
-
"""
|
|
23
|
-
array = series.pixel_values(dims=(zdim,))
|
|
24
|
-
spacing = series.spacing()
|
|
25
|
-
mosaic = as_mosaic(array, rows=rows)
|
|
26
|
-
cols = mosaic.shape[1]/spacing[1]
|
|
27
|
-
|
|
28
|
-
if clim is None:
|
|
29
|
-
c, w = series.WindowCenter, series.WindowWidth
|
|
30
|
-
clim = (c-w/2, c+w/2)
|
|
31
|
-
fig, ax = plt.subplots()
|
|
32
|
-
dx, dy = spacing[0]*mosaic.shape[0], spacing[1]*mosaic.shape[1]
|
|
33
|
-
size = 10
|
|
34
|
-
fig.set_size_inches(size*dx/np.amax([dx,dy]), size*dy/np.amax([dx,dy]))
|
|
35
|
-
im = ax.imshow(mosaic.T, clim=clim)
|
|
36
|
-
ax.set_xlabel("x-axis (mm)")
|
|
37
|
-
ax.set_ylabel("y-axis (mm)")
|
|
38
|
-
x = np.arange(0, 1+mosaic.shape[0], gridspacing/spacing[0])
|
|
39
|
-
y = np.arange(0, 1+mosaic.shape[1], gridspacing/spacing[1])
|
|
40
|
-
ax.set_xticks(x, np.int16(x*spacing[0]))
|
|
41
|
-
ax.set_yticks(y, np.int16(y*spacing[1]))
|
|
42
|
-
if colorbar:
|
|
43
|
-
fig.colorbar(im, ax=ax, label='Signal')
|
|
44
|
-
plt.show()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def plot_surface(series, level=0, gridspacing=10, show=True):
|
|
48
|
-
"""Plot the surface at a given level
|
|
49
|
-
|
|
50
|
-
Args:
|
|
51
|
-
series (dbdicom.Series): Series with the array to be plotted.
|
|
52
|
-
level (int, optional): Extract the surface at this level. Defaults to 0.
|
|
53
|
-
gridspacing (int, optional): spacing in mm between gridlines on the plot. Defaults to 10 mm.
|
|
54
|
-
show (bool, optional): if True, the function displays the plot. Defaults to True.
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
Figure: matplotlib figure with the plot.
|
|
58
|
-
|
|
59
|
-
Requires:
|
|
60
|
-
matplotlib
|
|
61
|
-
skimage
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
# Extract the numpy array from the dbdicom series:
|
|
65
|
-
array = series.pixel_values()
|
|
66
|
-
spacing = series.spacing()
|
|
67
|
-
#spacing = (spacing[1], spacing[0], spacing[2])
|
|
68
|
-
|
|
69
|
-
# Use marching cubes to extract the surface from the array
|
|
70
|
-
verts, faces, _, _ = measure.marching_cubes(array, level)
|
|
71
|
-
|
|
72
|
-
# Use the matplotlib toolkit to create a trinagular mesh
|
|
73
|
-
mesh = Poly3DCollection(verts[faces])
|
|
74
|
-
mesh.set_edgecolor('k')
|
|
75
|
-
|
|
76
|
-
fig = plt.figure(figsize=(10, 10))
|
|
77
|
-
ax = fig.add_subplot(111, projection='3d')
|
|
78
|
-
ax.add_collection3d(mesh)
|
|
79
|
-
|
|
80
|
-
ax.set_xlabel("x-axis (mm)")
|
|
81
|
-
ax.set_ylabel("y-axis (mm)")
|
|
82
|
-
ax.set_zlabel("z-axis (mm)")
|
|
83
|
-
|
|
84
|
-
x = np.arange(0, 1+array.shape[0], gridspacing/spacing[0])
|
|
85
|
-
y = np.arange(0, 1+array.shape[1], gridspacing/spacing[1])
|
|
86
|
-
z = np.arange(0, 1+array.shape[2], gridspacing/spacing[2])
|
|
87
|
-
|
|
88
|
-
ax.set_xticks(x, np.int16(x*spacing[0]))
|
|
89
|
-
ax.set_yticks(y, np.int16(y*spacing[1]))
|
|
90
|
-
ax.set_zticks(z, np.int16(z*spacing[2]))
|
|
91
|
-
|
|
92
|
-
# Hack to ensure proportional size of each axis
|
|
93
|
-
x_len = array.shape[0]*spacing[0]
|
|
94
|
-
y_len = array.shape[1]*spacing[1]
|
|
95
|
-
z_len = array.shape[2]*spacing[2]
|
|
96
|
-
|
|
97
|
-
scale=np.diag([x_len, y_len, z_len, 1.0])
|
|
98
|
-
scale=scale*(1.0/scale.max())
|
|
99
|
-
scale[3,3]=1.0
|
|
100
|
-
|
|
101
|
-
def short_proj():
|
|
102
|
-
return np.dot(Axes3D.get_proj(ax), scale)
|
|
103
|
-
|
|
104
|
-
ax.get_proj = short_proj
|
|
105
|
-
|
|
106
|
-
if show:
|
|
107
|
-
plt.show()
|