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.
Files changed (72) hide show
  1. dbdicom/__init__.py +3 -25
  2. dbdicom/api.py +496 -0
  3. dbdicom/const.py +144 -0
  4. dbdicom/database.py +133 -0
  5. dbdicom/dataset.py +471 -0
  6. dbdicom/dbd.py +1290 -0
  7. dbdicom/external/__pycache__/__init__.cpython-311.pyc +0 -0
  8. dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc +0 -0
  9. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc +0 -0
  10. dbdicom/external/dcm4che/bin/emf2sf +57 -57
  11. dbdicom/register.py +402 -0
  12. dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
  13. dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +206 -160
  14. dbdicom/sop_classes/mr_image.py +338 -0
  15. dbdicom/sop_classes/parametric_map.py +381 -0
  16. dbdicom/sop_classes/secondary_capture.py +140 -0
  17. dbdicom/sop_classes/segmentation.py +311 -0
  18. dbdicom/{ds/types → sop_classes}/ultrasound_multiframe_image.py +1 -15
  19. dbdicom/{ds/types → sop_classes}/xray_angiographic_image.py +2 -17
  20. dbdicom/utils/arrays.py +142 -0
  21. dbdicom/utils/files.py +0 -20
  22. dbdicom/utils/image.py +43 -466
  23. dbdicom/utils/pydicom_dataset.py +386 -0
  24. dbdicom-0.3.16.dist-info/METADATA +26 -0
  25. dbdicom-0.3.16.dist-info/RECORD +54 -0
  26. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/WHEEL +1 -1
  27. dbdicom/create.py +0 -450
  28. dbdicom/ds/__init__.py +0 -10
  29. dbdicom/ds/create.py +0 -63
  30. dbdicom/ds/dataset.py +0 -841
  31. dbdicom/ds/dictionaries.py +0 -620
  32. dbdicom/ds/types/mr_image.py +0 -267
  33. dbdicom/ds/types/parametric_map.py +0 -226
  34. dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  35. dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  36. dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  37. dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  38. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  39. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  40. dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  41. dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  42. dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  43. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  44. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  45. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  46. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  47. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  48. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  49. dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  50. dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  51. dbdicom/manager.py +0 -2077
  52. dbdicom/message.py +0 -119
  53. dbdicom/record.py +0 -1526
  54. dbdicom/types/database.py +0 -107
  55. dbdicom/types/instance.py +0 -184
  56. dbdicom/types/patient.py +0 -40
  57. dbdicom/types/series.py +0 -816
  58. dbdicom/types/study.py +0 -58
  59. dbdicom/utils/variables.py +0 -155
  60. dbdicom/utils/vreg.py +0 -2626
  61. dbdicom/wrappers/__init__.py +0 -7
  62. dbdicom/wrappers/dipy.py +0 -462
  63. dbdicom/wrappers/elastix.py +0 -855
  64. dbdicom/wrappers/numpy.py +0 -119
  65. dbdicom/wrappers/scipy.py +0 -1413
  66. dbdicom/wrappers/skimage.py +0 -1030
  67. dbdicom/wrappers/sklearn.py +0 -151
  68. dbdicom/wrappers/vreg.py +0 -273
  69. dbdicom-0.2.0.dist-info/METADATA +0 -276
  70. dbdicom-0.2.0.dist-info/RECORD +0 -81
  71. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info/licenses}/LICENSE +0 -0
  72. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/top_level.txt +0 -0
@@ -1,7 +0,0 @@
1
- # from . import (
2
- # numpy,
3
- # dipy,
4
- # scipy,
5
- # elastix,
6
- # skimage,
7
- # )
dbdicom/wrappers/dipy.py DELETED
@@ -1,462 +0,0 @@
1
- import numpy as np
2
- from dipy.align.imwarp import SymmetricDiffeomorphicRegistration
3
- from dipy.align.metrics import CCMetric, EMMetric, SSDMetric
4
- from dipy.align.imaffine import MutualInformationMetric, AffineRegistration
5
- from dipy.align.transforms import (TranslationTransform3D,
6
- RigidTransform3D,
7
- AffineTransform3D)
8
- from dipy.align import center_of_mass
9
- from dipy.align.vector_fields import (
10
- warp_3d_nn,
11
- warp_3d,
12
- warp_2d_nn,
13
- warp_2d,
14
- invert_vector_field_fixed_point_3d,
15
- invert_vector_field_fixed_point_2d,
16
- )
17
-
18
- from dipy.segment.mask import median_otsu as median_otsu_np
19
- import dbdicom.wrappers.scipy as scipy
20
- from dbdicom.utils.image import slice_to_volume
21
-
22
-
23
-
24
-
25
-
26
- def median_otsu(series, **kwargs):
27
-
28
- # Get arrays for fixed and moving series
29
- array, headers = series.array('SliceLocation', pixels_first=True)
30
-
31
- # Apply Otsu
32
- mask = np.empty(array.shape)
33
- cnt=0
34
- for z in range(array.shape[2]):
35
- for k in range(array.shape[3]):
36
- cnt+=1
37
- series.status.progress(cnt, array.shape[2]*array.shape[3], 'Applying Otsu segmentation..')
38
- image = np.squeeze(array[:,:,z,k])
39
- array[:,:,z,k], mask[:,:,z,k] = median_otsu_np(image, **kwargs)
40
-
41
- # Create new series
42
- masked_series = series.new_sibling(suffix='masked')
43
- otsu_mask = series.new_sibling(suffix ='otsu mask')
44
-
45
- # Set values and return
46
- masked_series.set_array(array, headers, pixels_first=True)
47
- otsu_mask.set_array(mask, headers, pixels_first=True)
48
- return masked_series, otsu_mask
49
-
50
-
51
- def align_center_of_mass_3d(moving, fixed):
52
-
53
- # Get arrays for fixed and moving series
54
- array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
55
- array_fixed = scipy.array(fixed, on=moving, sortby='SliceLocation', pixels_first=True, first_volume=True)
56
-
57
- # Coregister fixed and moving slice-by-slice
58
- identity = np.eye(4)
59
- array_moving, _ = center_of_mass(array_moving, array_fixed, static_affine=identity, moving_affine=identity)
60
-
61
- # Create new series
62
- moved = moving.new_sibling(suffix='aligned')
63
- moved.set_array(array_moving, headers_moving, pixels_first=True)
64
-
65
- return moved
66
-
67
-
68
- def coregister_translation_3d(moving, fixed):
69
-
70
- # Get arrays for fixed and moving series
71
- array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
72
- array_fixed = scipy.array(fixed, on=moving, sortby='SliceLocation', pixels_first=True, first_volume=True)
73
-
74
- # Align images
75
- moving.message('Performing coregistration..')
76
- coregistered = _coregister_translation_3d_arrays(array_fixed, array_moving)
77
-
78
- # Return as new series
79
- coreg = moving.new_sibling(suffix='translated')
80
- coreg.set_array(coregistered, headers_moving, pixels_first=True)
81
-
82
- return coreg
83
-
84
-
85
- def coregister_rigid_3d(moving, static, ignore_empty_slices=False):
86
-
87
- # Get arrays for fixed and moving series
88
- #array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
89
- #array_static = scipy.array(static, on=moving, sortby='SliceLocation', pixels_first=True, first_volume=True)
90
-
91
- array_static, headers_static = static.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
92
- array_moving = scipy.array(moving, on=static, sortby='SliceLocation', pixels_first=True, first_volume=True)
93
-
94
- # Get masks if required - this feature not tested
95
- if ignore_empty_slices:
96
- moving_mask = _coregistration_mask_3d(array_moving)
97
- static_mask = _coregistration_mask_3d(array_static)
98
- else:
99
- moving_mask = None
100
- static_mask = None
101
-
102
- # Align images
103
- moving.message('Performing coregistration..')
104
- coregistered = _coregister_rigid_3d_arrays(
105
- array_static,
106
- array_moving,
107
- static_mask = static_mask,
108
- moving_mask = moving_mask,
109
- )
110
-
111
- # Return as new series
112
- # coreg = moving.new_sibling(suffix='rigid')
113
- # coreg.set_array(coregistered, headers_moving, pixels_first=True)
114
- coreg = static.new_sibling(suffix='rigid')
115
- coreg.set_array(coregistered, headers_static, pixels_first=True)
116
- return coreg
117
-
118
-
119
- # Works but slices come out too thick
120
- def WIP_coregister_rigid_3d(moving, static, ignore_empty_slices=False):
121
-
122
- # Get affines for fixed and moving series
123
- affine_moving = moving.affine_matrix()
124
- affine_static = static.affine_matrix()
125
-
126
- # If there are multiple slice groups - raise error
127
- if isinstance(affine_moving, list):
128
- msg = 'Moving series consists of multiple slice groups.\n'
129
- msg += 'Can only align series consisting of a single slice group.'
130
- raise ValueError(msg)
131
- if isinstance(affine_static, list):
132
- msg = 'Static series consists of multiple slice groups.\n'
133
- msg += 'Can only align series consisting of a single slice group.'
134
- raise ValueError(msg)
135
-
136
- # Get affine matrices
137
- affine_static = affine_static[0].astype(np.double)
138
- affine_moving = affine_moving[0].astype(np.double)
139
-
140
- # Get arrays for fixed and moving series
141
- # array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
142
- # array_static, _ = static.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
143
- array_static, headers_static = static.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
144
- array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
145
-
146
- # If images are single-slice, expand into volumes
147
- if array_moving.shape[2] == 1:
148
- array_moving, affine_moving = slice_to_volume(array_moving, affine_moving)
149
- if array_static.shape[2] == 1:
150
- array_static, affine_static = slice_to_volume(array_static, affine_static)
151
-
152
- # Get masks if required - this feature not tested
153
- if ignore_empty_slices:
154
- moving_mask = _coregistration_mask_3d(array_moving)
155
- static_mask = _coregistration_mask_3d(array_static)
156
- else:
157
- moving_mask = None
158
- static_mask = None
159
-
160
- # Align images
161
- moving.message('Performing coregistration..')
162
- coregistered = _coregister_rigid_3d_arrays(
163
- array_static,
164
- array_moving,
165
- static_grid2world = affine_static,
166
- moving_grid2world = affine_moving,
167
- static_mask = static_mask,
168
- moving_mask = moving_mask,
169
- )
170
-
171
- # Return as new series
172
- # coreg = moving.new_sibling(suffix='rigid')
173
- # coreg.set_array(coregistered, headers_moving, pixels_first=True)
174
- coreg = static.new_sibling(suffix='rigid')
175
- coreg.set_array(coregistered, headers_static, pixels_first=True)
176
- return coreg
177
-
178
-
179
- def _coregister_rigid_3d_arrays(static, moving, **kwargs):
180
-
181
- metric = MutualInformationMetric(
182
- nbins=32,
183
- sampling_proportion=None,
184
- )
185
- affreg = AffineRegistration(
186
- metric = metric,
187
- level_iters = [10000, 1000, 100],
188
- sigmas = [3.0, 1.0, 0.0],
189
- factors = [4, 2, 1],
190
- )
191
- transform = RigidTransform3D()
192
- params0 = None
193
- mapping = affreg.optimize(static, moving, transform, params0, **kwargs)
194
-
195
- # Warp the moving image
196
- coregistered = mapping.transform(moving, 'linear')
197
-
198
- return coregistered
199
-
200
-
201
- def coregister_affine_3d(moving, fixed):
202
-
203
- # Get arrays for fixed and moving series
204
- array_moving, headers_moving = moving.array(sortby='SliceLocation', pixels_first=True, first_volume=True)
205
- array_fixed = scipy.array(fixed, on=moving, sortby='SliceLocation', pixels_first=True, first_volume=True)
206
-
207
- # Align images
208
- moving.message('Performing coregistration..')
209
- coregistered = _coregister_affine_3d_arrays(array_fixed, array_moving)
210
-
211
- # Return as new series
212
- coreg = moving.new_sibling(suffix='affine')
213
- coreg.set_array(coregistered, headers_moving, pixels_first=True)
214
-
215
- return coreg
216
-
217
-
218
- def coregister_2d_to_2d(moving, fixed, **kwargs):
219
-
220
- # Overlay fixed on moving image
221
- fixed_map = scipy.map_to(fixed, moving)
222
-
223
- # Get arrays for fixed and moving series
224
- array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
225
- array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
226
-
227
- # Remove overlay from database
228
- if fixed_map != fixed:
229
- fixed_map.remove()
230
-
231
- # Coregister fixed and moving slice-by-slice
232
- deformation = np.empty(array_moving.shape + (2,))
233
- for z in range(array_moving.shape[2]):
234
- moving.status.progress(z+1, array_moving.shape[2], 'Performing coregistration..')
235
- coreg, deform = _coregister_arrays(array_fixed[:,:,z], array_moving[:,:,z], **kwargs)
236
- array_moving[:,:,z] = coreg
237
- deformation[:,:,z,:] = deform
238
-
239
- # Create new series
240
- coreg = moving.new_sibling(suffix= 'registered')
241
- deform = moving.new_sibling(suffix='deformation field')
242
-
243
- # Set values & return
244
- coreg.set_array(array_moving, headers_moving, pixels_first=True)
245
- for dim in range(deformation.shape[-1]):
246
- deform.set_array(deformation[...,dim], headers_moving, pixels_first=True)
247
- return coreg, deform
248
-
249
-
250
- def coregister_3d_to_3d(moving, fixed, **kwargs):
251
-
252
- # Overlay fixed on moving image
253
- fixed_map = scipy.map_to(fixed, moving)
254
-
255
- # Get arrays for fixed and moving series
256
- array_fixed, _ = fixed_map.array('SliceLocation', pixels_first=True, first_volume=True)
257
- array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
258
-
259
- # Remove overlay from database
260
- if fixed_map != fixed:
261
- fixed_map.remove()
262
-
263
- # Perform coregistration
264
- moving.status.message('Performing coregistration..')
265
- array_moving, deformation = _coregister_arrays(array_fixed, array_moving, **kwargs)
266
-
267
- # Create new series
268
- coreg = moving.new_sibling(suffix='registered')
269
- deform = moving.new_sibling(suffix='deformation field')
270
-
271
- # Set arrays
272
- coreg.set_array(array_moving, headers_moving, pixels_first=True)
273
- for dim in range(deformation.shape[-1]):
274
- deform.set_array(deformation[...,dim], headers_moving, pixels_first=True)
275
-
276
- # Return coregistered images and deformation field
277
- return coreg, deform
278
-
279
-
280
-
281
- def invert_deformation_field(deformation_field, **kwargs):
282
-
283
- # Get array
284
- array, headers = deformation_field.array('SliceLocation', pixels_first=True)
285
-
286
- # Invert
287
- array = _invert_deformation_field_array(array, deformation_field.status, **kwargs)
288
-
289
- # Create new series
290
- inv = deformation_field.new_sibling(suffix='inverse')
291
- inv.set_array(array, headers, pixels_first=True)
292
-
293
- return inv
294
-
295
-
296
- def warp(image, deformation_field, **kwargs):
297
-
298
- # Overlay deformation field on image
299
- deform = scipy.map_to(deformation_field, image)
300
-
301
- # Get arrays
302
- array, headers = image.array('SliceLocation', pixels_first=True, first_volume=True)
303
- array_deform, _ = deform.array('SliceLocation', pixels_first=True)
304
-
305
- # Remove temporary variables
306
- if deform != deformation_field:
307
- deform.remove()
308
-
309
- # Perform warping
310
- array = _warp_array(array, array_deform, image.status, **kwargs)
311
-
312
- # Create new series
313
- warped = image.new_sibling(suffix='warped')
314
- warped.set_array(array, headers, pixels_first=True)
315
-
316
- return warped
317
-
318
-
319
- def _coregistration_mask_3d(array):
320
- mask = np.zeros(array.shape)
321
- for z in range(array.shape[2]):
322
- if np.count_nonzero(array[:,:,z]) > 0:
323
- mask[:,:,z] = 1
324
- return mask
325
-
326
-
327
- def _invert_deformation_field_array(array, status, max_iter=10, tolerance=0.1):
328
- status.message('Inverting deformation field..')
329
- dim = array.shape[-1]
330
- d_world2grid = np.eye(dim+1)
331
- spacing = np.ones(dim)
332
- if dim==3:
333
- return invert_vector_field_fixed_point_3d(array, d_world2grid, spacing, max_iter, tolerance)
334
- elif dim==2:
335
- nslices = array.shape[2]
336
- for z in range(nslices):
337
- status.progress(z+1, nslices, 'Inverting deformation field..')
338
- array[:,:,z] = invert_vector_field_fixed_point_2d(array[:,:,z], d_world2grid, spacing, max_iter, tolerance)
339
- return array
340
- else:
341
- msg = 'This series is not a deformation field.'
342
- msg += 'A deformation field must have either 2 or 3 components.'
343
- raise ValueError(msg)
344
-
345
-
346
- def _warp_array(array, deform, status, interpolate=True):
347
- status.message('Warping array..')
348
- dim = deform.shape[-1]
349
- if dim==3:
350
- if interpolate:
351
- return warp_3d(array, deform)
352
- else:
353
- return warp_3d_nn(array, deform)
354
- elif dim==2:
355
- nslices = deform.shape[2]
356
- for z in range(nslices):
357
- status.progress(z+1, nslices, 'Warping array..')
358
- if interpolate:
359
- array[:,:,z] = warp_2d(array[:,:,z], deform[:,:,z,:])
360
- else:
361
- array[:,:,z] = warp_2d_nn(array[:,:,z], deform[:,:,z,:])
362
- return array
363
- else:
364
- msg = 'This series is not a deformation field.'
365
- msg += 'A deformation field must have either 2 or 3 components.'
366
- raise ValueError(msg)
367
-
368
-
369
- def _coregister_translation_3d_arrays(fixed, moving):
370
-
371
- metric = MutualInformationMetric(
372
- nbins=32,
373
- sampling_proportion=None,
374
- )
375
- affreg = AffineRegistration(
376
- metric = metric,
377
- level_iters = [10000, 1000, 100],
378
- sigmas = [3.0, 1.0, 0.0],
379
- factors = [4, 2, 1],
380
- )
381
- transform = TranslationTransform3D()
382
- params0 = None
383
- mapping = affreg.optimize(fixed, moving, transform, params0)
384
-
385
- # Warp the moving image
386
- coregistered = mapping.transform(moving, 'linear')
387
-
388
- return coregistered
389
-
390
-
391
-
392
-
393
-
394
- def _coregister_affine_3d_arrays(fixed, moving):
395
-
396
- metric = MutualInformationMetric(
397
- nbins=32,
398
- sampling_proportion=None,
399
- )
400
- affreg = AffineRegistration(
401
- metric = metric,
402
- level_iters = [10000, 1000, 100],
403
- sigmas = [3.0, 1.0, 0.0],
404
- factors = [4, 2, 1],
405
- )
406
- transform = AffineTransform3D()
407
- params0 = None
408
- mapping = affreg.optimize(fixed, moving, transform, params0)
409
-
410
- # Warp the moving image
411
- coregistered = mapping.transform(moving, 'linear')
412
-
413
- return coregistered
414
-
415
-
416
- def _coregister_arrays(fixed, moving, transformation='Symmetric Diffeomorphic', metric="Cross-Correlation"):
417
- """
418
- Coregister two arrays and return coregistered + deformation field
419
- """
420
-
421
- # Define the metric
422
- dim = fixed.ndim
423
-
424
- # 3D registration does not seem to work with smaller slabs
425
- # Exclude this case
426
- if dim == 3:
427
- if fixed.shape[-1] < 6:
428
- msg = 'The 3D volume does not have enough slices for 3D registration. \n'
429
- msg += 'Try 2D registration instead.'
430
- raise ValueError(msg)
431
-
432
- # Define the metric
433
- if metric == "Cross-Correlation":
434
- sigma_diff = 3.0 # Gaussian Kernel
435
- radius = 4 # Window for local CC
436
- metric = CCMetric(dim, sigma_diff, radius)
437
- elif metric == 'Expectation-Maximization':
438
- metric = EMMetric(dim, smooth=1.0)
439
- elif metric == 'Sum of Squared Differences':
440
- metric = SSDMetric(dim, smooth=4.0)
441
- else:
442
- msg = 'The metric ' + metric + ' is currently not implemented.'
443
- raise ValueError(msg)
444
-
445
- # Define the deformation model
446
- if transformation == 'Symmetric Diffeomorphic':
447
- level_iters = [200, 100, 50, 25]
448
- sdr = SymmetricDiffeomorphicRegistration(metric, level_iters, inv_iter=50)
449
- else:
450
- msg = 'The transform ' + transformation + ' is currently not implemented.'
451
- raise ValueError(msg)
452
-
453
- # Perform the optimization, return a DiffeomorphicMap object
454
- mapping = sdr.optimize(fixed, moving)
455
-
456
- # Get forward deformation field
457
- deformation_field = mapping.get_forward_field()
458
-
459
- # Warp the moving image
460
- warped_moving = mapping.transform(moving, 'linear')
461
-
462
- return warped_moving, deformation_field