dbdicom 0.2.0__py3-none-any.whl → 0.2.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.

Files changed (52) hide show
  1. dbdicom/__init__.py +5 -3
  2. dbdicom/create.py +77 -70
  3. dbdicom/dro.py +174 -0
  4. dbdicom/ds/dataset.py +30 -3
  5. dbdicom/ds/types/mr_image.py +18 -7
  6. dbdicom/extensions/__init__.py +10 -0
  7. dbdicom/{wrappers → extensions}/dipy.py +191 -205
  8. dbdicom/extensions/elastix.py +503 -0
  9. dbdicom/extensions/matplotlib.py +107 -0
  10. dbdicom/extensions/numpy.py +271 -0
  11. dbdicom/{wrappers → extensions}/scipy.py +131 -32
  12. dbdicom/{wrappers → extensions}/skimage.py +1 -1
  13. dbdicom/extensions/sklearn.py +243 -0
  14. dbdicom/extensions/vreg.py +1390 -0
  15. dbdicom/external/dcm4che/bin/emf2sf +57 -57
  16. dbdicom/manager.py +91 -36
  17. dbdicom/pipelines.py +66 -0
  18. dbdicom/record.py +447 -80
  19. dbdicom/types/instance.py +46 -20
  20. dbdicom/types/series.py +2182 -399
  21. dbdicom/utils/image.py +152 -21
  22. dbdicom/utils/variables.py +8 -2
  23. dbdicom/utils/vreg.py +327 -135
  24. dbdicom-0.2.3.dist-info/METADATA +88 -0
  25. dbdicom-0.2.3.dist-info/RECORD +67 -0
  26. {dbdicom-0.2.0.dist-info → dbdicom-0.2.3.dist-info}/WHEEL +1 -1
  27. dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  28. dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  29. dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  30. dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  31. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  32. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  33. dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  34. dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  35. dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  36. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  37. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  38. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  39. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  40. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  41. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  42. dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  43. dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  44. dbdicom/wrappers/__init__.py +0 -7
  45. dbdicom/wrappers/elastix.py +0 -855
  46. dbdicom/wrappers/numpy.py +0 -119
  47. dbdicom/wrappers/sklearn.py +0 -151
  48. dbdicom/wrappers/vreg.py +0 -273
  49. dbdicom-0.2.0.dist-info/METADATA +0 -276
  50. dbdicom-0.2.0.dist-info/RECORD +0 -81
  51. {dbdicom-0.2.0.dist-info → dbdicom-0.2.3.dist-info}/LICENSE +0 -0
  52. {dbdicom-0.2.0.dist-info → dbdicom-0.2.3.dist-info}/top_level.txt +0 -0
dbdicom/__init__.py CHANGED
@@ -1,12 +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,
9
+ ones,
10
+ empty_series,
10
11
  )
11
12
  from .record import (
12
13
  copy_to,
@@ -22,5 +23,6 @@ from .types.database import Database
22
23
  from .types.patient import Patient
23
24
  from .types.study import Study
24
25
  from .types.series import Series
25
-
26
- from .utils import image
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
- Returns:
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 this is required. The coordinate values can be one-dimensions for regularly gridded data, or n-dimensional for irregularly gridded data.
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.
@@ -402,14 +344,39 @@ def as_series(array:np.ndarray, coords:dict=None, dtype='mri', in_study:Study=No
402
344
  >>> print(zeros.RepetitionTime)
403
345
  [2.5, 5.0]
404
346
  """
347
+ shape = array.shape
348
+ if coords is None:
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])
356
+ if len(shape) > 2:
357
+ gridcoords['SliceLocation'] = np.arange(shape[2])
358
+ if len(shape) > 3:
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)
405
372
  sery = series(dtype=dtype, in_study=in_study, in_database=in_database, **kwargs)
406
- sery.mute()
407
- sery.set_array(array, coords=coords, pixels_first=True)
408
- sery.unmute()
373
+ if coords is None:
374
+ return sery
375
+ sery.expand(coords)
409
376
  return sery
410
377
 
411
378
 
412
- def zeros(shape:tuple, coords:dict=None, **kwargs) -> Series:
379
+ def zeros(shape:tuple, coords:dict=None, gridcoords:dict=None, **kwargs) -> Series:
413
380
  """Create a DICOM series populated with zeros.
414
381
 
415
382
  This is a convenience wrapper providing a numpy-like interface for :func:`~as_series`.
@@ -422,8 +389,7 @@ def zeros(shape:tuple, coords:dict=None, **kwargs) -> Series:
422
389
  Series: DICOM series with zero values
423
390
 
424
391
  See Also:
425
- :func:`~series`
426
- :func:`~as_series`
392
+ :func:`~ones`
427
393
 
428
394
  Example:
429
395
  Create a series containing a 4-dimensional array of zeros:
@@ -446,5 +412,46 @@ def zeros(shape:tuple, coords:dict=None, **kwargs) -> Series:
446
412
  >>> array = np.zeros((128, 128, 2, 3))
447
413
  >>> zeros = db.as_series(array)
448
414
  """
415
+
449
416
  array = np.zeros(shape, dtype=np.float32)
450
- return as_series(array, coords=coords, **kwargs)
417
+ return as_series(array, coords=coords, gridcoords=gridcoords, **kwargs)
418
+
419
+
420
+ def ones(shape:tuple, coords:dict=None, gridcoords:dict=None, **kwargs) -> Series:
421
+ """Create a DICOM series populated with ones.
422
+
423
+ This is a convenience wrapper providing a numpy-like interface for :func:`~as_series`.
424
+
425
+ Args:
426
+ shape (tuple): shape of the array
427
+ kwargs: see :func:`~series`
428
+
429
+ Returns:
430
+ Series: DICOM series with values of one.
431
+
432
+ See Also:
433
+ :func:`~zeros`
434
+
435
+ Example:
436
+ Create a series containing a 4-dimensional array of ones:
437
+
438
+ >>> zeros = db.ones((128, 128, 2, 3))
439
+ >>> zeros.print()
440
+ ---------- SERIES --------------
441
+ Series 001 [New Series]
442
+ Nr of instances: 6
443
+ MRImage 000001
444
+ MRImage 000002
445
+ MRImage 000003
446
+ MRImage 000004
447
+ MRImage 000005
448
+ MRImage 000006
449
+ --------------------------------
450
+
451
+ This is effectively shorthand for:
452
+
453
+ >>> array = np.ones((128, 128, 2, 3))
454
+ >>> zeros = db.as_series(array)
455
+ """
456
+ array = np.ones(shape, dtype=np.float32)
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, 'Wezel ' + str(tag.group), create=True)
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
- value = to_set_type(pydcm_value, pydicom.datadict.dictionary_VR(tag)) # ELIMINATE THIS STEP - return pydicom datatypes
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
- value = to_set_type(ds[tag].value, pydicom.datadict.dictionary_VR(tag))
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
@@ -459,6 +485,7 @@ def set_affine_matrix(ds, affine):
459
485
  set_values(ds, 'SliceThickness', v['SpacingBetweenSlices'])
460
486
  set_values(ds, 'ImageOrientationPatient', v['ImageOrientationPatient'])
461
487
  set_values(ds, 'ImagePositionPatient', v['ImagePositionPatient'])
488
+ set_values(ds, 'SliceLocation', np.dot(v['ImagePositionPatient'], v['slice_cosine']))
462
489
 
463
490
 
464
491
  def map_mask_to(ds_source, ds_target):
@@ -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 = [75.561665058136, -163.6216506958, 118.50172901154]
130
- ds.ImageOrientationPatient = [0, 1, 0, 0, 0, -1]
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 = '75.561665058136'
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
- ds.PixelData = np.arange(ds.Rows*ds.Columns, dtype=np.uint16)*ds.LargestImagePixelValue/(ds.Rows*ds.Columns)
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
- ds.set_values('SmallestImagePixelValue', int(0))
201
- ds.set_values('LargestImagePixelValue', int(2**ds.BitsAllocated - 1))
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
@@ -0,0 +1,10 @@
1
+ from . import (
2
+ dipy,
3
+ elastix,
4
+ numpy,
5
+ scipy,
6
+ skimage,
7
+ sklearn,
8
+ vreg,
9
+ matplotlib,
10
+ )