dbdicom 0.3.1__py3-none-any.whl → 0.3.3__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/api.py +38 -23
- dbdicom/database.py +126 -0
- dbdicom/dataset.py +35 -60
- dbdicom/dbd.py +221 -201
- 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 +317 -235
- dbdicom/sop_classes/mr_image.py +156 -143
- dbdicom/sop_classes/parametric_map.py +93 -22
- dbdicom/utils/image.py +10 -10
- {dbdicom-0.3.1.dist-info → dbdicom-0.3.3.dist-info}/METADATA +2 -4
- {dbdicom-0.3.1.dist-info → dbdicom-0.3.3.dist-info}/RECORD +16 -15
- {dbdicom-0.3.1.dist-info → dbdicom-0.3.3.dist-info}/WHEEL +1 -1
- {dbdicom-0.3.1.dist-info → dbdicom-0.3.3.dist-info}/licenses/LICENSE +0 -0
- {dbdicom-0.3.1.dist-info → dbdicom-0.3.3.dist-info}/top_level.txt +0 -0
dbdicom/sop_classes/mr_image.py
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
# Coded version of DICOM file
|
|
2
|
-
# 'RIDER Neuro MRI-3369019796\03-21-1904-BRAINRESEARCH-00598\14.000000-sag 3d gre c-04769\1-010.dcm'
|
|
3
|
-
# Produced by pydicom codify utility script
|
|
4
1
|
import os
|
|
5
|
-
|
|
2
|
+
|
|
6
3
|
import numpy as np
|
|
7
4
|
import pydicom
|
|
8
5
|
from pydicom.dataset import FileMetaDataset, Dataset, FileDataset
|
|
@@ -14,7 +11,6 @@ from pydicom.uid import (
|
|
|
14
11
|
)
|
|
15
12
|
|
|
16
13
|
from datetime import datetime
|
|
17
|
-
import tempfile
|
|
18
14
|
|
|
19
15
|
import dbdicom.utils.image as image
|
|
20
16
|
|
|
@@ -22,168 +18,64 @@ import dbdicom.utils.image as image
|
|
|
22
18
|
def pixel_data(ds):
|
|
23
19
|
"""Read the pixel array from an MR image"""
|
|
24
20
|
|
|
25
|
-
#array = ds.pixel_array.astype(np.float64)
|
|
26
|
-
#array = ds.pixel_array
|
|
27
|
-
#array = np.frombuffer(ds.PixelData, dtype=np.uint16).reshape(ds.Rows, ds.Columns)
|
|
28
|
-
#array = array.astype(np.float32)
|
|
29
|
-
|
|
30
21
|
array = ds.pixel_array
|
|
31
22
|
array = array.astype(np.float32)
|
|
32
23
|
if [0x2005, 0x100E] in ds: # 'Philips Rescale Slope'
|
|
33
24
|
slope = ds[(0x2005, 0x100E)].value
|
|
34
25
|
intercept = ds[(0x2005, 0x100D)].value
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
if (intercept == 0) and (slope == 1):
|
|
27
|
+
array = array.astype(np.int16)
|
|
28
|
+
else:
|
|
29
|
+
array = array.astype(np.float32)
|
|
30
|
+
array -= intercept
|
|
31
|
+
array /= slope
|
|
37
32
|
else:
|
|
38
33
|
slope = float(getattr(ds, 'RescaleSlope', 1))
|
|
39
34
|
intercept = float(getattr(ds, 'RescaleIntercept', 0))
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
if (intercept == 0) and (slope == 1):
|
|
36
|
+
array = array.astype(np.int16)
|
|
37
|
+
else:
|
|
38
|
+
array = array.astype(np.float32)
|
|
39
|
+
array *= slope
|
|
40
|
+
array += intercept
|
|
42
41
|
return np.transpose(array)
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
def set_pixel_data(ds, array):
|
|
46
45
|
|
|
46
|
+
# Delete 'Philips Rescale Slope'
|
|
47
47
|
if (0x2005, 0x100E) in ds:
|
|
48
|
-
del ds[0x2005, 0x100E]
|
|
48
|
+
del ds[0x2005, 0x100E]
|
|
49
49
|
if (0x2005, 0x100D) in ds:
|
|
50
50
|
del ds[0x2005, 0x100D]
|
|
51
51
|
|
|
52
|
+
ds.BitsAllocated = 16
|
|
53
|
+
ds.BitsStored = 16
|
|
54
|
+
ds.HighBit = 15
|
|
55
|
+
|
|
52
56
|
# clipping may slow down a lot
|
|
53
|
-
array = image.clip(array.astype(np.float32))
|
|
54
|
-
array
|
|
55
|
-
array
|
|
57
|
+
#array = image.clip(array.astype(np.float32))
|
|
58
|
+
array = image.clip(array) # remove nan and infs
|
|
59
|
+
if array.dtype==np.int16:
|
|
60
|
+
ds.PixelRepresentation = 1
|
|
61
|
+
ds.RescaleSlope = 1
|
|
62
|
+
ds.RescaleIntercept = 0
|
|
63
|
+
elif array.dtype==np.uint16:
|
|
64
|
+
ds.PixelRepresentation = 0
|
|
65
|
+
ds.RescaleSlope = 1
|
|
66
|
+
ds.RescaleIntercept = 0
|
|
67
|
+
else:
|
|
68
|
+
array, slope, intercept = image.scale_to_range(array, ds.BitsStored)
|
|
69
|
+
ds.PixelRepresentation = 0
|
|
70
|
+
ds.RescaleSlope = 1 / slope
|
|
71
|
+
ds.RescaleIntercept = - intercept / slope
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
ds.RescaleSlope = 1 / slope
|
|
59
|
-
ds.RescaleIntercept = - intercept / slope
|
|
60
|
-
# ds.WindowCenter = (maximum + minimum) / 2
|
|
61
|
-
# ds.WindowWidth = maximum - minimum
|
|
73
|
+
array = np.transpose(array)
|
|
62
74
|
ds.Rows = array.shape[0]
|
|
63
75
|
ds.Columns = array.shape[1]
|
|
64
76
|
ds.PixelData = array.tobytes()
|
|
65
77
|
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
def chat_gpt_3d(num_frames=10, rows=256, columns=256):
|
|
69
|
-
|
|
70
|
-
# File meta info
|
|
71
|
-
file_meta = FileMetaDataset()
|
|
72
|
-
file_meta.MediaStorageSOPClassUID = MRImageStorage
|
|
73
|
-
file_meta.MediaStorageSOPInstanceUID = generate_uid()
|
|
74
|
-
file_meta.ImplementationClassUID = generate_uid()
|
|
75
|
-
file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
|
|
76
|
-
|
|
77
|
-
# Create FileDataset in memory
|
|
78
|
-
ds = FileDataset(
|
|
79
|
-
filename_or_obj=None,
|
|
80
|
-
dataset=Dataset(),
|
|
81
|
-
file_meta=file_meta,
|
|
82
|
-
preamble=b"\0" * 128,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
# Transfer syntax
|
|
86
|
-
ds.is_little_endian = True
|
|
87
|
-
ds.is_implicit_VR = False
|
|
88
|
-
|
|
89
|
-
now = datetime.now()
|
|
90
|
-
|
|
91
|
-
# Required fields
|
|
92
|
-
ds.SOPClassUID = MRImageStorage
|
|
93
|
-
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
|
|
94
|
-
ds.PatientName = "Multi^Frame"
|
|
95
|
-
ds.PatientID = "999999"
|
|
96
|
-
ds.StudyInstanceUID = generate_uid()
|
|
97
|
-
ds.SeriesInstanceUID = generate_uid()
|
|
98
|
-
ds.StudyDate = now.strftime("%Y%m%d")
|
|
99
|
-
ds.StudyTime = now.strftime("%H%M%S")
|
|
100
|
-
ds.Modality = "MR"
|
|
101
|
-
ds.Manufacturer = "PythonPACS"
|
|
102
|
-
ds.StudyID = "1"
|
|
103
|
-
ds.SeriesNumber = "1"
|
|
104
|
-
ds.InstanceNumber = "1"
|
|
105
|
-
|
|
106
|
-
# Image geometry
|
|
107
|
-
ds.Rows = rows
|
|
108
|
-
ds.Columns = columns
|
|
109
|
-
ds.PixelSpacing = [1.0, 1.0]
|
|
110
|
-
ds.ImagePositionPatient = [0.0, 0.0, 0.0]
|
|
111
|
-
ds.ImageOrientationPatient = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
|
|
112
|
-
ds.FrameOfReferenceUID = generate_uid()
|
|
113
|
-
ds.PositionReferenceIndicator = ""
|
|
114
|
-
|
|
115
|
-
# Multi-frame specific
|
|
116
|
-
ds.NumberOfFrames = str(num_frames)
|
|
117
|
-
ds.InstanceNumber = "1"
|
|
118
|
-
|
|
119
|
-
# Pixel data requirements
|
|
120
|
-
ds.SamplesPerPixel = 1
|
|
121
|
-
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
122
|
-
ds.BitsAllocated = 16
|
|
123
|
-
ds.BitsStored = 12
|
|
124
|
-
ds.HighBit = 11
|
|
125
|
-
ds.PixelRepresentation = 0 # unsigned
|
|
126
|
-
|
|
127
|
-
# Create dummy image data (e.g., black frames)
|
|
128
|
-
pixel_array = np.zeros((num_frames, rows, columns), dtype=np.uint16)
|
|
129
|
-
ds.PixelData = pixel_array.tobytes()
|
|
130
|
-
|
|
131
|
-
return ds
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def chat_gpt_2d():
|
|
136
|
-
# Basic identifiers
|
|
137
|
-
file_meta = FileMetaDataset()
|
|
138
|
-
file_meta.MediaStorageSOPClassUID = MRImageStorage
|
|
139
|
-
file_meta.MediaStorageSOPInstanceUID = generate_uid()
|
|
140
|
-
file_meta.ImplementationClassUID = generate_uid()
|
|
141
|
-
|
|
142
|
-
# Create the main dataset
|
|
143
|
-
ds = FileDataset(
|
|
144
|
-
filename_or_obj=None,
|
|
145
|
-
dataset=Dataset(),
|
|
146
|
-
file_meta=file_meta,
|
|
147
|
-
preamble=b"\0" * 128,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
# Set transfer syntax
|
|
151
|
-
ds.is_little_endian = True
|
|
152
|
-
ds.is_implicit_VR = False
|
|
153
|
-
|
|
154
|
-
# Required DICOM tags for MR Image Storage
|
|
155
|
-
now = datetime.now()
|
|
156
|
-
ds.SOPClassUID = MRImageStorage
|
|
157
|
-
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
|
|
158
|
-
ds.PatientName = "Anonymous^Patient"
|
|
159
|
-
ds.PatientID = "123456"
|
|
160
|
-
ds.StudyInstanceUID = generate_uid()
|
|
161
|
-
ds.SeriesInstanceUID = generate_uid()
|
|
162
|
-
ds.StudyDate = now.strftime("%Y%m%d")
|
|
163
|
-
ds.StudyTime = now.strftime("%H%M%S")
|
|
164
|
-
ds.Modality = "MR"
|
|
165
|
-
ds.Manufacturer = "PythonPACS"
|
|
166
|
-
ds.StudyID = "1"
|
|
167
|
-
ds.SeriesNumber = "1"
|
|
168
|
-
ds.InstanceNumber = "1"
|
|
169
|
-
ds.ImagePositionPatient = [0.0, 0.0, 0.0]
|
|
170
|
-
ds.ImageOrientationPatient = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
|
|
171
|
-
ds.FrameOfReferenceUID = generate_uid()
|
|
172
|
-
ds.PositionReferenceIndicator = ""
|
|
173
|
-
ds.Rows = 256
|
|
174
|
-
ds.Columns = 256
|
|
175
|
-
ds.PixelSpacing = [1.0, 1.0]
|
|
176
|
-
ds.BitsAllocated = 16
|
|
177
|
-
ds.BitsStored = 12
|
|
178
|
-
ds.HighBit = 11
|
|
179
|
-
ds.PixelRepresentation = 0 # unsigned
|
|
180
|
-
ds.SamplesPerPixel = 1
|
|
181
|
-
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
182
|
-
ds.PixelData = (b"\0" * (ds.Rows * ds.Columns * 2)) # Dummy black image
|
|
183
|
-
|
|
184
|
-
return ds
|
|
185
|
-
|
|
186
|
-
|
|
187
79
|
def default(): # from the RIDER dataset
|
|
188
80
|
|
|
189
81
|
# File meta info data elements
|
|
@@ -309,6 +201,127 @@ def default(): # from the RIDER dataset
|
|
|
309
201
|
return ds
|
|
310
202
|
|
|
311
203
|
|
|
204
|
+
def chat_gpt_3d(num_frames=10, rows=256, columns=256):
|
|
205
|
+
|
|
206
|
+
# File meta info
|
|
207
|
+
file_meta = FileMetaDataset()
|
|
208
|
+
file_meta.MediaStorageSOPClassUID = MRImageStorage
|
|
209
|
+
file_meta.MediaStorageSOPInstanceUID = generate_uid()
|
|
210
|
+
file_meta.ImplementationClassUID = generate_uid()
|
|
211
|
+
file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
|
|
212
|
+
|
|
213
|
+
# Create FileDataset in memory
|
|
214
|
+
ds = FileDataset(
|
|
215
|
+
filename_or_obj=None,
|
|
216
|
+
dataset=Dataset(),
|
|
217
|
+
file_meta=file_meta,
|
|
218
|
+
preamble=b"\0" * 128,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Transfer syntax
|
|
222
|
+
ds.is_little_endian = True
|
|
223
|
+
ds.is_implicit_VR = False
|
|
224
|
+
|
|
225
|
+
now = datetime.now()
|
|
226
|
+
|
|
227
|
+
# Required fields
|
|
228
|
+
ds.SOPClassUID = MRImageStorage
|
|
229
|
+
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
|
|
230
|
+
ds.PatientName = "Multi^Frame"
|
|
231
|
+
ds.PatientID = "999999"
|
|
232
|
+
ds.StudyInstanceUID = generate_uid()
|
|
233
|
+
ds.SeriesInstanceUID = generate_uid()
|
|
234
|
+
ds.StudyDate = now.strftime("%Y%m%d")
|
|
235
|
+
ds.StudyTime = now.strftime("%H%M%S")
|
|
236
|
+
ds.Modality = "MR"
|
|
237
|
+
ds.Manufacturer = "PythonPACS"
|
|
238
|
+
ds.StudyID = "1"
|
|
239
|
+
ds.SeriesNumber = "1"
|
|
240
|
+
ds.InstanceNumber = "1"
|
|
241
|
+
|
|
242
|
+
# Image geometry
|
|
243
|
+
ds.Rows = rows
|
|
244
|
+
ds.Columns = columns
|
|
245
|
+
ds.PixelSpacing = [1.0, 1.0]
|
|
246
|
+
ds.ImagePositionPatient = [0.0, 0.0, 0.0]
|
|
247
|
+
ds.ImageOrientationPatient = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
|
|
248
|
+
ds.FrameOfReferenceUID = generate_uid()
|
|
249
|
+
ds.PositionReferenceIndicator = ""
|
|
250
|
+
|
|
251
|
+
# Multi-frame specific
|
|
252
|
+
ds.NumberOfFrames = str(num_frames)
|
|
253
|
+
ds.InstanceNumber = "1"
|
|
254
|
+
|
|
255
|
+
# Pixel data requirements
|
|
256
|
+
ds.SamplesPerPixel = 1
|
|
257
|
+
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
258
|
+
ds.BitsAllocated = 16
|
|
259
|
+
ds.BitsStored = 12
|
|
260
|
+
ds.HighBit = 11
|
|
261
|
+
ds.PixelRepresentation = 0 # unsigned
|
|
262
|
+
|
|
263
|
+
# Create dummy image data (e.g., black frames)
|
|
264
|
+
pixel_array = np.zeros((num_frames, rows, columns), dtype=np.uint16)
|
|
265
|
+
ds.PixelData = pixel_array.tobytes()
|
|
266
|
+
|
|
267
|
+
return ds
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def chat_gpt_2d():
|
|
272
|
+
# Basic identifiers
|
|
273
|
+
file_meta = FileMetaDataset()
|
|
274
|
+
file_meta.MediaStorageSOPClassUID = MRImageStorage
|
|
275
|
+
file_meta.MediaStorageSOPInstanceUID = generate_uid()
|
|
276
|
+
file_meta.ImplementationClassUID = generate_uid()
|
|
277
|
+
|
|
278
|
+
# Create the main dataset
|
|
279
|
+
ds = FileDataset(
|
|
280
|
+
filename_or_obj=None,
|
|
281
|
+
dataset=Dataset(),
|
|
282
|
+
file_meta=file_meta,
|
|
283
|
+
preamble=b"\0" * 128,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Set transfer syntax
|
|
287
|
+
ds.is_little_endian = True
|
|
288
|
+
ds.is_implicit_VR = False
|
|
289
|
+
|
|
290
|
+
# Required DICOM tags for MR Image Storage
|
|
291
|
+
now = datetime.now()
|
|
292
|
+
ds.SOPClassUID = MRImageStorage
|
|
293
|
+
ds.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
|
|
294
|
+
ds.PatientName = "Anonymous^Patient"
|
|
295
|
+
ds.PatientID = "123456"
|
|
296
|
+
ds.StudyInstanceUID = generate_uid()
|
|
297
|
+
ds.SeriesInstanceUID = generate_uid()
|
|
298
|
+
ds.StudyDate = now.strftime("%Y%m%d")
|
|
299
|
+
ds.StudyTime = now.strftime("%H%M%S")
|
|
300
|
+
ds.Modality = "MR"
|
|
301
|
+
ds.Manufacturer = "PythonPACS"
|
|
302
|
+
ds.StudyID = "1"
|
|
303
|
+
ds.SeriesNumber = "1"
|
|
304
|
+
ds.InstanceNumber = "1"
|
|
305
|
+
ds.ImagePositionPatient = [0.0, 0.0, 0.0]
|
|
306
|
+
ds.ImageOrientationPatient = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
|
|
307
|
+
ds.FrameOfReferenceUID = generate_uid()
|
|
308
|
+
ds.PositionReferenceIndicator = ""
|
|
309
|
+
ds.Rows = 256
|
|
310
|
+
ds.Columns = 256
|
|
311
|
+
ds.PixelSpacing = [1.0, 1.0]
|
|
312
|
+
ds.BitsAllocated = 16
|
|
313
|
+
ds.BitsStored = 12
|
|
314
|
+
ds.HighBit = 11
|
|
315
|
+
ds.PixelRepresentation = 0 # unsigned
|
|
316
|
+
ds.SamplesPerPixel = 1
|
|
317
|
+
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
318
|
+
ds.PixelData = (b"\0" * (ds.Rows * ds.Columns * 2)) # Dummy black image
|
|
319
|
+
|
|
320
|
+
return ds
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
312
325
|
|
|
313
326
|
|
|
314
327
|
|
|
@@ -6,13 +6,12 @@ from pydicom.uid import generate_uid, ParametricMapStorage
|
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def from_volume(vol):
|
|
10
|
-
pass
|
|
11
9
|
|
|
10
|
+
def default():
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
rows=16
|
|
13
|
+
cols=16
|
|
14
|
+
frames=1
|
|
16
15
|
|
|
17
16
|
# File Meta Information
|
|
18
17
|
file_meta = Dataset()
|
|
@@ -35,8 +34,11 @@ def create_parametric_map(rows=64, cols=64, frames=1):
|
|
|
35
34
|
ds.PatientID = "123456"
|
|
36
35
|
ds.StudyDate = datetime.now().strftime("%Y%m%d")
|
|
37
36
|
ds.StudyTime = datetime.now().strftime("%H%M%S")
|
|
37
|
+
ds.ContentDate = datetime.now().strftime("%Y%m%d")
|
|
38
|
+
ds.ContentTime = datetime.now().strftime("%H%M%S")
|
|
38
39
|
ds.Modality = "OT"
|
|
39
40
|
ds.Manufacturer = "SyntheticGenerator"
|
|
41
|
+
ds.SeriesDescription = 'Minimal parametric map'
|
|
40
42
|
|
|
41
43
|
# General Image
|
|
42
44
|
ds.SeriesNumber = 1
|
|
@@ -46,38 +48,107 @@ def create_parametric_map(rows=64, cols=64, frames=1):
|
|
|
46
48
|
ds.ImageType = ['DERIVED', 'PRIMARY']
|
|
47
49
|
ds.ContentLabel = "PMAP"
|
|
48
50
|
ds.ContentDescription = "Synthetic Parametric Map"
|
|
49
|
-
ds.ContentCreatorName = "
|
|
51
|
+
ds.ContentCreatorName = "dbdicom"
|
|
50
52
|
|
|
51
53
|
# Pixel Data
|
|
52
|
-
ds.Rows = rows
|
|
53
|
-
ds.Columns = cols
|
|
54
54
|
ds.NumberOfFrames = frames
|
|
55
|
-
ds.PixelData = pixel_array.tobytes()
|
|
56
55
|
ds.SamplesPerPixel = 1
|
|
57
56
|
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
57
|
+
|
|
58
|
+
ds.Rows = rows
|
|
59
|
+
ds.Columns = cols
|
|
58
60
|
ds.BitsAllocated = 32
|
|
59
61
|
ds.BitsStored = 32
|
|
60
62
|
ds.HighBit = 31
|
|
61
63
|
ds.PixelRepresentation = 1 # 1 = signed, 0 = unsigned
|
|
62
|
-
ds.FloatPixelData =
|
|
63
|
-
ds.PixelData =
|
|
64
|
+
ds.FloatPixelData = np.zeros((rows, cols), dtype=np.float32).tobytes()
|
|
65
|
+
#ds.PixelData = np.zeros((rows, cols), dtype=np.int16).tobytes()
|
|
66
|
+
|
|
67
|
+
# Required Parametric Map Attributes
|
|
68
|
+
ds.PixelMeasuresSequence = [Dataset()]
|
|
69
|
+
ds.PixelMeasuresSequence[0].SliceThickness = 1.0
|
|
70
|
+
ds.PixelMeasuresSequence[0].PixelSpacing = [1.0, 1.0]
|
|
71
|
+
|
|
72
|
+
ds.FrameOfReferenceUID = pydicom.uid.generate_uid()
|
|
64
73
|
|
|
65
74
|
# Functional Group Sequences (minimal dummy values)
|
|
66
75
|
ds.SharedFunctionalGroupsSequence = [Dataset()]
|
|
67
|
-
ds.
|
|
76
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence = [Dataset()]
|
|
77
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0].PixelSpacing = [1.0, 1.0]
|
|
78
|
+
ds.SharedFunctionalGroupsSequence[0].PlaneOrientationSequence = [Dataset()]
|
|
79
|
+
ds.SharedFunctionalGroupsSequence[0].PlaneOrientationSequence[0].ImageOrientationPatient = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
|
|
80
|
+
|
|
81
|
+
ds.PerFrameFunctionalGroupsSequence = []
|
|
82
|
+
for i in range(ds.NumberOfFrames):
|
|
83
|
+
frame = Dataset()
|
|
84
|
+
frame.PlanePositionSequence = [Dataset()]
|
|
85
|
+
frame.PlanePositionSequence[0].ImagePositionPatient = [0.0, 0.0, float(i)]
|
|
86
|
+
ds.PerFrameFunctionalGroupsSequence.append(frame)
|
|
87
|
+
|
|
88
|
+
return ds
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def set_pixel_data(ds, array):
|
|
93
|
+
|
|
94
|
+
array = np.transpose(array)
|
|
95
|
+
ds.RescaleSlope = 1
|
|
96
|
+
ds.RescaleIntercept = 0
|
|
97
|
+
ds.Rows = array.shape[0]
|
|
98
|
+
ds.Columns = array.shape[1]
|
|
99
|
+
|
|
100
|
+
if array.dtype==np.int16:
|
|
101
|
+
ds.BitsAllocated = 16
|
|
102
|
+
ds.BitsStored = 16
|
|
103
|
+
ds.HighBit = 15
|
|
104
|
+
ds.PixelRepresentation = 1 # signed
|
|
105
|
+
ds.PixelData = array.tobytes()
|
|
106
|
+
elif array.dtype==np.float32:
|
|
107
|
+
ds.BitsAllocated = 32
|
|
108
|
+
ds.BitsStored = 32
|
|
109
|
+
ds.HighBit = 31
|
|
110
|
+
ds.PixelRepresentation = 1 # signed
|
|
111
|
+
ds.FloatPixelData = array.tobytes()
|
|
112
|
+
elif array.dtype==np.float64:
|
|
113
|
+
ds.BitsAllocated = 64
|
|
114
|
+
ds.BitsStored = 64
|
|
115
|
+
ds.HighBit = 63
|
|
116
|
+
ds.PixelRepresentation = 1 # signed
|
|
117
|
+
ds.DoubleFloatPixelData = array.tobytes()
|
|
118
|
+
else:
|
|
119
|
+
raise ValueError(
|
|
120
|
+
f"Parametric map storage currently only available for "
|
|
121
|
+
f"32-bit float, 64-bit float or 16-bit int."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def pixel_data(ds):
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
array = ds.pixel_array
|
|
129
|
+
except:
|
|
130
|
+
raise ValueError("Dataset has no pixel data.")
|
|
131
|
+
|
|
132
|
+
if ds.PixelRepresentation != 1:
|
|
133
|
+
raise ValueError(
|
|
134
|
+
"Currently only signed integer or floating point supported."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
slope = float(getattr(ds, 'RescaleSlope', 1))
|
|
138
|
+
intercept = float(getattr(ds, 'RescaleIntercept', 0))
|
|
139
|
+
array *= slope
|
|
140
|
+
array += intercept
|
|
141
|
+
if hasattr(ds, 'PixelData'):
|
|
142
|
+
array = array.astype(np.int16)
|
|
143
|
+
elif hasattr(ds, 'FloatPixelData'):
|
|
144
|
+
array = array.astype(np.float32)
|
|
145
|
+
elif hasattr(ds, 'DoubleFloatPixelData'):
|
|
146
|
+
array = array.astype(np.float64)
|
|
147
|
+
return np.transpose(array)
|
|
148
|
+
|
|
68
149
|
|
|
69
|
-
# Add dummy Dimension Organization
|
|
70
|
-
ds.DimensionOrganizationSequence = [Dataset()]
|
|
71
|
-
ds.DimensionOrganizationSequence[0].DimensionOrganizationUID = generate_uid()
|
|
72
150
|
|
|
73
|
-
ds.DimensionIndexSequence = [
|
|
74
|
-
Dataset() for _ in range(1)
|
|
75
|
-
]
|
|
76
|
-
ds.DimensionIndexSequence[0].DimensionOrganizationUID = ds.DimensionOrganizationSequence[0].DimensionOrganizationUID
|
|
77
|
-
ds.DimensionIndexSequence[0].DimensionIndexPointer = (0x0020, 0x9157) # In-stack position
|
|
78
|
-
ds.DimensionIndexSequence[0].FunctionalGroupPointer = (0x0020, 0x9116)
|
|
79
151
|
|
|
80
|
-
return ds
|
|
81
152
|
|
|
82
153
|
|
|
83
154
|
|
dbdicom/utils/image.py
CHANGED
|
@@ -16,9 +16,10 @@ def affine_matrix( # single slice function
|
|
|
16
16
|
column_cosine = np.array(image_orientation[3:])
|
|
17
17
|
slice_cosine = np.cross(row_cosine, column_cosine)
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# This should not be addressed here
|
|
20
|
+
# # The coronal orientation has a left-handed reference frame
|
|
21
|
+
# if np.array_equal(np.around(image_orientation, 3), [1,0,0,0,0,-1]):
|
|
22
|
+
# slice_cosine = -slice_cosine
|
|
22
23
|
|
|
23
24
|
affine = np.identity(4, dtype=np.float32)
|
|
24
25
|
affine[:3, 0] = row_cosine * column_spacing
|
|
@@ -39,9 +40,9 @@ def slice_location(
|
|
|
39
40
|
column_cosine = np.array(image_orientation[3:])
|
|
40
41
|
slice_cosine = np.cross(row_cosine, column_cosine)
|
|
41
42
|
|
|
42
|
-
# The coronal orientation has a left-handed reference frame
|
|
43
|
-
if np.array_equal(np.around(image_orientation, 3), [1,0,0,0,0,-1]):
|
|
44
|
-
|
|
43
|
+
# # The coronal orientation has a left-handed reference frame
|
|
44
|
+
# if np.array_equal(np.around(image_orientation, 3), [1,0,0,0,0,-1]):
|
|
45
|
+
# slice_cosine = -slice_cosine
|
|
45
46
|
|
|
46
47
|
return np.dot(np.array(image_position), slice_cosine)
|
|
47
48
|
|
|
@@ -53,14 +54,13 @@ def dismantle_affine_matrix(affine):
|
|
|
53
54
|
# ImagePositionPatient_i = ImagePositionPatient + i * SpacingBetweenSlices * slice_cosine
|
|
54
55
|
column_spacing = np.linalg.norm(affine[:3, 0])
|
|
55
56
|
row_spacing = np.linalg.norm(affine[:3, 1])
|
|
56
|
-
|
|
57
|
+
slice_spacing = np.linalg.norm(affine[:3, 2])
|
|
57
58
|
row_cosine = affine[:3, 0] / column_spacing
|
|
58
59
|
column_cosine = affine[:3, 1] / row_spacing
|
|
59
|
-
slice_cosine = affine[:3, 2] /
|
|
60
|
+
slice_cosine = affine[:3, 2] / slice_spacing
|
|
60
61
|
return {
|
|
61
62
|
'PixelSpacing': [row_spacing, column_spacing],
|
|
62
|
-
|
|
63
|
-
'SliceThickness': slice_thickness,
|
|
63
|
+
'SpacingBetweenSlices': slice_spacing,
|
|
64
64
|
'ImageOrientationPatient': row_cosine.tolist() + column_cosine.tolist(),
|
|
65
65
|
'ImagePositionPatient': affine[:3, 3].tolist(), # first slice for a volume
|
|
66
66
|
'slice_cosine': slice_cosine.tolist()}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbdicom
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A pythonic interface for reading and writing DICOM databases
|
|
5
5
|
Author-email: Steven Sourbron <s.sourbron@sheffield.ac.uk>, Ebony Gunwhy <e.gunwhy@sheffield.ac.uk>
|
|
6
6
|
Project-URL: Homepage, https://openmiblab.github.io/dbdicom/
|
|
@@ -22,7 +22,5 @@ Requires-Dist: importlib-resources
|
|
|
22
22
|
Requires-Dist: numpy
|
|
23
23
|
Requires-Dist: pandas
|
|
24
24
|
Requires-Dist: vreg
|
|
25
|
-
Requires-Dist: pydicom
|
|
26
|
-
Requires-Dist: python-gdcm
|
|
27
|
-
Requires-Dist: pylibjpeg-libjpeg
|
|
25
|
+
Requires-Dist: pydicom[basic,pixeldata]
|
|
28
26
|
Dynamic: license-file
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
dbdicom/__init__.py,sha256=DyogeTraV6o-FgWdBCbtVEaMmdkMQHkYkraDIE0t8OA,25
|
|
2
|
-
dbdicom/api.py,sha256=
|
|
2
|
+
dbdicom/api.py,sha256=MHJBHY_ikUj93T8Vt0GAjvjLFJL-2IdIFKhr8T-bvVI,8871
|
|
3
3
|
dbdicom/const.py,sha256=BqBiRRjeiSqDr1W6YvaayD8WKCjG4Cny2NT0GeLM6bI,4269
|
|
4
|
-
dbdicom/
|
|
5
|
-
dbdicom/
|
|
6
|
-
dbdicom/
|
|
4
|
+
dbdicom/database.py,sha256=_LUbH7gc9l7j_63AC71DjwxgTUwbEjHSy5kuvRw75Hw,4764
|
|
5
|
+
dbdicom/dataset.py,sha256=hLAyFlN7zQ-dOzI9V67aHfTq3VtpvCI7_83tnBqXObE,21880
|
|
6
|
+
dbdicom/dbd.py,sha256=ZUXmLcQ2C6L9UTanGzTSte1XIJAcQoNNsEpweXW8N50,29921
|
|
7
|
+
dbdicom/register.py,sha256=VPxS2oTlONxx5eNdGRbvFeEfQo69jo5YDp7L_Vb4x28,23676
|
|
7
8
|
dbdicom/external/__init__.py,sha256=XNQqfspyf6vFGedXlRKZsUB8k8E-0W19Uamwn8Aioxo,316
|
|
8
|
-
dbdicom/external/__pycache__/__init__.cpython-311.pyc,sha256=
|
|
9
|
+
dbdicom/external/__pycache__/__init__.cpython-311.pyc,sha256=pXAQ35ixd92fm6YcuHgzR1t6RcASQ-cHhU1wOA5b8sw,542
|
|
9
10
|
dbdicom/external/dcm4che/README.md,sha256=0aAGRs36W3_0s5LzWHRGf_tqariS_JP4iJggaxnD4Xw,8987
|
|
10
11
|
dbdicom/external/dcm4che/__init__.py,sha256=YwpeMCLrxffGOkchsGjgAuB6ia3VX_tx9Y7ru9EWtoY,35
|
|
11
|
-
dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc,sha256=
|
|
12
|
+
dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc,sha256=FB8wyWqXDUt_1P-QmE4yt9uD6dDm5YqYWjqVuRwGdSo,256
|
|
12
13
|
dbdicom/external/dcm4che/bin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
14
|
dbdicom/external/dcm4che/bin/deidentify,sha256=64MNIEpp-CWzFSb6TV0KtyCBvD7XyEsovRjBeyxDqSc,1698
|
|
14
15
|
dbdicom/external/dcm4che/bin/deidentify.bat,sha256=kVXUkcy1C4Y3KjC2NJwmmR0pufSJWmaof_LR5CTAxMg,1455
|
|
15
16
|
dbdicom/external/dcm4che/bin/emf2sf,sha256=svCzkZ-QhdVTV0NNHOpBiwNBMODVWZHJIFA7cWaN2bM,1622
|
|
16
17
|
dbdicom/external/dcm4che/bin/emf2sf.bat,sha256=Vh0ry9KNJX_WXcyCrLSxbJ_6Crot9rjmwi__u2GZqLY,1375
|
|
17
|
-
dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc,sha256=
|
|
18
|
+
dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc,sha256=GYcm47ETjYvRUN5RPTe5R-c0prd14GP8gm96eJcy0uQ,203
|
|
18
19
|
dbdicom/external/dcm4che/etc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
20
|
dbdicom/external/dcm4che/etc/emf2sf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
21
|
dbdicom/external/dcm4che/etc/emf2sf/log4j.properties,sha256=3hHcBFt2oNRjvHtix5bfuEsnKfdv5IYOkbsyoY9g7cM,223
|
|
@@ -35,8 +36,8 @@ dbdicom/external/dcm4che/lib/windows-x86/opencv_java.dll,sha256=QanyzLy0Cd79-aOV
|
|
|
35
36
|
dbdicom/external/dcm4che/lib/windows-x86-64/opencv_java.dll,sha256=TmjW2SbG4MR3GQ95T8xCVVDLgsdKukgaHBPUvWkfXp8,11039232
|
|
36
37
|
dbdicom/sop_classes/ct_image.py,sha256=16PNv_0e1_7cfxE12JWlx5YQeaTAQVzwtXTjxs3aonk,2812
|
|
37
38
|
dbdicom/sop_classes/enhanced_mr_image.py,sha256=13j4EGXniBpJxpzzL3Xa4y3g5OKhMd5Ct7cjPGOYQY4,35496
|
|
38
|
-
dbdicom/sop_classes/mr_image.py,sha256=
|
|
39
|
-
dbdicom/sop_classes/parametric_map.py,sha256=
|
|
39
|
+
dbdicom/sop_classes/mr_image.py,sha256=kNcrWXZ3VC3hhfqjMRjrlZOVqZH3Q5KfWXYLfLD-bEY,10913
|
|
40
|
+
dbdicom/sop_classes/parametric_map.py,sha256=2OKBuC2bo03OEpKqimQS-nVGFp1cKRPYwVgmDGVf1JU,12288
|
|
40
41
|
dbdicom/sop_classes/secondary_capture.py,sha256=wgNRX8qyhV7HR7Jq2tQWPPuGpiRzYl6qPOgK6qFbPUc,4541
|
|
41
42
|
dbdicom/sop_classes/segmentation.py,sha256=I8-PciIoIz27_-dZ4esBZSw0TBBbO8KbNYTiTmVe62g,11465
|
|
42
43
|
dbdicom/sop_classes/ultrasound_multiframe_image.py,sha256=j3KN5R90j6WwPMy01hAN2_XSum5TvksF2MYoNGfX_yE,2797
|
|
@@ -44,10 +45,10 @@ dbdicom/sop_classes/xray_angiographic_image.py,sha256=nWysCGaEWKVNItnOgyJfcGMpS3
|
|
|
44
45
|
dbdicom/utils/arrays.py,sha256=wiqCczLXlNl0qIePVOwCYvbAJhPveNorplkhtGleS48,1121
|
|
45
46
|
dbdicom/utils/dcm4che.py,sha256=Vxq8NYWWK3BuqJkzhBQ89oMqzJlnxqTxgsgTo_Frznc,2317
|
|
46
47
|
dbdicom/utils/files.py,sha256=qhWNJqeWnRjDNbERpC6Mz962_TW9mFdvd2lnBbK3xt4,2259
|
|
47
|
-
dbdicom/utils/image.py,sha256=
|
|
48
|
+
dbdicom/utils/image.py,sha256=D46CD_ezpp2uq8VMqug5Z09fAyoJ9U6VwuxIFNJK8zg,4048
|
|
48
49
|
dbdicom/utils/variables.py,sha256=vUh5cDnmCft5hoXDYXUvfkg5Cy5WlgMAogU38Y_BKRo,5753
|
|
49
|
-
dbdicom-0.3.
|
|
50
|
-
dbdicom-0.3.
|
|
51
|
-
dbdicom-0.3.
|
|
52
|
-
dbdicom-0.3.
|
|
53
|
-
dbdicom-0.3.
|
|
50
|
+
dbdicom-0.3.3.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
51
|
+
dbdicom-0.3.3.dist-info/METADATA,sha256=aMYhKPS907fOj0pgSkQh7vbFeYspNvJP5-ZYNZ6LpMs,1030
|
|
52
|
+
dbdicom-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
53
|
+
dbdicom-0.3.3.dist-info/top_level.txt,sha256=nJWxXg4YjD6QblfmhrzTMXcr8FSKNc0Yk-CAIDUsYkQ,8
|
|
54
|
+
dbdicom-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|