dbdicom 0.2.5__py3-none-any.whl → 0.3.0__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 +267 -0
- dbdicom/const.py +144 -0
- dbdicom/dataset.py +752 -0
- dbdicom/dbd.py +719 -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 +307 -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.0.dist-info/METADATA +28 -0
- dbdicom-0.3.0.dist-info/RECORD +53 -0
- {dbdicom-0.2.5.dist-info → dbdicom-0.3.0.dist-info}/WHEEL +1 -1
- 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.5.dist-info/METADATA +0 -71
- dbdicom-0.2.5.dist-info/RECORD +0 -66
- {dbdicom-0.2.5.dist-info → dbdicom-0.3.0.dist-info/licenses}/LICENSE +0 -0
- {dbdicom-0.2.5.dist-info → dbdicom-0.3.0.dist-info}/top_level.txt +0 -0
dbdicom/extensions/sklearn.py
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from sklearn.cluster import KMeans
|
|
3
|
-
from sklearn.preprocessing import StandardScaler
|
|
4
|
-
from dbdicom.extensions import scipy, vreg
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans
|
|
8
|
-
def kmeans(features, mask=None, n_clusters=2, multiple_series=False, normalize=True, return_features=False):
|
|
9
|
-
"""
|
|
10
|
-
Labels structures in an image
|
|
11
|
-
|
|
12
|
-
Wrapper for sklearn.cluster.KMeans function.
|
|
13
|
-
|
|
14
|
-
Parameters
|
|
15
|
-
----------
|
|
16
|
-
input: list of dbdicom series (one for each feature)
|
|
17
|
-
mask: optional mask for clustering
|
|
18
|
-
|
|
19
|
-
Returns
|
|
20
|
-
-------
|
|
21
|
-
clusters : list of dbdicom series, with labels per cluster.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
# If a mask is provided, map it onto the reference feature and
|
|
25
|
-
# extract the indices of all pixels under the mask
|
|
26
|
-
if mask is not None:
|
|
27
|
-
mask.message('Reading mask array..')
|
|
28
|
-
#mask = vreg.map_to(mask, features[0], mask=True)
|
|
29
|
-
#mask_array, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
|
|
30
|
-
mask_array, _ = vreg.mask_array(mask, on=features[0], dim='AcquisitionTime')
|
|
31
|
-
mask_array = np.ravel(mask_array)
|
|
32
|
-
mask_indices = tuple(mask_array.nonzero())
|
|
33
|
-
|
|
34
|
-
# Ensure all the features are in the same geometry as the reference feature
|
|
35
|
-
features = scipy.overlay(features)
|
|
36
|
-
|
|
37
|
-
# Create array with shape (n_samples, n_features) and mask if needed.
|
|
38
|
-
array = []
|
|
39
|
-
for s, series in enumerate(features):
|
|
40
|
-
series.progress(s+1, len(features), 'Reading features..')
|
|
41
|
-
arr, headers = series.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
|
|
42
|
-
shape = arr.shape
|
|
43
|
-
arr = np.ravel(arr)
|
|
44
|
-
if mask is not None:
|
|
45
|
-
arr = arr[mask_indices]
|
|
46
|
-
#if normalize:
|
|
47
|
-
# arr = (arr-np.mean(arr))/np.std(arr)
|
|
48
|
-
array.append(arr)
|
|
49
|
-
array = np.vstack(array).T
|
|
50
|
-
|
|
51
|
-
# Perform the K-Means clustering.
|
|
52
|
-
series.message('Clustering. Please be patient - this is hard work..')
|
|
53
|
-
if normalize:
|
|
54
|
-
X = StandardScaler().fit_transform(array)
|
|
55
|
-
kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(X)
|
|
56
|
-
else:
|
|
57
|
-
kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(array)
|
|
58
|
-
|
|
59
|
-
# Create an output array for the labels
|
|
60
|
-
if mask is not None:
|
|
61
|
-
mask.message('Creating output array..')
|
|
62
|
-
output_array = np.zeros(shape)
|
|
63
|
-
output_array = np.ravel(output_array)
|
|
64
|
-
output_array[mask_indices] = 1+kmeans.labels_
|
|
65
|
-
else:
|
|
66
|
-
output_array = 1+kmeans.labels_
|
|
67
|
-
output_array = output_array.reshape(shape)
|
|
68
|
-
|
|
69
|
-
# Save the results in DICOM
|
|
70
|
-
series.message('Saving clusters..')
|
|
71
|
-
if multiple_series:
|
|
72
|
-
# Save each cluster as a separate mask
|
|
73
|
-
clusters = []
|
|
74
|
-
for cluster in range(1,1+n_clusters):
|
|
75
|
-
array_cluster = np.zeros(output_array.shape)
|
|
76
|
-
array_cluster[output_array == cluster] = 1
|
|
77
|
-
series_cluster = features[0].new_sibling(SeriesDescription = 'KMeans cluster ' + str(cluster))
|
|
78
|
-
series_cluster.set_array(array_cluster, headers, pixels_first=True)
|
|
79
|
-
_reset_window(series_cluster, array_cluster)
|
|
80
|
-
clusters.append(series_cluster)
|
|
81
|
-
else:
|
|
82
|
-
# Save the label array in a single series
|
|
83
|
-
clusters = features[0].new_sibling(SeriesDescription = 'KMeans')
|
|
84
|
-
clusters.set_array(output_array, headers, pixels_first=True)
|
|
85
|
-
_reset_window(clusters, output_array)
|
|
86
|
-
|
|
87
|
-
# If requested, return features (mean values over clusters + size of cluster)
|
|
88
|
-
if return_features: # move up
|
|
89
|
-
cluster_features = []
|
|
90
|
-
for cluster in range(1,1+n_clusters):
|
|
91
|
-
vals = []
|
|
92
|
-
#locs = (output_array.ravel() == cluster)
|
|
93
|
-
locs = (1+kmeans.labels_ == cluster)
|
|
94
|
-
for feature in range(array.shape[1]):
|
|
95
|
-
val = np.mean(array[:,feature][locs])
|
|
96
|
-
vals.append(val)
|
|
97
|
-
vals.append(np.sum(locs))
|
|
98
|
-
cluster_features.append(vals)
|
|
99
|
-
return clusters, cluster_features
|
|
100
|
-
|
|
101
|
-
return clusters
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def kmeans_4d(features, mask=None, n_clusters=2, multiple_series=False, normalize=True, return_features=False):
|
|
105
|
-
|
|
106
|
-
# If a mask is provided, map it onto the reference feature and
|
|
107
|
-
# extract the indices of all pixels under the mask
|
|
108
|
-
if mask is not None:
|
|
109
|
-
mask.message('Reading mask array..')
|
|
110
|
-
mask_array, _ = vreg.mask_array(mask, on=features[0], dim='AcquisitionTime')
|
|
111
|
-
mask_array = np.ravel(mask_array)
|
|
112
|
-
mask_indices = tuple(mask_array.nonzero())
|
|
113
|
-
|
|
114
|
-
# Create array with shape (n_samples, n_features) and mask if needed.
|
|
115
|
-
array, headers = features.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
|
|
116
|
-
shape = array.shape
|
|
117
|
-
array = array.reshape((-1, shape[-1]))
|
|
118
|
-
if mask is not None:
|
|
119
|
-
array = array[mask_indices, :]
|
|
120
|
-
|
|
121
|
-
# Perform the K-Means clustering.
|
|
122
|
-
features.message('Clustering. Please be patient - this is hard work..')
|
|
123
|
-
if normalize:
|
|
124
|
-
X = StandardScaler().fit_transform(array)
|
|
125
|
-
kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(X)
|
|
126
|
-
else:
|
|
127
|
-
kmeans = KMeans(n_clusters=n_clusters, random_state=0, n_init=3, verbose=1).fit(array)
|
|
128
|
-
|
|
129
|
-
# Create an output array for the labels
|
|
130
|
-
if mask is not None:
|
|
131
|
-
mask.message('Creating output array..')
|
|
132
|
-
output_array = np.zeros(shape)
|
|
133
|
-
output_array = np.ravel(output_array)
|
|
134
|
-
output_array[mask_indices] = 1+kmeans.labels_
|
|
135
|
-
else:
|
|
136
|
-
output_array = 1+kmeans.labels_
|
|
137
|
-
output_array = output_array.reshape(shape)
|
|
138
|
-
|
|
139
|
-
# Save the results in DICOM
|
|
140
|
-
features.message('Saving clusters..')
|
|
141
|
-
if multiple_series:
|
|
142
|
-
# Save each cluster as a separate mask
|
|
143
|
-
clusters = []
|
|
144
|
-
for cluster in range(1,1+n_clusters):
|
|
145
|
-
array_cluster = np.zeros(output_array.shape)
|
|
146
|
-
array_cluster[output_array == cluster] = 1
|
|
147
|
-
series_cluster = features[0].new_sibling(SeriesDescription = 'KMeans cluster ' + str(cluster))
|
|
148
|
-
series_cluster.set_array(array_cluster, headers, pixels_first=True)
|
|
149
|
-
_reset_window(series_cluster, array_cluster)
|
|
150
|
-
clusters.append(series_cluster)
|
|
151
|
-
else:
|
|
152
|
-
# Save the label array in a single series
|
|
153
|
-
clusters = features[0].new_sibling(SeriesDescription = 'KMeans')
|
|
154
|
-
clusters.set_array(output_array, headers, pixels_first=True)
|
|
155
|
-
_reset_window(clusters, output_array)
|
|
156
|
-
|
|
157
|
-
# If requested, return features (mean values over clusters + size of cluster)
|
|
158
|
-
if return_features: # move up
|
|
159
|
-
cluster_features = []
|
|
160
|
-
for cluster in range(1,1+n_clusters):
|
|
161
|
-
vals = []
|
|
162
|
-
#locs = (output_array.ravel() == cluster)
|
|
163
|
-
locs = (1+kmeans.labels_ == cluster)
|
|
164
|
-
for feature in range(array.shape[1]):
|
|
165
|
-
val = np.mean(array[:,feature][locs])
|
|
166
|
-
vals.append(val)
|
|
167
|
-
vals.append(np.sum(locs))
|
|
168
|
-
cluster_features.append(vals)
|
|
169
|
-
return clusters, cluster_features
|
|
170
|
-
|
|
171
|
-
return clusters
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
def sequential_kmeans(features, mask=None, n_clusters=2, multiple_series=False):
|
|
176
|
-
"""
|
|
177
|
-
Labels structures in an image using sequential k-means clustering
|
|
178
|
-
|
|
179
|
-
Sequential here means that the clustering is always performed on a single feature
|
|
180
|
-
using the output of the previous iteration as a mask for the next.
|
|
181
|
-
|
|
182
|
-
Parameters
|
|
183
|
-
----------
|
|
184
|
-
input: list of dbdicom series (one for each feature)
|
|
185
|
-
mask: optional mask for clustering
|
|
186
|
-
|
|
187
|
-
Returns
|
|
188
|
-
-------
|
|
189
|
-
clusters : list of dbdicom series, with labels per cluster.
|
|
190
|
-
"""
|
|
191
|
-
|
|
192
|
-
f = features[0]
|
|
193
|
-
clusters = kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
|
|
194
|
-
for f in features[1:]:
|
|
195
|
-
cf = []
|
|
196
|
-
for mask in clusters:
|
|
197
|
-
cf += kmeans([f], mask=mask, n_clusters=n_clusters, multiple_series=True)
|
|
198
|
-
mask.remove()
|
|
199
|
-
clusters = cf
|
|
200
|
-
|
|
201
|
-
# Return clusters as a list
|
|
202
|
-
if multiple_series:
|
|
203
|
-
return clusters
|
|
204
|
-
|
|
205
|
-
# Return a single label series
|
|
206
|
-
label = masks_to_label(clusters)
|
|
207
|
-
for c in clusters:
|
|
208
|
-
c.remove()
|
|
209
|
-
return label
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def masks_to_label(masks):
|
|
214
|
-
"Convert a list of masks into a single label series"
|
|
215
|
-
|
|
216
|
-
# Ensure all the masks are in the same geometry
|
|
217
|
-
masks = scipy.overlay(masks)
|
|
218
|
-
|
|
219
|
-
# Create a single label array
|
|
220
|
-
array, headers = masks[0].array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
|
|
221
|
-
msg = 'Creating a single label image'
|
|
222
|
-
for m, mask in enumerate(masks[1:]):
|
|
223
|
-
mask.status.progress(m+1, len(masks)-1, msg)
|
|
224
|
-
arr, _ = mask.array(['SliceLocation', 'AcquisitionTime'], pixels_first=True)
|
|
225
|
-
ind = tuple(arr.nonzero())
|
|
226
|
-
array[ind] = m+2
|
|
227
|
-
|
|
228
|
-
# Save label array to disk
|
|
229
|
-
desc = masks[0].SeriesDescription
|
|
230
|
-
label = masks[0].new_sibling(SeriesDescription = desc + ' [Label]')
|
|
231
|
-
label.set_array(array, headers, pixels_first=True)
|
|
232
|
-
|
|
233
|
-
return label
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
# Helper functions
|
|
238
|
-
|
|
239
|
-
def _reset_window(image, array):
|
|
240
|
-
min = np.amin(array)
|
|
241
|
-
max = np.amax(array)
|
|
242
|
-
image.WindowCenter= (max+min)/2
|
|
243
|
-
image.WindowWidth = 0.9*(max-min)
|