dbdicom 0.2.1__py3-none-any.whl → 0.2.4__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 +4 -3
- dbdicom/create.py +34 -97
- dbdicom/dro.py +174 -0
- dbdicom/ds/dataset.py +31 -4
- dbdicom/ds/types/mr_image.py +18 -7
- dbdicom/extensions/__init__.py +9 -0
- dbdicom/{wrappers → extensions}/dipy.py +191 -205
- dbdicom/extensions/elastix.py +503 -0
- dbdicom/extensions/matplotlib.py +107 -0
- dbdicom/extensions/numpy.py +271 -0
- dbdicom/{wrappers → extensions}/scipy.py +130 -31
- dbdicom/{wrappers → extensions}/skimage.py +1 -1
- dbdicom/extensions/sklearn.py +243 -0
- dbdicom/extensions/vreg.py +1390 -0
- dbdicom/external/dcm4che/bin/emf2sf +57 -57
- dbdicom/manager.py +70 -36
- dbdicom/pipelines.py +66 -0
- dbdicom/record.py +266 -43
- dbdicom/types/instance.py +54 -19
- dbdicom/types/series.py +2183 -412
- dbdicom/utils/image.py +256 -48
- dbdicom-0.2.4.dist-info/METADATA +89 -0
- {dbdicom-0.2.1.dist-info → dbdicom-0.2.4.dist-info}/RECORD +26 -41
- {dbdicom-0.2.1.dist-info → dbdicom-0.2.4.dist-info}/WHEEL +1 -1
- 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/utils/vreg.py +0 -2626
- dbdicom/wrappers/__init__.py +0 -7
- dbdicom/wrappers/elastix.py +0 -855
- dbdicom/wrappers/numpy.py +0 -119
- dbdicom/wrappers/sklearn.py +0 -151
- dbdicom/wrappers/vreg.py +0 -273
- dbdicom-0.2.1.dist-info/METADATA +0 -276
- {dbdicom-0.2.1.dist-info → dbdicom-0.2.4.dist-info}/LICENSE +0 -0
- {dbdicom-0.2.1.dist-info → dbdicom-0.2.4.dist-info}/top_level.txt +0 -0
dbdicom/__init__.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
from .create import (
|
|
3
3
|
database,
|
|
4
|
-
database_hollywood,
|
|
5
4
|
patient,
|
|
6
5
|
study,
|
|
7
6
|
series,
|
|
8
7
|
as_series,
|
|
9
8
|
zeros,
|
|
10
9
|
ones,
|
|
10
|
+
empty_series,
|
|
11
11
|
)
|
|
12
12
|
from .record import (
|
|
13
13
|
copy_to,
|
|
@@ -23,5 +23,6 @@ from .types.database import Database
|
|
|
23
23
|
from .types.patient import Patient
|
|
24
24
|
from .types.study import Study
|
|
25
25
|
from .types.series import Series
|
|
26
|
-
|
|
27
|
-
from .
|
|
26
|
+
from .utils import image
|
|
27
|
+
from . import extensions
|
|
28
|
+
from . import dro
|
dbdicom/create.py
CHANGED
|
@@ -6,7 +6,7 @@ from dbdicom.manager import Manager
|
|
|
6
6
|
from dbdicom.types.database import Database
|
|
7
7
|
from dbdicom.types.patient import Patient
|
|
8
8
|
from dbdicom.types.study import Study
|
|
9
|
-
from dbdicom.types.series import Series
|
|
9
|
+
from dbdicom.types.series import Series, _coords_size, _grid_to_coords
|
|
10
10
|
from dbdicom.types.instance import Instance
|
|
11
11
|
|
|
12
12
|
|
|
@@ -270,6 +270,7 @@ def series(dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs
|
|
|
270
270
|
else:
|
|
271
271
|
if in_database is None:
|
|
272
272
|
_database = database()
|
|
273
|
+
_database.mute()
|
|
273
274
|
else:
|
|
274
275
|
_database = in_database
|
|
275
276
|
patient = _database.new_patient()
|
|
@@ -281,73 +282,14 @@ def series(dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs
|
|
|
281
282
|
|
|
282
283
|
|
|
283
284
|
|
|
284
|
-
def database_hollywood()->Database:
|
|
285
|
-
"""Create an empty toy database for demonstration purposes.
|
|
286
285
|
|
|
287
|
-
|
|
288
|
-
Database: Database with two patients, two studies per patient and two empty series per study.
|
|
289
|
-
|
|
290
|
-
See Also:
|
|
291
|
-
:func:`~database`
|
|
292
|
-
|
|
293
|
-
Example:
|
|
294
|
-
>>> database = db.database_hollywood()
|
|
295
|
-
>>> database.print()
|
|
296
|
-
---------- DATABASE --------------
|
|
297
|
-
Location: In memory
|
|
298
|
-
Patient James Bond
|
|
299
|
-
Study MRI [19821201]
|
|
300
|
-
Series 001 [Localizer]
|
|
301
|
-
Nr of instances: 0
|
|
302
|
-
Series 002 [T2w]
|
|
303
|
-
Nr of instances: 0
|
|
304
|
-
Study Xray [19821205]
|
|
305
|
-
Series 001 [Chest]
|
|
306
|
-
Nr of instances: 0
|
|
307
|
-
Series 002 [Head]
|
|
308
|
-
Nr of instances: 0
|
|
309
|
-
Patient Scarface
|
|
310
|
-
Study MRI [19850105]
|
|
311
|
-
Series 001 [Localizer]
|
|
312
|
-
Nr of instances: 0
|
|
313
|
-
Series 002 [T2w]
|
|
314
|
-
Nr of instances: 0
|
|
315
|
-
Study Xray [19850106]
|
|
316
|
-
Series 001 [Chest]
|
|
317
|
-
Nr of instances: 0
|
|
318
|
-
Series 002 [Head]
|
|
319
|
-
Nr of instances: 0
|
|
320
|
-
---------------------------------
|
|
321
|
-
"""
|
|
322
|
-
hollywood = database()
|
|
323
|
-
|
|
324
|
-
james_bond = hollywood.new_patient(PatientName='James Bond')
|
|
325
|
-
james_bond_mri = james_bond.new_study(StudyDescription='MRI', StudyDate='19821201')
|
|
326
|
-
james_bond_mri_localizer = james_bond_mri.new_series(SeriesDescription='Localizer')
|
|
327
|
-
james_bond_mri_T2w = james_bond_mri.new_series(SeriesDescription='T2w')
|
|
328
|
-
james_bond_xray = james_bond.new_study(StudyDescription='Xray', StudyDate='19821205')
|
|
329
|
-
james_bond_xray_chest = james_bond_xray.new_series(SeriesDescription='Chest')
|
|
330
|
-
james_bond_xray_head = james_bond_xray.new_series(SeriesDescription='Head')
|
|
331
|
-
|
|
332
|
-
scarface = hollywood.new_patient(PatientName='Scarface')
|
|
333
|
-
scarface_mri = scarface.new_study(StudyDescription='MRI', StudyDate='19850105')
|
|
334
|
-
scarface_mri_localizer = scarface_mri.new_series(SeriesDescription='Localizer')
|
|
335
|
-
scarface_mri_T2w = scarface_mri.new_series(SeriesDescription='T2w')
|
|
336
|
-
scarface_xray = scarface.new_study(StudyDescription='Xray', StudyDate='19850106')
|
|
337
|
-
scarface_xray_chest = scarface_xray.new_series(SeriesDescription='Chest')
|
|
338
|
-
scarface_xray_head = scarface_xray.new_series(SeriesDescription='Head')
|
|
339
|
-
|
|
340
|
-
return hollywood
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
def as_series(array:np.ndarray, coords:dict=None, dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs)->Series:
|
|
286
|
+
def as_series(array:np.ndarray, coords:dict=None, gridcoords:dict=None, dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs)->Series:
|
|
346
287
|
"""Create a DICOM series from a numpy array.
|
|
347
288
|
|
|
348
289
|
Args:
|
|
349
290
|
array (np.ndarray): numpy.ndarray with image data
|
|
350
|
-
coords (dict, optional): Dictionary with coordinate labels and values. For 3- or 4-dimensional arrays this is optional but for arrays with more than 4 dimensions
|
|
291
|
+
coords (dict, optional): Dictionary with coordinate labels and values. For 3- or 4-dimensional arrays this is optional but for arrays with more than 4 dimensions either *coords* or *gridcoords* are required.
|
|
292
|
+
gridcoords (dict, optional): regularly gridded coordinates can also be provided as a coordinate grid.
|
|
351
293
|
dtype (str, optional): The type of the series to create. Defaults to 'mri'.
|
|
352
294
|
in_study (Study, optional): If provided, the series is created in this study. Defaults to None.
|
|
353
295
|
in_database (Database, optional): If provided, the series is created in this database. Defaults to None.
|
|
@@ -404,23 +346,37 @@ def as_series(array:np.ndarray, coords:dict=None, dtype='mri', in_study:Study=No
|
|
|
404
346
|
"""
|
|
405
347
|
shape = array.shape
|
|
406
348
|
if coords is None:
|
|
407
|
-
if
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
349
|
+
if gridcoords is None:
|
|
350
|
+
if len(shape) > 4:
|
|
351
|
+
msg = 'With more than 4 dimensions, the coords argument is required.'
|
|
352
|
+
raise ValueError(msg)
|
|
353
|
+
gridcoords = {}
|
|
354
|
+
if len(shape) == 2:
|
|
355
|
+
gridcoords['InstanceNumber'] = np.array([1])
|
|
412
356
|
if len(shape) > 2:
|
|
413
|
-
|
|
357
|
+
gridcoords['SliceLocation'] = np.arange(shape[2])
|
|
414
358
|
if len(shape) > 3:
|
|
415
|
-
|
|
359
|
+
gridcoords['AcquisitionTime'] = np.arange(shape[3])
|
|
360
|
+
if gridcoords is not None:
|
|
361
|
+
coords = _grid_to_coords(gridcoords)
|
|
362
|
+
sery = series(dtype=dtype, in_study=in_study, in_database=in_database, **kwargs)
|
|
363
|
+
sery.expand(coords)
|
|
364
|
+
sery.set_pixel_values(array, dims=tuple(coords))
|
|
365
|
+
return sery
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def empty_series(coords:dict=None, gridcoords:dict=None, dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs)->Series:
|
|
369
|
+
|
|
370
|
+
if gridcoords is not None:
|
|
371
|
+
coords = _grid_to_coords(gridcoords)
|
|
416
372
|
sery = series(dtype=dtype, in_study=in_study, in_database=in_database, **kwargs)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
sery.
|
|
373
|
+
if coords is None:
|
|
374
|
+
return sery
|
|
375
|
+
sery.expand(coords)
|
|
420
376
|
return sery
|
|
421
377
|
|
|
422
378
|
|
|
423
|
-
def zeros(shape:tuple, coords:dict=None, **kwargs) -> Series:
|
|
379
|
+
def zeros(shape:tuple, coords:dict=None, gridcoords:dict=None, **kwargs) -> Series:
|
|
424
380
|
"""Create a DICOM series populated with zeros.
|
|
425
381
|
|
|
426
382
|
This is a convenience wrapper providing a numpy-like interface for :func:`~as_series`.
|
|
@@ -456,21 +412,12 @@ def zeros(shape:tuple, coords:dict=None, **kwargs) -> Series:
|
|
|
456
412
|
>>> array = np.zeros((128, 128, 2, 3))
|
|
457
413
|
>>> zeros = db.as_series(array)
|
|
458
414
|
"""
|
|
459
|
-
|
|
460
|
-
if len(shape) > 4:
|
|
461
|
-
msg = 'With more than 4 dimensions, the coordinates argument is required'
|
|
462
|
-
raise ValueError(msg)
|
|
463
|
-
else:
|
|
464
|
-
coords = {}
|
|
465
|
-
if len(shape) > 2:
|
|
466
|
-
coords['SliceLocation'] = np.arange(shape[2])
|
|
467
|
-
if len(shape) > 3:
|
|
468
|
-
coords['AcquisitionTime'] = np.arange(shape[3])
|
|
415
|
+
|
|
469
416
|
array = np.zeros(shape, dtype=np.float32)
|
|
470
|
-
return as_series(array, coords=coords, **kwargs)
|
|
417
|
+
return as_series(array, coords=coords, gridcoords=gridcoords, **kwargs)
|
|
471
418
|
|
|
472
419
|
|
|
473
|
-
def ones(shape:tuple, coords:dict=None, **kwargs) -> Series:
|
|
420
|
+
def ones(shape:tuple, coords:dict=None, gridcoords:dict=None, **kwargs) -> Series:
|
|
474
421
|
"""Create a DICOM series populated with ones.
|
|
475
422
|
|
|
476
423
|
This is a convenience wrapper providing a numpy-like interface for :func:`~as_series`.
|
|
@@ -506,15 +453,5 @@ def ones(shape:tuple, coords:dict=None, **kwargs) -> Series:
|
|
|
506
453
|
>>> array = np.ones((128, 128, 2, 3))
|
|
507
454
|
>>> zeros = db.as_series(array)
|
|
508
455
|
"""
|
|
509
|
-
if coords is None:
|
|
510
|
-
if len(shape) > 4:
|
|
511
|
-
msg = 'With more than 4 dimensions, the coordinates argument is required'
|
|
512
|
-
raise ValueError(msg)
|
|
513
|
-
else:
|
|
514
|
-
coords = {}
|
|
515
|
-
if len(shape) > 2:
|
|
516
|
-
coords['SliceLocation'] = np.arange(shape[2])
|
|
517
|
-
if len(shape) > 3:
|
|
518
|
-
coords['AcquisitionTime'] = np.arange(shape[3])
|
|
519
456
|
array = np.ones(shape, dtype=np.float32)
|
|
520
|
-
return as_series(array, coords=coords, **kwargs)
|
|
457
|
+
return as_series(array, coords=coords, gridcoords=gridcoords, **kwargs)
|
dbdicom/dro.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Importing annotations to handle or sign in import type hints
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import dbdicom as db
|
|
6
|
+
from dbdicom.types.database import Database
|
|
7
|
+
from dbdicom.types.series import Series
|
|
8
|
+
from dbdicom.utils import image
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def T1_mapping_vFATR(spacing = (15, 15, 20), fov = (300, 250, 120), T1min = 600, S0min = 100, vFA = [2.0, 20.0], vTR = [5.0,15.0])->Series:
|
|
12
|
+
"""Synthetic T1-mapping data with variable TR and FA
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
spacing (tuple, optional): x, y, z pixel spacing in mm. Defaults to (1.5, 1.5, 2.0).
|
|
16
|
+
fov (tuple, optional): x, y, z field of view in mm. Defaults to (300, 250, 120).
|
|
17
|
+
T1min (int, optional): smallest T1 in msec. Defaults to 600.
|
|
18
|
+
S0min (int, optional): smallest S0 in a.u. Defaults to 100.
|
|
19
|
+
vFA (list, optional): variable flip angle values in degrees. Defaults to [2.0, 5.0, 10.0, 15.0, 20.0].
|
|
20
|
+
vTR (list, optional): variable repetition time values in msec. Defaults to [2.0, 3.0, 4.0, 5.0, 10.0, 15.0].
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
dbdicom.Series: A series with appropriate array and header data.
|
|
24
|
+
"""
|
|
25
|
+
ellipsoid = image.ellipsoid(fov[0]/2, fov[1]/2, fov[2]/2, spacing=spacing, levelset=True)
|
|
26
|
+
ellipsoid = 1 + ellipsoid - np.amin(ellipsoid)
|
|
27
|
+
T1 = T1min*ellipsoid
|
|
28
|
+
S0 = S0min*ellipsoid
|
|
29
|
+
array = np.empty((T1.shape[0], T1.shape[1], T1.shape[2], len(vFA), len(vTR)))
|
|
30
|
+
for j, TR in enumerate(vTR):
|
|
31
|
+
Ej = np.exp(-TR/T1)
|
|
32
|
+
for i, FA in enumerate(vFA):
|
|
33
|
+
ci = np.cos(FA*np.pi/180)
|
|
34
|
+
array[:,:,:,i,j] = S0 * (1-Ej) / (1-ci*Ej)
|
|
35
|
+
|
|
36
|
+
coords = {
|
|
37
|
+
'SliceLocation': spacing[2]*np.arange(array.shape[2]),
|
|
38
|
+
'FlipAngle': np.array(vFA),
|
|
39
|
+
'RepetitionTime': np.array(vTR),
|
|
40
|
+
}
|
|
41
|
+
v0, v1 = np.amin(array), np.amax(array)
|
|
42
|
+
series = db.as_series(array, gridcoords=coords, PixelSpacing=[spacing[1],spacing[0]], WindowWidth=v1-v0, WindowCenter=(v0+v1)/2)
|
|
43
|
+
series.patient().PatientName = 'Ellipsoid'
|
|
44
|
+
series.study().StudyDescription = 'Synthetic'
|
|
45
|
+
series.SeriesDescription = 'T1 mapping variable TR and FA'
|
|
46
|
+
|
|
47
|
+
return series
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def ellipsoid(a, b, c, spacing=(1., 1., 1.), levelset=False)->Series:
|
|
51
|
+
"""
|
|
52
|
+
Generates ellipsoid with semimajor axes aligned with grid dimensions
|
|
53
|
+
on grid with specified `spacing`.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
a (float): Length of semimajor axis aligned with x-axis.
|
|
57
|
+
b (float): Length of semimajor axis aligned with y-axis.
|
|
58
|
+
c (float): Length of semimajor axis aligned with z-axis.
|
|
59
|
+
spacing (tuple of floats, length 3): Spacing in (x, y, z) spatial dimensions. Defaults to (1,1,1)
|
|
60
|
+
levelset (bool): If True, returns the level set for this ellipsoid (signed level set about zero, with positive denoting interior) as np.float64. False returns a binarized version of said level set. Defaults to False.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
dbdicom.Series: A series with appropriate array and header data.
|
|
64
|
+
|
|
65
|
+
Note:
|
|
66
|
+
The interface and the array generation is taken directly from skimage but the core function is copied into dbdicom utilities to avoid bringing in skimage as an essential dependency.
|
|
67
|
+
"""
|
|
68
|
+
arr = image.ellipsoid(a, b, c, spacing=spacing, levelset=levelset)
|
|
69
|
+
coords = {'SliceLocation': spacing[2]*np.arange(arr.shape[2])}
|
|
70
|
+
v0, v1 = np.amin(arr), np.amax(arr)
|
|
71
|
+
series = db.as_series(arr, gridcoords=coords, PixelSpacing=[spacing[1],spacing[0]], WindowWidth=v1-v0, WindowCenter=(v0+v1)/2)
|
|
72
|
+
affine = np.array(
|
|
73
|
+
[[spacing[1], 0., 0., 0.],
|
|
74
|
+
[0., spacing[0], 0., 0.],
|
|
75
|
+
[0., 0., spacing[2], 0.],
|
|
76
|
+
[0., 0., 0., 1.]]
|
|
77
|
+
)
|
|
78
|
+
series.set_affine(affine)
|
|
79
|
+
series.patient().PatientName = 'Ellipsoid'
|
|
80
|
+
series.study().StudyDescription = 'Synthetic'
|
|
81
|
+
series.SeriesDescription = 'Levelset ellipsoid'
|
|
82
|
+
return series
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def double_ellipsoid(a, b, c, spacing=(1., 1., 1.), levelset=False)->Series:
|
|
86
|
+
"""
|
|
87
|
+
Generates a double ellipsoid with semimajor axes aligned with grid dimensions
|
|
88
|
+
on grid with specified `spacing`.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
a (float): Length of semimajor axis aligned with x-axis.
|
|
92
|
+
b (float): Length of semimajor axis aligned with y-axis.
|
|
93
|
+
c (float): Length of semimajor axis aligned with z-axis.
|
|
94
|
+
spacing (tuple of floats, length 3): Spacing in (x, y, z) spatial dimensions. Defaults to (1,1,1)
|
|
95
|
+
levelset (bool): If True, returns the level set for this ellipsoid (signed level set about zero, with positive denoting interior) as np.float64. False returns a binarized version of said level set. Defaults to False.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
dbdicom.Series: A series with appropriate array and header data.
|
|
99
|
+
|
|
100
|
+
Note:
|
|
101
|
+
The interface and the array generation is taken directly from skimage, but the core function is copied into dbdicom utilities to avoid bringing in skimage as an essential dependency.
|
|
102
|
+
"""
|
|
103
|
+
arr = image.ellipsoid(a, b, c, spacing=spacing, levelset=levelset)
|
|
104
|
+
coords = {'SliceLocation': spacing[2]*np.arange(arr.shape[2])}
|
|
105
|
+
arr = np.concatenate((arr[:-1, ...], arr[2:, ...]), axis=0)
|
|
106
|
+
v0, v1 = np.amin(arr), np.amax(arr)
|
|
107
|
+
series = db.as_series(arr, gridcoords=coords, PixelSpacing=[spacing[1],spacing[0]], WindowWidth=v1-v0, WindowCenter=(v0+v1)/2)
|
|
108
|
+
series.patient().PatientName = 'Ellipsoid'
|
|
109
|
+
series.study().StudyDescription = 'Synthetic'
|
|
110
|
+
series.SeriesDescription = 'Levelset ellipsoid'
|
|
111
|
+
return series
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def database_hollywood()->Database:
|
|
115
|
+
"""Create an empty toy database for demonstration purposes.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Database: Database with two patients, two studies per patient and two empty series per study.
|
|
119
|
+
|
|
120
|
+
See Also:
|
|
121
|
+
:func:`~database`
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
>>> database = db.dro.database_hollywood()
|
|
125
|
+
>>> database.print()
|
|
126
|
+
---------- DATABASE --------------
|
|
127
|
+
Location: In memory
|
|
128
|
+
Patient James Bond
|
|
129
|
+
Study MRI [19821201]
|
|
130
|
+
Series 001 [Localizer]
|
|
131
|
+
Nr of instances: 0
|
|
132
|
+
Series 002 [T2w]
|
|
133
|
+
Nr of instances: 0
|
|
134
|
+
Study Xray [19821205]
|
|
135
|
+
Series 001 [Chest]
|
|
136
|
+
Nr of instances: 0
|
|
137
|
+
Series 002 [Head]
|
|
138
|
+
Nr of instances: 0
|
|
139
|
+
Patient Scarface
|
|
140
|
+
Study MRI [19850105]
|
|
141
|
+
Series 001 [Localizer]
|
|
142
|
+
Nr of instances: 0
|
|
143
|
+
Series 002 [T2w]
|
|
144
|
+
Nr of instances: 0
|
|
145
|
+
Study Xray [19850106]
|
|
146
|
+
Series 001 [Chest]
|
|
147
|
+
Nr of instances: 0
|
|
148
|
+
Series 002 [Head]
|
|
149
|
+
Nr of instances: 0
|
|
150
|
+
---------------------------------
|
|
151
|
+
"""
|
|
152
|
+
hollywood = db.database()
|
|
153
|
+
hollywood.mute()
|
|
154
|
+
|
|
155
|
+
james_bond = hollywood.new_patient(PatientName='James Bond')
|
|
156
|
+
james_bond_mri = james_bond.new_study(StudyDescription='MRI', StudyDate='19821201')
|
|
157
|
+
james_bond_mri_localizer = james_bond_mri.new_series(SeriesDescription='Localizer')
|
|
158
|
+
james_bond_mri_T2w = james_bond_mri.new_series(SeriesDescription='T2w')
|
|
159
|
+
james_bond_xray = james_bond.new_study(StudyDescription='Xray', StudyDate='19821205')
|
|
160
|
+
james_bond_xray_chest = james_bond_xray.new_series(SeriesDescription='Chest')
|
|
161
|
+
james_bond_xray_head = james_bond_xray.new_series(SeriesDescription='Head')
|
|
162
|
+
|
|
163
|
+
scarface = hollywood.new_patient(PatientName='Scarface')
|
|
164
|
+
scarface_mri = scarface.new_study(StudyDescription='MRI', StudyDate='19850105')
|
|
165
|
+
scarface_mri_localizer = scarface_mri.new_series(SeriesDescription='Localizer')
|
|
166
|
+
scarface_mri_T2w = scarface_mri.new_series(SeriesDescription='T2w')
|
|
167
|
+
scarface_xray = scarface.new_study(StudyDescription='Xray', StudyDate='19850106')
|
|
168
|
+
scarface_xray_chest = scarface_xray.new_series(SeriesDescription='Chest')
|
|
169
|
+
scarface_xray_head = scarface_xray.new_series(SeriesDescription='Head')
|
|
170
|
+
|
|
171
|
+
return hollywood
|
|
172
|
+
|
|
173
|
+
if __name__ == '__main__':
|
|
174
|
+
T1_mapping_vFATR()
|
dbdicom/ds/dataset.py
CHANGED
|
@@ -306,9 +306,21 @@ def set_values(ds, tags, values, VR=None):
|
|
|
306
306
|
ds[tag].value = format_value(values[i], tag=tag)
|
|
307
307
|
else:
|
|
308
308
|
_add_new(ds, tag, values[i], VR=VR[i])
|
|
309
|
+
|
|
310
|
+
#_set_derived_data_element(ds, tag, values[i])
|
|
311
|
+
|
|
309
312
|
return ds
|
|
310
313
|
|
|
311
314
|
|
|
315
|
+
# def _set_derived_data_element(ds, tag, value):
|
|
316
|
+
# """Set any tags that are need to change as well"""
|
|
317
|
+
|
|
318
|
+
# if tag == 'SliceLocation' or tag == (0x0020, 0x1041):
|
|
319
|
+
# if value is not None:
|
|
320
|
+
# loc = ds['ImageOrientationPatient'].value
|
|
321
|
+
# ds['ImagePositionPatient'].value = image.image_position_from_slice_location(value, loc)
|
|
322
|
+
|
|
323
|
+
|
|
312
324
|
def _add_new(ds, tag, value, VR='OW'):
|
|
313
325
|
if not isinstance(tag, pydicom.tag.BaseTag):
|
|
314
326
|
tag = pydicom.tag.Tag(tag)
|
|
@@ -324,10 +336,15 @@ def _add_new(ds, tag, value, VR='OW'):
|
|
|
324
336
|
ds.add_new(tag, value_repr, format_value(value, value_repr))
|
|
325
337
|
else:
|
|
326
338
|
if (tag.group, 0x0010) not in ds:
|
|
327
|
-
ds.private_block(tag.group, '
|
|
339
|
+
ds.private_block(tag.group, 'dbdicom ' + str(tag.group), create=True)
|
|
328
340
|
ds.add_new(tag, VR, format_value(value, VR))
|
|
329
341
|
|
|
330
342
|
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
331
348
|
def get_values(ds, tags):
|
|
332
349
|
"""Return a list of values for a dataset"""
|
|
333
350
|
|
|
@@ -347,12 +364,20 @@ def get_values(ds, tags):
|
|
|
347
364
|
value = getattr(ds, 'get_attribute_' + tag)()
|
|
348
365
|
else:
|
|
349
366
|
pydcm_value = ds[tag].value
|
|
350
|
-
|
|
367
|
+
try:
|
|
368
|
+
VR = pydicom.datadict.dictionary_VR(tag)
|
|
369
|
+
except:
|
|
370
|
+
VR = None
|
|
371
|
+
value = to_set_type(pydcm_value, VR) # ELIMINATE THIS STEP - return pydicom datatypes
|
|
351
372
|
|
|
352
373
|
# If the tag is a tuple of hexadecimal values
|
|
353
374
|
else:
|
|
354
375
|
if tag in ds:
|
|
355
|
-
|
|
376
|
+
try:
|
|
377
|
+
VR = pydicom.datadict.dictionary_VR(tag)
|
|
378
|
+
except:
|
|
379
|
+
VR = None
|
|
380
|
+
value = to_set_type(ds[tag].value, VR)
|
|
356
381
|
|
|
357
382
|
# If a tag is not present in the dataset, check if it can be derived
|
|
358
383
|
if value is None:
|
|
@@ -374,6 +399,7 @@ def derive_data_element(ds, tag):
|
|
|
374
399
|
# To be extended ad hoc with other tags that can be derived
|
|
375
400
|
|
|
376
401
|
|
|
402
|
+
|
|
377
403
|
def format_value(value, VR=None, tag=None):
|
|
378
404
|
|
|
379
405
|
# If the change below is made (TM, DA, DT) then this needs to
|
|
@@ -437,6 +463,7 @@ def new_uid(n=None):
|
|
|
437
463
|
return [pydicom.uid.generate_uid() for _ in range(n)]
|
|
438
464
|
|
|
439
465
|
|
|
466
|
+
# Obsolete - replaced by instance.affine()
|
|
440
467
|
def get_affine_matrix(ds):
|
|
441
468
|
"""Affine transformation matrix for a DICOM image"""
|
|
442
469
|
|
|
@@ -444,7 +471,6 @@ def get_affine_matrix(ds):
|
|
|
444
471
|
# if slice_spacing is None:
|
|
445
472
|
# slice_spacing = get_values(ds, 'SliceThickness')
|
|
446
473
|
slice_spacing = get_values(ds, 'SliceThickness')
|
|
447
|
-
|
|
448
474
|
return image.affine_matrix(
|
|
449
475
|
get_values(ds, 'ImageOrientationPatient'),
|
|
450
476
|
get_values(ds, 'ImagePositionPatient'),
|
|
@@ -452,6 +478,7 @@ def get_affine_matrix(ds):
|
|
|
452
478
|
slice_spacing)
|
|
453
479
|
|
|
454
480
|
|
|
481
|
+
# Obsolete - replaced by instance.set_affine()
|
|
455
482
|
def set_affine_matrix(ds, affine):
|
|
456
483
|
v = image.dismantle_affine_matrix(affine)
|
|
457
484
|
set_values(ds, 'PixelSpacing', v['PixelSpacing'])
|
dbdicom/ds/types/mr_image.py
CHANGED
|
@@ -126,11 +126,11 @@ def rider(ds): # required only - check
|
|
|
126
126
|
ds.SeriesNumber = '14'
|
|
127
127
|
ds.AcquisitionNumber = '1'
|
|
128
128
|
ds.InstanceNumber = '1'
|
|
129
|
-
ds.ImagePositionPatient = [
|
|
130
|
-
ds.ImageOrientationPatient = [
|
|
129
|
+
ds.ImagePositionPatient = [0, 0, 0]
|
|
130
|
+
ds.ImageOrientationPatient = [1, 0, 0, 0, 1, 0]
|
|
131
131
|
ds.FrameOfReferenceUID = '1.3.6.1.4.1.9328.50.16.22344679587635360510174487884943834158'
|
|
132
132
|
ds.PositionReferenceIndicator = ''
|
|
133
|
-
ds.SliceLocation = '
|
|
133
|
+
ds.SliceLocation = '0.0'
|
|
134
134
|
ds.SamplesPerPixel = 1
|
|
135
135
|
ds.PhotometricInterpretation = 'MONOCHROME2'
|
|
136
136
|
ds.Rows = 64
|
|
@@ -156,7 +156,8 @@ def rider(ds): # required only - check
|
|
|
156
156
|
ds.RequestAttributesSequence = Sequence()
|
|
157
157
|
ds.RequestedProcedureID = '5133240'
|
|
158
158
|
ds.StorageMediaFileSetUID = '1.3.6.1.4.1.9328.50.16.162890465625511526068665093825399871205'
|
|
159
|
-
|
|
159
|
+
pixel_values = np.arange(ds.Rows*ds.Columns)*ds.LargestImagePixelValue/(ds.Rows*ds.Columns)
|
|
160
|
+
ds.PixelData = pixel_values.astype(np.uint16).tobytes()
|
|
160
161
|
|
|
161
162
|
return ds
|
|
162
163
|
|
|
@@ -190,15 +191,25 @@ def set_pixel_array(ds, array):
|
|
|
190
191
|
del ds[0x2005, 0x100E] # Delete 'Philips Rescale Slope'
|
|
191
192
|
if (0x2005, 0x100D) in ds:
|
|
192
193
|
del ds[0x2005, 0x100D]
|
|
193
|
-
|
|
194
|
+
|
|
194
195
|
# clipping may slow down a lot
|
|
195
196
|
array = image.clip(array.astype(np.float32))
|
|
196
197
|
array, slope, intercept = image.scale_to_range(array, ds.BitsAllocated)
|
|
197
198
|
array = np.transpose(array)
|
|
198
199
|
|
|
199
200
|
ds.PixelRepresentation = 0
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
|
|
202
|
+
# Does this need setting? Optional and should not be used like this anyway.
|
|
203
|
+
# Prob
|
|
204
|
+
# 11 june 2016: commented this out it produced busg in some cases due to US vs SS confusion
|
|
205
|
+
# vr = ds.data_element('SmallestImagePixelValue').VR
|
|
206
|
+
# if vr =='US':
|
|
207
|
+
# ds.set_values('SmallestImagePixelValue', int(0))
|
|
208
|
+
# ds.set_values('LargestImagePixelValue', int(2**ds.BitsAllocated - 1))
|
|
209
|
+
# else:
|
|
210
|
+
# ds.set_values('SmallestImagePixelValue', int(-2**(ds.BitsAllocated - 1)))
|
|
211
|
+
# ds.set_values('LargestImagePixelValue', int(2**(ds.BitsAllocated - 1)-1))
|
|
212
|
+
|
|
202
213
|
ds.RescaleSlope = 1 / slope
|
|
203
214
|
ds.RescaleIntercept = - intercept / slope
|
|
204
215
|
# ds.WindowCenter = (maximum + minimum) / 2
|