dbdicom 0.2.1__tar.gz → 0.2.3__tar.gz

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 (108) hide show
  1. dbdicom-0.2.3/PKG-INFO +88 -0
  2. dbdicom-0.2.3/README.md +35 -0
  3. {dbdicom-0.2.1 → dbdicom-0.2.3}/pyproject.toml +12 -4
  4. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/__init__.py +4 -3
  5. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/create.py +34 -97
  6. dbdicom-0.2.3/src/dbdicom/dro.py +174 -0
  7. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/dataset.py +29 -3
  8. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/mr_image.py +18 -7
  9. dbdicom-0.2.3/src/dbdicom/extensions/__init__.py +10 -0
  10. {dbdicom-0.2.1/src/dbdicom/wrappers → dbdicom-0.2.3/src/dbdicom/extensions}/dipy.py +191 -205
  11. dbdicom-0.2.3/src/dbdicom/extensions/elastix.py +503 -0
  12. dbdicom-0.2.3/src/dbdicom/extensions/matplotlib.py +107 -0
  13. dbdicom-0.2.3/src/dbdicom/extensions/numpy.py +271 -0
  14. {dbdicom-0.2.1/src/dbdicom/wrappers → dbdicom-0.2.3/src/dbdicom/extensions}/scipy.py +130 -31
  15. {dbdicom-0.2.1/src/dbdicom/wrappers → dbdicom-0.2.3/src/dbdicom/extensions}/skimage.py +1 -1
  16. dbdicom-0.2.3/src/dbdicom/extensions/sklearn.py +243 -0
  17. dbdicom-0.2.3/src/dbdicom/extensions/vreg.py +1390 -0
  18. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/bin/emf2sf +57 -57
  19. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/manager.py +70 -36
  20. dbdicom-0.2.3/src/dbdicom/pipelines.py +66 -0
  21. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/record.py +266 -43
  22. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/types/instance.py +17 -3
  23. dbdicom-0.2.3/src/dbdicom/types/series.py +2599 -0
  24. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/utils/image.py +152 -21
  25. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/utils/vreg.py +327 -135
  26. dbdicom-0.2.3/src/dbdicom.egg-info/PKG-INFO +88 -0
  27. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom.egg-info/SOURCES.txt +13 -26
  28. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom.egg-info/requires.txt +6 -2
  29. dbdicom-0.2.3/tests/test_dro.py +60 -0
  30. dbdicom-0.2.3/tests/test_extensions.py +165 -0
  31. {dbdicom-0.2.1 → dbdicom-0.2.3}/tests/test_record.py +62 -7
  32. dbdicom-0.2.3/tests/test_series.py +1295 -0
  33. dbdicom-0.2.1/PKG-INFO +0 -249
  34. dbdicom-0.2.1/README.md +0 -25
  35. dbdicom-0.2.1/setup.py +0 -8
  36. dbdicom-0.2.1/src/dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  37. dbdicom-0.2.1/src/dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  38. dbdicom-0.2.1/src/dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  39. dbdicom-0.2.1/src/dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  40. dbdicom-0.2.1/src/dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  41. dbdicom-0.2.1/src/dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  42. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  43. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  44. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  45. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  46. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  47. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  48. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  49. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  50. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  51. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  52. dbdicom-0.2.1/src/dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  53. dbdicom-0.2.1/src/dbdicom/types/series.py +0 -1103
  54. dbdicom-0.2.1/src/dbdicom/wrappers/__init__.py +0 -7
  55. dbdicom-0.2.1/src/dbdicom/wrappers/elastix.py +0 -855
  56. dbdicom-0.2.1/src/dbdicom/wrappers/numpy.py +0 -119
  57. dbdicom-0.2.1/src/dbdicom/wrappers/sklearn.py +0 -151
  58. dbdicom-0.2.1/src/dbdicom/wrappers/vreg.py +0 -273
  59. dbdicom-0.2.1/src/dbdicom.egg-info/PKG-INFO +0 -249
  60. dbdicom-0.2.1/tests/test_series.py +0 -228
  61. {dbdicom-0.2.1 → dbdicom-0.2.3}/LICENSE +0 -0
  62. {dbdicom-0.2.1 → dbdicom-0.2.3}/MANIFEST.in +0 -0
  63. {dbdicom-0.2.1 → dbdicom-0.2.3}/setup.cfg +0 -0
  64. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/__init__.py +0 -0
  65. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/create.py +0 -0
  66. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/dictionaries.py +0 -0
  67. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/ct_image.py +0 -0
  68. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/enhanced_mr_image.py +0 -0
  69. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/parametric_map.py +0 -0
  70. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/ultrasound_multiframe_image.py +0 -0
  71. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/ds/types/xray_angiographic_image.py +0 -0
  72. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/__init__.py +0 -0
  73. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/README.md +0 -0
  74. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/__init__.py +0 -0
  75. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/bin/__init__.py +0 -0
  76. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/bin/deidentify +0 -0
  77. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/bin/deidentify.bat +0 -0
  78. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/bin/emf2sf.bat +0 -0
  79. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/etc/__init__.py +0 -0
  80. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/etc/emf2sf/__init__.py +0 -0
  81. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/etc/emf2sf/log4j.properties +0 -0
  82. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/__init__.py +0 -0
  83. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/commons-cli-1.4.jar +0 -0
  84. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/dcm4che-core-5.23.1.jar +0 -0
  85. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/dcm4che-emf-5.23.1.jar +0 -0
  86. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/dcm4che-tool-common-5.23.1.jar +0 -0
  87. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/dcm4che-tool-emf2sf-5.23.1.jar +0 -0
  88. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/log4j-1.2.17.jar +0 -0
  89. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/macosx-x86-64/libopencv_java.jnilib +0 -0
  90. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/slf4j-api-1.7.30.jar +0 -0
  91. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/slf4j-log4j12-1.7.30.jar +0 -0
  92. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/windows-x86/clib_jiio.dll +0 -0
  93. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/windows-x86/clib_jiio_sse2.dll +0 -0
  94. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/windows-x86/clib_jiio_util.dll +0 -0
  95. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/windows-x86/opencv_java.dll +0 -0
  96. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/external/dcm4che/lib/windows-x86-64/opencv_java.dll +0 -0
  97. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/message.py +0 -0
  98. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/types/database.py +0 -0
  99. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/types/patient.py +0 -0
  100. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/types/study.py +0 -0
  101. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/utils/dcm4che.py +0 -0
  102. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/utils/files.py +0 -0
  103. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom/utils/variables.py +0 -0
  104. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom.egg-info/dependency_links.txt +0 -0
  105. {dbdicom-0.2.1 → dbdicom-0.2.3}/src/dbdicom.egg-info/top_level.txt +0 -0
  106. {dbdicom-0.2.1 → dbdicom-0.2.3}/tests/test_dataset.py +0 -0
  107. {dbdicom-0.2.1 → dbdicom-0.2.3}/tests/test_dcm4che.py +0 -0
  108. {dbdicom-0.2.1 → dbdicom-0.2.3}/tests/test_manager.py +0 -0
dbdicom-0.2.3/PKG-INFO ADDED
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.1
2
+ Name: dbdicom
3
+ Version: 0.2.3
4
+ Summary: A pythonic interface for reading and writing DICOM databases
5
+ Author-email: Steven Sourbron <s.sourbron@sheffield.ac.uk>, Ebony Gunwhy <e.gunwhy@sheffield.ac.uk>
6
+ Project-URL: Homepage, https://qib-sheffield.github.io/dbdicom/
7
+ Keywords: python,medical imaging,DICOM
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Topic :: Scientific/Engineering
12
+ Classifier: Environment :: Console
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Requires-Python: >=3.6
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: matplotlib
21
+ Requires-Dist: nibabel
22
+ Requires-Dist: numpy<=1.26.4
23
+ Requires-Dist: pandas
24
+ Requires-Dist: pydicom
25
+ Requires-Dist: python-gdcm
26
+ Requires-Dist: pylibjpeg-libjpeg
27
+ Requires-Dist: importlib-resources
28
+ Requires-Dist: scipy
29
+ Requires-Dist: imageio
30
+ Provides-Extra: docs
31
+ Requires-Dist: sphinx; extra == "docs"
32
+ Requires-Dist: pydata-sphinx-theme; extra == "docs"
33
+ Requires-Dist: myst-parser; extra == "docs"
34
+ Requires-Dist: sphinx-copybutton; extra == "docs"
35
+ Requires-Dist: sphinx-design; extra == "docs"
36
+ Requires-Dist: sphinx-remove-toctrees; extra == "docs"
37
+ Requires-Dist: autodocsumm; extra == "docs"
38
+ Requires-Dist: docutils; extra == "docs"
39
+ Requires-Dist: sphinxcontrib-applehelp; extra == "docs"
40
+ Requires-Dist: sphinxcontrib-devhelp; extra == "docs"
41
+ Requires-Dist: sphinxcontrib-htmlhelp; extra == "docs"
42
+ Requires-Dist: sphinxcontrib-jsmath; extra == "docs"
43
+ Requires-Dist: sphinxcontrib-qthelp; extra == "docs"
44
+ Requires-Dist: sphinxcontrib-serializinghtml; extra == "docs"
45
+ Requires-Dist: sphinx-gallery; extra == "docs"
46
+ Provides-Extra: extensions
47
+ Requires-Dist: scipy; extra == "extensions"
48
+ Requires-Dist: scikit-image<=0.19.0; extra == "extensions"
49
+ Requires-Dist: SimpleITK-SimpleElastix; extra == "extensions"
50
+ Requires-Dist: itk-elastix; extra == "extensions"
51
+ Requires-Dist: dipy; extra == "extensions"
52
+ Requires-Dist: scikit-learn; extra == "extensions"
53
+
54
+ `dbdicom` is a Pythonic interface for reading and writing DICOM databases.
55
+
56
+ # Installation
57
+
58
+ `pip install dbdicom`
59
+
60
+ # Documentation
61
+
62
+ For more detail, see the current [dbdicom documentation](https://qib-sheffield.github.io/dbdicom/).
63
+
64
+ # Ambition
65
+
66
+ The DICOM format is the universally recognised standard for medical imaging,
67
+ but working with DICOM data remains a challenging task for data scientists.
68
+
69
+ ``dbdicom`` aims to provide an intuitive programming interface for reading and
70
+ writing DICOM databases - replacing unfamiliar DICOM-native concepts by
71
+ pythonic language and syntax.
72
+
73
+ # Disclaimer
74
+
75
+ `dbdicom` is developed in public and currently trialled in ongoing
76
+ multi-centre clinical studies
77
+ [iBEAt](https://bmcnephrol.biomedcentral.com/articles/10.1186/s12882-020-01901-x>)
78
+ and [AFiRM](https://www.uhdb.nhs.uk/afirm-study/). However, ``dbdicom`` is
79
+ work in progress and **not yet sufficiently stable for wider use**. Current
80
+ dissemination activities, such as on the
81
+ [ISMRM (Toronto 2023)](https://www.ismrm.org/23m/), are limited in scope and
82
+ intended to get early feedback from the community.
83
+
84
+
85
+
86
+
87
+
88
+
@@ -0,0 +1,35 @@
1
+ `dbdicom` is a Pythonic interface for reading and writing DICOM databases.
2
+
3
+ # Installation
4
+
5
+ `pip install dbdicom`
6
+
7
+ # Documentation
8
+
9
+ For more detail, see the current [dbdicom documentation](https://qib-sheffield.github.io/dbdicom/).
10
+
11
+ # Ambition
12
+
13
+ The DICOM format is the universally recognised standard for medical imaging,
14
+ but working with DICOM data remains a challenging task for data scientists.
15
+
16
+ ``dbdicom`` aims to provide an intuitive programming interface for reading and
17
+ writing DICOM databases - replacing unfamiliar DICOM-native concepts by
18
+ pythonic language and syntax.
19
+
20
+ # Disclaimer
21
+
22
+ `dbdicom` is developed in public and currently trialled in ongoing
23
+ multi-centre clinical studies
24
+ [iBEAt](https://bmcnephrol.biomedcentral.com/articles/10.1186/s12882-020-01901-x>)
25
+ and [AFiRM](https://www.uhdb.nhs.uk/afirm-study/). However, ``dbdicom`` is
26
+ work in progress and **not yet sufficiently stable for wider use**. Current
27
+ dissemination activities, such as on the
28
+ [ISMRM (Toronto 2023)](https://www.ismrm.org/23m/), are limited in scope and
29
+ intended to get early feedback from the community.
30
+
31
+
32
+
33
+
34
+
35
+
@@ -1,18 +1,24 @@
1
1
  # https://python-poetry.org/docs/pyproject
2
2
  # minimal required information
3
3
 
4
+ [build-system]
5
+ build-backend = 'setuptools.build_meta'
6
+ requires = ['setuptools>=61.2']
7
+
4
8
  [project]
5
9
  name = "dbdicom"
6
- version = "0.2.1"
10
+ version = "0.2.3"
7
11
  dependencies = [
8
12
  "matplotlib",
9
13
  "nibabel",
10
- "numpy",
14
+ "numpy<=1.26.4",
11
15
  "pandas",
12
16
  "pydicom",
13
17
  "python-gdcm",
14
18
  "pylibjpeg-libjpeg",
15
19
  "importlib-resources", #necessary?
20
+ 'scipy',
21
+ 'imageio',
16
22
  ]
17
23
 
18
24
  # optional information
@@ -23,7 +29,7 @@ authors = [
23
29
  { name = "Steven Sourbron", email = "s.sourbron@sheffield.ac.uk" },
24
30
  { name = "Ebony Gunwhy", email = "e.gunwhy@sheffield.ac.uk" },
25
31
  ]
26
- license = { file = "LICENSE" }
32
+ #license = "Apache-2.0"
27
33
  classifiers = [
28
34
  # How mature is this project? Common values are
29
35
  # 3 - Alpha
@@ -68,8 +74,9 @@ docs = [
68
74
  "sphinxcontrib-jsmath",
69
75
  "sphinxcontrib-qthelp",
70
76
  "sphinxcontrib-serializinghtml",
77
+ "sphinx-gallery",
71
78
  ]
72
- wrappers = [
79
+ extensions = [
73
80
  "scipy",
74
81
  # restricting to the latest stable release for now due to a bug
75
82
  # introduced in 0.20.0 that causes executables to crash. The bug is known
@@ -83,6 +90,7 @@ wrappers = [
83
90
  "scikit-image<=0.19.0",
84
91
  #"SimpleITK", "itk-elastix",
85
92
  "SimpleITK-SimpleElastix",
93
+ "itk-elastix",
86
94
  "dipy",
87
95
  "scikit-learn",
88
96
  ]
@@ -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 .utils import image
26
+ from .utils import image
27
+ from . import extensions
28
+ from . import dro
@@ -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.
@@ -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 len(shape) > 4:
408
- msg = 'With more than 4 dimensions, the coordinates argument is required'
409
- raise ValueError(msg)
410
- else:
411
- coords = {}
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
- coords['SliceLocation'] = np.arange(array.shape[2])
357
+ gridcoords['SliceLocation'] = np.arange(shape[2])
414
358
  if len(shape) > 3:
415
- coords['AcquisitionTime'] = np.arange(array.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)
416
372
  sery = series(dtype=dtype, in_study=in_study, in_database=in_database, **kwargs)
417
- sery.mute()
418
- sery.set_ndarray(array, coords=coords)
419
- sery.unmute()
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
- if coords is None:
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)
@@ -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()
@@ -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