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.
- dbdicom/__init__.py +3 -25
- dbdicom/api.py +496 -0
- dbdicom/const.py +144 -0
- dbdicom/database.py +133 -0
- dbdicom/dataset.py +471 -0
- dbdicom/dbd.py +1290 -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/external/dcm4che/bin/emf2sf +57 -57
- dbdicom/register.py +402 -0
- dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
- dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +206 -160
- dbdicom/sop_classes/mr_image.py +338 -0
- dbdicom/sop_classes/parametric_map.py +381 -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 +142 -0
- dbdicom/utils/files.py +0 -20
- dbdicom/utils/image.py +43 -466
- dbdicom/utils/pydicom_dataset.py +386 -0
- dbdicom-0.3.16.dist-info/METADATA +26 -0
- dbdicom-0.3.16.dist-info/RECORD +54 -0
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/WHEEL +1 -1
- dbdicom/create.py +0 -450
- dbdicom/ds/__init__.py +0 -10
- dbdicom/ds/create.py +0 -63
- dbdicom/ds/dataset.py +0 -841
- dbdicom/ds/dictionaries.py +0 -620
- dbdicom/ds/types/mr_image.py +0 -267
- dbdicom/ds/types/parametric_map.py +0 -226
- dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
- dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
- dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
- dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
- dbdicom/manager.py +0 -2077
- dbdicom/message.py +0 -119
- dbdicom/record.py +0 -1526
- dbdicom/types/database.py +0 -107
- dbdicom/types/instance.py +0 -184
- dbdicom/types/patient.py +0 -40
- dbdicom/types/series.py +0 -816
- dbdicom/types/study.py +0 -58
- dbdicom/utils/variables.py +0 -155
- dbdicom/utils/vreg.py +0 -2626
- dbdicom/wrappers/__init__.py +0 -7
- dbdicom/wrappers/dipy.py +0 -462
- dbdicom/wrappers/elastix.py +0 -855
- dbdicom/wrappers/numpy.py +0 -119
- dbdicom/wrappers/scipy.py +0 -1413
- dbdicom/wrappers/skimage.py +0 -1030
- dbdicom/wrappers/sklearn.py +0 -151
- dbdicom/wrappers/vreg.py +0 -273
- dbdicom-0.2.0.dist-info/METADATA +0 -276
- dbdicom-0.2.0.dist-info/RECORD +0 -81
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info/licenses}/LICENSE +0 -0
- {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/top_level.txt +0 -0
|
@@ -1,46 +1,228 @@
|
|
|
1
1
|
# Coded version of DICOM file 'C:\Users\steve\Dropbox\Software\QIB-Sheffield\dbdicom\tests\data\MULTIFRAME\IM_0010'
|
|
2
2
|
# Produced by pydicom codify utility script
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
|
|
3
6
|
import numpy as np
|
|
7
|
+
import vreg
|
|
4
8
|
|
|
9
|
+
import pydicom
|
|
5
10
|
from pydicom.dataset import Dataset, FileMetaDataset
|
|
6
11
|
from pydicom.sequence import Sequence
|
|
12
|
+
from pydicom.uid import ExplicitVRLittleEndian, generate_uid
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
import dbdicom.utils.image as image_utils
|
|
15
|
+
from dbdicom.utils.pydicom_dataset import set_values, get_values
|
|
10
16
|
|
|
11
|
-
class EnhancedMRImage(DbDataset):
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
def from_volume(vol:vreg.Volume3D):
|
|
19
|
+
"""
|
|
20
|
+
Build an Enhanced MR Image DICOM dataset from N+3D array.
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
vol: vreg Volume3D
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
pydicom dataset
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# Flatten frames
|
|
32
|
+
frames = vol.values.reshape(vol.shape[:2] + (-1,))
|
|
33
|
+
geom = image_utils.dismantle_affine_matrix(vol.affine)
|
|
34
|
+
|
|
35
|
+
# --- FileDataset ---
|
|
36
|
+
ds = Dataset()
|
|
21
37
|
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
# File Meta
|
|
39
|
+
ds.file_meta = FileMetaDataset()
|
|
40
|
+
ds.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
|
|
41
|
+
ds.file_meta.MediaStorageSOPClassUID = "1.2.840.10008.5.1.4.1.1.4.1" # Enhanced MR
|
|
42
|
+
|
|
43
|
+
ds.is_little_endian = True
|
|
44
|
+
ds.is_implicit_VR = False
|
|
45
|
+
ds.SOPClassUID = ds.file_meta.MediaStorageSOPClassUID
|
|
46
|
+
ds.SOPInstanceUID = generate_uid()
|
|
47
|
+
|
|
48
|
+
# Study/Series
|
|
49
|
+
ds.SeriesInstanceUID = generate_uid()
|
|
50
|
+
ds.StudyInstanceUID = generate_uid()
|
|
51
|
+
ds.FrameOfReferenceUID = generate_uid()
|
|
52
|
+
ds.Modality = "MR"
|
|
53
|
+
ds.PatientName = "Test^Patient"
|
|
54
|
+
ds.PatientID = "123456"
|
|
55
|
+
ds.StudyDate = datetime.date.today().strftime("%Y%m%d")
|
|
56
|
+
ds.StudyTime = datetime.datetime.now().strftime("%H%M%S")
|
|
57
|
+
|
|
58
|
+
# Image attributes
|
|
59
|
+
ds.Columns = vol.shape[0]
|
|
60
|
+
ds.Rows = vol.shape[1]
|
|
61
|
+
ds.NumberOfFrames = np.prod(vol.shape[2:])
|
|
62
|
+
ds.SamplesPerPixel = 1
|
|
63
|
+
ds.PhotometricInterpretation = "MONOCHROME2"
|
|
64
|
+
ds.BitsAllocated = 16
|
|
65
|
+
ds.BitsStored = 16
|
|
66
|
+
ds.HighBit = 15
|
|
67
|
+
ds.PixelRepresentation = 1
|
|
68
|
+
ds.PixelSpacing = list(vol.spacing[:2])
|
|
69
|
+
ds.SliceThickness = vol.spacing[2]
|
|
24
70
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
71
|
+
# Dimensions
|
|
72
|
+
ds.DimensionOrganizationSequence = Sequence([Dataset()])
|
|
73
|
+
ds.DimensionOrganizationSequence[0].DimensionOrganizationUID = generate_uid()
|
|
74
|
+
ds.DimensionIndexSequence = Sequence()
|
|
75
|
+
for axis in ['SliceLocation'] + vol.dims:
|
|
76
|
+
axis_dimension_item = Dataset()
|
|
77
|
+
axis_dimension_item.DimensionIndexPointer = pydicom.tag.Tag(axis)
|
|
78
|
+
axis_dimension_item.DimensionDescriptionLabel = axis
|
|
79
|
+
ds.DimensionIndexSequence.append(axis_dimension_item)
|
|
80
|
+
|
|
81
|
+
# Shared Functional Groups
|
|
82
|
+
ds.SharedFunctionalGroupsSequence = [Dataset()]
|
|
83
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence = [Dataset()]
|
|
84
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0].PixelSpacing = ds.PixelSpacing
|
|
85
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0].SliceThickness = ds.SliceThickness
|
|
86
|
+
ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0].SpacingBetweenSlices = ds.SliceThickness
|
|
87
|
+
ds.SharedFunctionalGroupsSequence[0].PlaneOrientationSequence = [Dataset()]
|
|
88
|
+
ds.SharedFunctionalGroupsSequence[0].PlaneOrientationSequence[0].ImageOrientationPatient = geom['ImageOrientationPatient']
|
|
89
|
+
|
|
90
|
+
# Per-frame Functional Groups
|
|
91
|
+
PerFrameFunctionalGroupsSequence = []
|
|
92
|
+
|
|
93
|
+
for flat_index in range(frames.shape[-1]):
|
|
94
|
+
frame_ds = Dataset()
|
|
95
|
+
vol_idx, slice_idx = divmod(flat_index, vol.shape[2])
|
|
96
|
+
indices = np.unravel_index(vol_idx, vol.shape[3:])
|
|
97
|
+
dim_values = [i + 1 for i in indices]
|
|
98
|
+
|
|
99
|
+
# Frame content
|
|
100
|
+
frame_ds.FrameContentSequence = [Dataset()]
|
|
101
|
+
frame_ds.FrameContentSequence[0].DimensionIndexValues = dim_values
|
|
102
|
+
|
|
103
|
+
# Plane position
|
|
104
|
+
frame_ds.PlanePositionSequence = [Dataset()]
|
|
105
|
+
frame_ds.PlanePositionSequence[0].ImagePositionPatient = list(np.array(geom['ImagePositionPatient']) + slice_idx * vol.spacing[2] * np.array(geom['slice_cosine']))
|
|
106
|
+
|
|
107
|
+
# Plane orientation
|
|
108
|
+
frame_ds.PlaneOrientationSequence = [Dataset()]
|
|
109
|
+
frame_ds.PlaneOrientationSequence[0].ImageOrientationPatient = geom['ImageOrientationPatient']
|
|
110
|
+
|
|
111
|
+
# Assign parameters using dims as DICOM keywords
|
|
112
|
+
for ax_i, axis in enumerate(vol.dims):
|
|
113
|
+
val = vol.coords[ax_i][indices]
|
|
114
|
+
|
|
115
|
+
sequence, attr = axis.split("/")
|
|
116
|
+
if not hasattr(frame_ds, sequence):
|
|
117
|
+
setattr(frame_ds, sequence, [Dataset()])
|
|
118
|
+
sequence_ds = getattr(frame_ds, sequence)[0]
|
|
119
|
+
set_values(sequence_ds, attr, val)
|
|
120
|
+
|
|
121
|
+
# Frame anatomy & type
|
|
122
|
+
frame_ds.FrameAnatomySequence = [Dataset()]
|
|
123
|
+
frame_ds.FrameAnatomySequence[0].AnatomicRegionSequence = [Dataset()]
|
|
124
|
+
frame_ds.FrameAnatomySequence[0].AnatomicRegionSequence[0].CodeValue = "12738006"
|
|
125
|
+
frame_ds.FrameAnatomySequence[0].AnatomicRegionSequence[0].CodingSchemeDesignator = "SCT"
|
|
126
|
+
frame_ds.FrameAnatomySequence[0].AnatomicRegionSequence[0].CodeMeaning = "Brain"
|
|
127
|
+
|
|
128
|
+
frame_ds.MRImageFrameTypeSequence = [Dataset()]
|
|
129
|
+
frame_ds.MRImageFrameTypeSequence[0].FrameType = ["ORIGINAL", "PRIMARY", "M", "NONE"]
|
|
130
|
+
|
|
131
|
+
# Acquisition datetime
|
|
132
|
+
frame_ds.FrameAcquisitionDateTime = (
|
|
133
|
+
datetime.datetime.now() + datetime.timedelta(seconds=flat_index)
|
|
134
|
+
).strftime("%Y%m%d%H%M%S.%f")
|
|
135
|
+
|
|
136
|
+
PerFrameFunctionalGroupsSequence.append(frame_ds)
|
|
137
|
+
|
|
138
|
+
ds.PerFrameFunctionalGroupsSequence = PerFrameFunctionalGroupsSequence
|
|
139
|
+
|
|
140
|
+
# Pixel Data
|
|
141
|
+
ds.PixelData = b"".join([f.tobytes() for f in frames])
|
|
142
|
+
|
|
143
|
+
return ds
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# THIS NEEDS DEBUGGING
|
|
148
|
+
def to_volume(ds):
|
|
149
|
+
"""
|
|
150
|
+
Write an Enhanced MR Image DICOM from N+3D array.
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
ds: pydicom Dataset
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
vreg Volume3D
|
|
159
|
+
"""
|
|
160
|
+
values = pixel_data(ds).T # need reshape
|
|
161
|
+
dims = [item.DimensionDescriptionLabel
|
|
162
|
+
for item in ds.DimensionIndexSequence[1:]] # handle slice location
|
|
163
|
+
affine = image_utils.affine_matrix(
|
|
164
|
+
get_values(ds.SharedFunctionalGroupsSequence[0].PlaneOrientationSequence[0], 'ImageOrientationPatient'),
|
|
165
|
+
get_values(ds.SharedFunctionalGroupsSequence[0].PlanePositionSequence[0], 'ImagePositionPatient'),
|
|
166
|
+
get_values(ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0], 'PixelSpacing'),
|
|
167
|
+
get_values(ds.SharedFunctionalGroupsSequence[0].PixelMeasuresSequence[0], 'SliceThickness'), # derive from slice_loc in per-frame
|
|
168
|
+
)
|
|
169
|
+
coords = np.zeros((len(dims), ds.NumberOfFrames))
|
|
170
|
+
for d, dim in enumerate(dims):
|
|
171
|
+
for flat_index in range(ds.NumberOfFrames):
|
|
172
|
+
found_val = False
|
|
173
|
+
frame_ds = ds.PerFrameFunctionalGroupsSequence[flat_index]
|
|
174
|
+
for sequence in frame_ds:
|
|
175
|
+
if hasattr(sequence[0], dim):
|
|
176
|
+
coords[d, flat_index] = get_values(sequence[0], dim)
|
|
177
|
+
found_val=True
|
|
178
|
+
break
|
|
179
|
+
if not found_val:
|
|
180
|
+
raise ValueError(f"Dimension {dim} not found in frame {flat_index}")
|
|
181
|
+
shape = [len(np.unique(coords[d,:])) for d in range(len(dims))]
|
|
182
|
+
if np.prod(shape) == ds.NumberOfFrames:
|
|
183
|
+
values = values.reshape(values.shape[:2] + tuple(shape))
|
|
184
|
+
else:
|
|
185
|
+
values = values.reshape(values.shape[:2] + (1, ds.NumberOfFrames) )
|
|
186
|
+
|
|
187
|
+
return vreg.volume(values, affine, coords, dims)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def pixel_data(ds):
|
|
193
|
+
"""Read the pixel array from an MR image"""
|
|
194
|
+
|
|
195
|
+
array = ds.pixel_array
|
|
196
|
+
array = array.astype(np.float32)
|
|
197
|
+
if [0x2005, 0x100E] in ds: # 'Philips Rescale Slope'
|
|
198
|
+
slope = ds[(0x2005, 0x100E)].value
|
|
199
|
+
intercept = ds[(0x2005, 0x100D)].value
|
|
200
|
+
if (intercept == 0) and (slope == 1):
|
|
201
|
+
array = array.astype(np.int16)
|
|
202
|
+
else:
|
|
203
|
+
array = array.astype(np.float32)
|
|
204
|
+
array -= intercept
|
|
205
|
+
array /= slope
|
|
206
|
+
else:
|
|
207
|
+
slope = float(getattr(ds, 'RescaleSlope', 1))
|
|
208
|
+
intercept = float(getattr(ds, 'RescaleIntercept', 0))
|
|
209
|
+
if (intercept == 0) and (slope == 1):
|
|
210
|
+
array = array.astype(np.int16)
|
|
211
|
+
else:
|
|
212
|
+
array = array.astype(np.float32)
|
|
213
|
+
array *= slope
|
|
214
|
+
array += intercept
|
|
215
|
+
return np.transpose(array)
|
|
29
216
|
|
|
30
|
-
def get_pixel_array(self):
|
|
31
|
-
return get_pixel_array(self)
|
|
32
217
|
|
|
33
|
-
def set_pixel_array(self, array, value_range=None):
|
|
34
|
-
set_pixel_array(self, array, value_range=value_range)
|
|
35
218
|
|
|
36
|
-
def image_type(self):
|
|
37
|
-
return image_type(self)
|
|
38
219
|
|
|
39
|
-
def signal_type(self):
|
|
40
|
-
return signal_type(self)
|
|
41
220
|
|
|
42
221
|
|
|
43
|
-
def
|
|
222
|
+
def default(): # UKRIN-MAPS
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
ds = Dataset()
|
|
44
226
|
|
|
45
227
|
# File meta info data elements
|
|
46
228
|
ds.file_meta = FileMetaDataset()
|
|
@@ -497,139 +679,3 @@ def ukrin_maps_per_frame_functional_group():
|
|
|
497
679
|
|
|
498
680
|
return ds
|
|
499
681
|
|
|
500
|
-
def get_window(ds):
|
|
501
|
-
"""Centre and width of the pixel data after applying rescale slope and intercept.
|
|
502
|
-
|
|
503
|
-
In this case retrieve the centre and width values of the first frame
|
|
504
|
-
NOT In USE
|
|
505
|
-
"""
|
|
506
|
-
|
|
507
|
-
centre = ds.PerFrameFunctionalGroupsSequence[0].FrameVOILUTSequence[0].WindowCenter
|
|
508
|
-
width = ds.PerFrameFunctionalGroupsSequence[0].FrameVOILUTSequence[0].WindowWidth
|
|
509
|
-
if centre is None or width is None:
|
|
510
|
-
array = ds.get_pixel_array()
|
|
511
|
-
if centre is None:
|
|
512
|
-
centre = np.median(array)
|
|
513
|
-
if width is None:
|
|
514
|
-
p = np.percentile(array, [25, 75])
|
|
515
|
-
width = p[1] - p[0]
|
|
516
|
-
|
|
517
|
-
return centre, width
|
|
518
|
-
|
|
519
|
-
def get_pixel_array(ds):
|
|
520
|
-
|
|
521
|
-
array = ds.pixel_array.astype(np.float32)
|
|
522
|
-
frames = ds.PerFrameFunctionalGroupsSequence
|
|
523
|
-
for index, frame in enumerate(frames):
|
|
524
|
-
slice = np.squeeze(array[index, ...])
|
|
525
|
-
if [0x2005, 0x100E] in ds: # 'Philips Rescale Slope'
|
|
526
|
-
slope = ds[(0x2005, 0x100E)].value
|
|
527
|
-
intercept = ds[(0x2005, 0x100D)].value
|
|
528
|
-
slice = (slice - intercept) / slope
|
|
529
|
-
else:
|
|
530
|
-
transform = frame.PixelValueTransformationSequence[0]
|
|
531
|
-
slope = float(getattr(transform, 'RescaleSlope', 1))
|
|
532
|
-
intercept = float(getattr(transform, 'RescaleIntercept', 0))
|
|
533
|
-
slice = slice * slope + intercept
|
|
534
|
-
array[index, ...] = np.transpose(slice)
|
|
535
|
-
|
|
536
|
-
return array
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
def set_pixel_array(ds, array, value_range=None):
|
|
540
|
-
|
|
541
|
-
if (0x2005, 0x100E) in ds:
|
|
542
|
-
del ds[0x2005, 0x100E] # Delete 'Philips Rescale Slope'
|
|
543
|
-
if (0x2005, 0x100D) in ds:
|
|
544
|
-
del ds[0x2005, 0x100D]
|
|
545
|
-
|
|
546
|
-
array = image.clip(array, value_range=value_range)
|
|
547
|
-
array, slope, intercept = image.scale_to_range(array, ds.BitsAllocated)
|
|
548
|
-
array = np.transpose(array, (0, 2, 1))
|
|
549
|
-
|
|
550
|
-
maximum = np.amax(array)
|
|
551
|
-
minimum = np.amin(array)
|
|
552
|
-
shape = np.shape(array)
|
|
553
|
-
|
|
554
|
-
ds.NumberOfFrames = np.shape(array)[0]
|
|
555
|
-
del ds.PerFrameFunctionalGroupsSequence[ds.NumberOfFrames:]
|
|
556
|
-
|
|
557
|
-
ds.PixelRepresentation = 0
|
|
558
|
-
ds.SmallestImagePixelValue = int(maximum)
|
|
559
|
-
ds.LargestImagePixelValue = int(minimum)
|
|
560
|
-
ds.RescaleSlope = 1 / slope
|
|
561
|
-
ds.RescaleIntercept = - intercept / slope
|
|
562
|
-
ds.WindowCenter = (maximum + minimum) / 2
|
|
563
|
-
ds.WindowWidth = maximum - minimum
|
|
564
|
-
ds.Rows = shape[0]
|
|
565
|
-
ds.Columns = shape[1]
|
|
566
|
-
ds.PixelData = array.tobytes()
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
def image_type(ds):
|
|
570
|
-
"""Determine if a dataset is Magnitude, Phase, Real or Imaginary"""
|
|
571
|
-
|
|
572
|
-
image_type = []
|
|
573
|
-
for slice in ds.PerFrameFunctionalGroupsSequence:
|
|
574
|
-
sequence = slice.MRImageFrameTypeSequence[0]
|
|
575
|
-
|
|
576
|
-
if hasattr(sequence, 'FrameType'):
|
|
577
|
-
type = set(sequence.FrameType)
|
|
578
|
-
if set(['M', 'MAGNITUDE']).intersection(type):
|
|
579
|
-
image_type.append('MAGNITUDE')
|
|
580
|
-
elif set(['P', 'PHASE']).intersection(type):
|
|
581
|
-
image_type.append('PHASE')
|
|
582
|
-
elif set(['R', 'REAL']).intersection(type):
|
|
583
|
-
image_type.append('REAL')
|
|
584
|
-
elif set(['I', 'IMAGINARY']).intersection(type):
|
|
585
|
-
image_type.append('IMAGINARY')
|
|
586
|
-
elif hasattr(sequence, 'ComplexImageComponent'):
|
|
587
|
-
type = set(sequence.ComplexImageComponent)
|
|
588
|
-
if set(['M', 'MAGNITUDE']).intersection(type):
|
|
589
|
-
image_type.append('MAGNITUDE')
|
|
590
|
-
elif set(['P', 'PHASE']).intersection(type):
|
|
591
|
-
image_type.append('PHASE')
|
|
592
|
-
elif set(['R', 'REAL']).intersection(type):
|
|
593
|
-
image_type.append('REAL')
|
|
594
|
-
elif set(['I', 'IMAGINARY']).intersection(type):
|
|
595
|
-
image_type.append('IMAGINARY')
|
|
596
|
-
else:
|
|
597
|
-
image_type.append('UNKNOWN')
|
|
598
|
-
|
|
599
|
-
return image_type
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
def signal_type(ds):
|
|
603
|
-
"""Determine if an image is Water, Fat, In-Phase, Out-phase image or None"""
|
|
604
|
-
|
|
605
|
-
signal_type = []
|
|
606
|
-
for slice in ds.PerFrameFunctionalGroupsSequence:
|
|
607
|
-
sequence = slice.MRImageFrameTypeSequence[0]
|
|
608
|
-
|
|
609
|
-
if hasattr(sequence, 'FrameType'):
|
|
610
|
-
type = set(sequence.FrameType)
|
|
611
|
-
if set(['W', 'WATER']).intersection(type):
|
|
612
|
-
signal_type.append('WATER')
|
|
613
|
-
elif set(['F', 'FAT']).intersection(type):
|
|
614
|
-
signal_type.append('FAT')
|
|
615
|
-
elif set(['IP', 'IN_PHASE']).intersection(type):
|
|
616
|
-
signal_type.append('IN-PHASE')
|
|
617
|
-
elif set(['OP', 'OUT_PHASE']).intersection(type):
|
|
618
|
-
signal_type.append('OP-PHASE')
|
|
619
|
-
else:
|
|
620
|
-
signal_type.append('UNKNOWN')
|
|
621
|
-
|
|
622
|
-
return signal_type
|
|
623
|
-
|
|
624
|
-
def get_affine_matrix(ds):
|
|
625
|
-
"""Affine transformation matrix for all images in a multiframe image"""
|
|
626
|
-
|
|
627
|
-
affineList = []
|
|
628
|
-
for frame in ds.PerFrameFunctionalGroupsSequence:
|
|
629
|
-
affine = image.affine_matrix(
|
|
630
|
-
frame.PlaneOrientationSequence[0].ImageOrientationPatient,
|
|
631
|
-
frame.PlanePositionSequence[0].ImagePositionPatient,
|
|
632
|
-
frame.PixelMeasuresSequence[0].PixelSpacing,
|
|
633
|
-
frame.PixelMeasuresSequence[0].SliceThickness)
|
|
634
|
-
affineList.append(affine)
|
|
635
|
-
return np.squeeze(np.array(affineList))
|