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,151 +0,0 @@
1
- import numpy as np
2
- from sklearn.cluster import KMeans
3
- import dbdicom.wrappers.scipy as scipy
4
-
5
-
6
- # https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans
7
- def kmeans(features, mask=None, n_clusters=2, multiple_series=False):
8
- """
9
- Labels structures in an image
10
-
11
- Wrapper for sklearn.cluster.KMeans function.
12
-
13
- Parameters
14
- ----------
15
- input: list of dbdicom series (one for each feature)
16
- mask: optional mask for clustering
17
-
18
- Returns
19
- -------
20
- clusters : list of dbdicom series, with labels per cluster.
21
- """
22
-
23
- # If a mask is provided, map it onto the reference feature and
24
- # extract the indices of all pixels under the mask
25
- if mask is not None:
26
- mask.status.message('Reading mask array..')
27
- mask = scipy.map_to(mask, features[0], mask=True)
28
- mask_array, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
29
- mask_array = np.ravel(mask_array)
30
- mask_indices = tuple(mask_array.nonzero())
31
-
32
- # Ensure all the features are in the same geometry as the reference feature
33
- features = scipy.overlay(features)
34
-
35
- # Create array with shape (n_samples, n_features) and mask if needed.
36
- array = []
37
- for s, series in enumerate(features):
38
- series.status.progress(s+1, len(features), 'Reading features..')
39
- arr, headers = series.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
40
- shape = arr.shape
41
- arr = np.ravel(arr)
42
- if mask is not None:
43
- arr = arr[mask_indices]
44
- array.append(arr)
45
- array = np.vstack(array).T
46
-
47
- # Perform the K-Means clustering.
48
- series.status.message('Clustering. Please be patient - this is hard work..')
49
- kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(array)
50
-
51
- # Create an output array for the labels
52
- if mask is not None:
53
- mask.status.message('Creating output array..')
54
- array = np.zeros(shape)
55
- array = np.ravel(array)
56
- array[mask_indices] = 1+kmeans.labels_
57
- else:
58
- array = 1+kmeans.labels_
59
- array = array.reshape(shape)
60
-
61
- # Save the results
62
- series.status.message('Saving clusters..')
63
- if multiple_series:
64
- # Save each cluster as a separate mask
65
- clusters = []
66
- for cluster in range(1,1+n_clusters):
67
- array_cluster = np.zeros(array.shape)
68
- array_cluster[array == cluster] = 1
69
- series_cluster = features[0].new_sibling(SeriesDescription = 'KMeans cluster ' + str(cluster))
70
- series_cluster.set_array(array_cluster, headers, pixels_first=True)
71
- _reset_window(series_cluster, array_cluster)
72
- clusters.append(series_cluster)
73
- else:
74
- # Save the label array in a single series
75
- clusters = features[0].new_sibling(SeriesDescription = 'KMeans')
76
- clusters.set_array(array, headers, pixels_first=True)
77
- _reset_window(clusters, array)
78
-
79
- return clusters
80
-
81
-
82
-
83
- def sequential_kmeans(features, mask=None, n_clusters=2, multiple_series=False):
84
- """
85
- Labels structures in an image using sequential k-means clustering
86
-
87
- Sequential here means that the clustering is always performed on a single feature
88
- using the output of the previous iteration as a mask for the next.
89
-
90
- Parameters
91
- ----------
92
- input: list of dbdicom series (one for each feature)
93
- mask: optional mask for clustering
94
-
95
- Returns
96
- -------
97
- clusters : list of dbdicom series, with labels per cluster.
98
- """
99
-
100
- f = features[0]
101
- clusters = kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
102
- for f in features[1:]:
103
- cf = []
104
- for mask in clusters:
105
- cf += kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
106
- mask.remove()
107
- clusters = cf
108
-
109
- # Return clusters as a list
110
- if multiple_series:
111
- return clusters
112
-
113
- # Return a single label series
114
- label = masks_to_label(clusters)
115
- for c in clusters:
116
- c.remove()
117
- return label
118
-
119
-
120
-
121
- def masks_to_label(masks):
122
- "Convert a list of masks into a single label series"
123
-
124
- # Ensure all the masks are in the same geometry
125
- masks = scipy.overlay(masks)
126
-
127
- # Create a single label array
128
- array, headers = masks[0].array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
129
- msg = 'Creating a single label image'
130
- for m, mask in enumerate(masks[1:]):
131
- mask.status.progress(m+1, len(masks)-1, msg)
132
- arr, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
133
- ind = tuple(arr.nonzero())
134
- array[ind] = m+2
135
-
136
- # Save label array to disk
137
- desc = masks[0].SeriesDescription
138
- label = masks[0].new_sibling(SeriesDescription = desc + ' [Label]')
139
- label.set_array(array, headers, pixels_first=True)
140
-
141
- return label
142
-
143
-
144
-
145
- # Helper functions
146
-
147
- def _reset_window(image, array):
148
- min = np.amin(array)
149
- max = np.amax(array)
150
- image.WindowCenter= (max+min)/2
151
- image.WindowWidth = 0.9*(max-min)
dbdicom/wrappers/vreg.py DELETED
@@ -1,273 +0,0 @@
1
- import numpy as np
2
- from dbdicom.utils import vreg
3
-
4
- def print_current(vk):
5
- print(vk)
6
-
7
-
8
- def _get_input(moving, static):
9
-
10
- # Get affine matrices and check that there is a single value
11
- affine_moving = moving.affine_matrix()
12
- if isinstance(affine_moving, list):
13
- msg = 'This function only works for series with a single slice group. \n'
14
- msg += 'Multiple slice groups detected in moving series - please split the series first.'
15
- raise ValueError(msg)
16
- else:
17
- affine_moving = affine_moving[0]
18
- affine_static = static.affine_matrix()
19
- if isinstance(affine_static, list):
20
- msg = 'This function only works for series with a single slice group. \n'
21
- msg += 'Multiple slice groups detected in static series - please split the series first.'
22
- raise ValueError(msg)
23
- else:
24
- affine_static = affine_static[0]
25
-
26
- # Get arrays for static and moving series
27
- array_static, headers_static = static.array('SliceLocation', pixels_first=True, first_volume=True)
28
- if array_static is None:
29
- msg = 'Fixed series is empty - cannot perform alignment.'
30
- raise ValueError(msg)
31
- array_moving, headers_moving = moving.array('SliceLocation', pixels_first=True, first_volume=True)
32
- if array_moving is None:
33
- msg = 'Moving series is empty - cannot perform alignment.'
34
- raise ValueError(msg)
35
-
36
- moving.message('Performing coregistration. Please be patient. Its hard work and I need to concentrate..')
37
-
38
- return array_static, affine_static, array_moving, affine_moving, headers_static, headers_moving
39
-
40
-
41
-
42
-
43
-
44
- def translation_sos(moving, static, tolerance=0.1):
45
-
46
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
47
-
48
- # Define initial values and optimization
49
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
50
- optimization = {
51
- 'method': 'GD',
52
- 'options': {'gradient step': static_pixel_spacing, 'tolerance': tolerance},
53
- 'callback': lambda vk: moving.status.message('Current parameter: ' + str(vk)),
54
- }
55
-
56
- # Align volumes
57
- try:
58
- translation_estimate = vreg.align(
59
- moving = array_moving,
60
- moving_affine = affine_moving,
61
- static = array_static,
62
- static_affine = affine_static,
63
- parameters = np.array([0, 0, 0], dtype=np.float32),
64
- resolutions = [4,2,1],
65
- transformation = vreg.translate,
66
- metric = vreg.sum_of_squares,
67
- optimization = optimization,
68
- )
69
- except:
70
- print('Failed to align volumes..')
71
- return None
72
-
73
- coregistered = vreg.translate(array_moving, affine_moving, array_static.shape, affine_static, translation_estimate)
74
-
75
- # Save results as new dicom series
76
- moving.message('Writing coregistered series to database..')
77
- desc = moving.instance().SeriesDescription
78
- coreg = moving.new_sibling(SeriesDescription = desc + ' [translation]')
79
- coreg.set_array(coregistered, headers, pixels_first=True)
80
- return coreg
81
-
82
-
83
- def rigid_sos(moving, static, tolerance=0.1):
84
-
85
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
86
-
87
- # Define initial values and optimization
88
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
89
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
90
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
91
- optimization = {
92
- 'method': 'GD',
93
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
94
- 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
95
- }
96
-
97
- # Align volumes
98
- try:
99
- rigid_estimate = vreg.align(
100
- moving = array_moving,
101
- moving_affine = affine_moving,
102
- static = array_static,
103
- static_affine = affine_static,
104
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
105
- resolutions = [4,2,1],
106
- transformation = vreg.rigid,
107
- metric = vreg.sum_of_squares,
108
- optimization = optimization,
109
- )
110
- except:
111
- print('Failed to align volumes..')
112
- return None
113
-
114
- coregistered = vreg.rigid(array_moving, affine_moving, array_static.shape, affine_static, rigid_estimate)
115
-
116
- moving.message('Writing coregistered series to database..')
117
-
118
- # Save results as new dicom series
119
- desc = moving.instance().SeriesDescription
120
- coreg = moving.new_sibling(SeriesDescription = desc + ' [rigid]')
121
- coreg.set_array(coregistered, headers, pixels_first=True)
122
- return coreg
123
-
124
-
125
-
126
- def sbs_translation_sos(moving, static, tolerance=0.1):
127
-
128
- array_static, affine_static, array_moving, affine_moving, headers, headers_moving = _get_input(moving, static)
129
- slice_thickness = [headers_moving[z].SliceThickness for z in range(headers_moving.size)]
130
-
131
- # Define initial values and optimization
132
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
133
- optimization = {
134
- 'method': 'GD',
135
- 'options': {'gradient step': static_pixel_spacing, 'tolerance': tolerance},
136
- # 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
137
- }
138
-
139
- # Perform coregistration
140
- estimate = vreg.align_slice_by_slice(
141
- moving = array_moving,
142
- static = array_static,
143
- parameters = np.array([0, 0, 0], dtype=np.float32),
144
- moving_affine = affine_moving,
145
- static_affine = affine_static,
146
- transformation = vreg.translate,
147
- metric = vreg.sum_of_squares,
148
- optimization = optimization,
149
- resolutions = [4,2,1],
150
- slice_thickness = slice_thickness,
151
- progress = lambda z, nz: moving.progress(z, nz, 'Coregistering slice-by-slice using translations'),
152
- )
153
-
154
- # Calculate coregistered
155
- coregistered = vreg.transform_slice_by_slice(array_moving, affine_moving, array_static.shape, affine_static, estimate, vreg.translate, slice_thickness)
156
- # coregistered = vreg.transform_slice_by_slice(
157
- # moving = array_moving,
158
- # moving_affine = affine_moving,
159
- # static_shape = array_static.shape,
160
- # static_affine = affine_static,
161
- # parameters = estimate,
162
- # transformation = vreg.translate,
163
- # slice_thickness = slice_thickness)
164
-
165
- # Save results as new dicom series
166
- moving.message('Writing coregistered series to database..')
167
- desc = moving.instance().SeriesDescription
168
- coreg = moving.new_sibling(SeriesDescription = desc + ' [sbs translation]')
169
- coreg.set_array(coregistered, headers, pixels_first=True)
170
-
171
- return coreg
172
-
173
-
174
- def sbs_rigid_around_com_sos(moving, static, tolerance=0.1):
175
-
176
- array_static, affine_static, array_moving, affine_moving, headers, headers_moving = _get_input(moving, static)
177
- slice_thickness = [headers_moving[z].SliceThickness for z in range(headers_moving.size)]
178
-
179
- # Define initial values and optimization
180
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
181
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
182
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
183
- optimization = {
184
- 'method': 'GD',
185
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
186
- #'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
187
- }
188
-
189
- # Perform coregistration
190
- estimate = vreg.align_slice_by_slice(
191
- moving = array_moving,
192
- static = array_static,
193
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
194
- moving_affine = affine_moving,
195
- static_affine = affine_static,
196
- transformation = vreg.rigid_around_com,
197
- metric = vreg.sum_of_squares,
198
- optimization = optimization,
199
- resolutions = [4,2,1],
200
- slice_thickness = slice_thickness,
201
- progress = lambda z, nz: moving.progress(z, nz, 'Coregistering slice-by-slice using rigid transformations'),
202
- )
203
-
204
- # The generic slice-by-slice transform does not work for center of mass rotations.
205
- # Calculate rotation center and use rigid rotation around given center instead.
206
- estimate_center = []
207
- for z in range(len(estimate)):
208
- array_moving_z, affine_moving_z = vreg.extract_slice(array_moving, affine_moving, z, slice_thickness)
209
- center = estimate[z][3:] + vreg.center_of_mass(vreg.to_3d(array_moving_z), affine_moving_z)
210
- pars = np.concatenate((estimate[z][:3], center, estimate[z][3:]))
211
- estimate_center.append(pars)
212
-
213
- # Calculate coregistered (using rigid around known center)
214
- coregistered = vreg.transform_slice_by_slice(array_moving, affine_moving, array_static.shape, affine_static, estimate_center, vreg.rigid_around, slice_thickness)
215
- # coregistered = vreg.transform_slice_by_slice(
216
- # moving = array_moving,
217
- # moving_affine = affine_moving,
218
- # static_shape = array_static.shape,
219
- # static_affine = affine_static,
220
- # parameters = estimate_center,
221
- # transformation = vreg.rigid_around,
222
- # slice_thickness = slice_thickness)
223
-
224
- # Save results as new dicom series
225
- moving.message('Writing coregistered series to database..')
226
- desc = moving.instance().SeriesDescription
227
- coreg = moving.new_sibling(SeriesDescription = desc + ' [sbs rigid com]')
228
- coreg.set_array(coregistered, headers, pixels_first=True)
229
-
230
- return coreg
231
-
232
-
233
-
234
- def rigid_around_com_sos(moving, static, tolerance=0.1):
235
-
236
- array_static, affine_static, array_moving, affine_moving, headers, _ = _get_input(moving, static)
237
-
238
- # Define initial values and optimization
239
- _, _, static_pixel_spacing = vreg.affine_components(affine_static)
240
- rot_gradient_step, translation_gradient_step, _ = vreg.affine_resolution(array_static.shape, static_pixel_spacing)
241
- gradient_step = np.concatenate((1.0*rot_gradient_step, 0.5*translation_gradient_step))
242
- optimization = {
243
- 'method': 'GD',
244
- 'options': {'gradient step': gradient_step, 'tolerance': tolerance},
245
- 'callback': lambda vk: moving.message('Current parameter: ' + str(vk)),
246
- }
247
-
248
- # Align volumes
249
- try:
250
- rigid_estimate = vreg.align(
251
- moving = array_moving,
252
- moving_affine = affine_moving,
253
- static = array_static,
254
- static_affine = affine_static,
255
- parameters = np.array([0, 0, 0, 0, 0, 0], dtype=np.float32),
256
- resolutions = [4,2,1],
257
- transformation = vreg.rigid_around_com,
258
- metric = vreg.sum_of_squares,
259
- optimization = optimization,
260
- )
261
- except:
262
- print('Failed to align volumes..')
263
- return None
264
-
265
- coregistered = vreg.rigid_around_com(array_moving, affine_moving, array_static.shape, affine_static, rigid_estimate)
266
-
267
- moving.message('Writing coregistered series to database..')
268
-
269
- # Save results as new dicom series
270
- desc = moving.instance().SeriesDescription
271
- coreg = moving.new_sibling(SeriesDescription = desc + ' [rigid com]')
272
- coreg.set_array(coregistered, headers, pixels_first=True)
273
- return coreg