dbdicom 0.2.6__py3-none-any.whl → 0.3.0__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 +1 -28
  2. dbdicom/api.py +267 -0
  3. dbdicom/const.py +144 -0
  4. dbdicom/dataset.py +752 -0
  5. dbdicom/dbd.py +719 -0
  6. dbdicom/external/__pycache__/__init__.cpython-311.pyc +0 -0
  7. dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc +0 -0
  8. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc +0 -0
  9. dbdicom/register.py +527 -0
  10. dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
  11. dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +153 -26
  12. dbdicom/{ds/types → sop_classes}/mr_image.py +185 -140
  13. dbdicom/sop_classes/parametric_map.py +307 -0
  14. dbdicom/sop_classes/secondary_capture.py +140 -0
  15. dbdicom/sop_classes/segmentation.py +311 -0
  16. dbdicom/{ds/types → sop_classes}/ultrasound_multiframe_image.py +1 -15
  17. dbdicom/{ds/types → sop_classes}/xray_angiographic_image.py +2 -17
  18. dbdicom/utils/arrays.py +36 -0
  19. dbdicom/utils/files.py +0 -20
  20. dbdicom/utils/image.py +10 -629
  21. dbdicom-0.3.0.dist-info/METADATA +28 -0
  22. dbdicom-0.3.0.dist-info/RECORD +53 -0
  23. dbdicom/create.py +0 -457
  24. dbdicom/dro.py +0 -174
  25. dbdicom/ds/__init__.py +0 -10
  26. dbdicom/ds/create.py +0 -63
  27. dbdicom/ds/dataset.py +0 -869
  28. dbdicom/ds/dictionaries.py +0 -620
  29. dbdicom/ds/types/parametric_map.py +0 -226
  30. dbdicom/extensions/__init__.py +0 -9
  31. dbdicom/extensions/dipy.py +0 -448
  32. dbdicom/extensions/elastix.py +0 -503
  33. dbdicom/extensions/matplotlib.py +0 -107
  34. dbdicom/extensions/numpy.py +0 -271
  35. dbdicom/extensions/scipy.py +0 -1512
  36. dbdicom/extensions/skimage.py +0 -1030
  37. dbdicom/extensions/sklearn.py +0 -243
  38. dbdicom/extensions/vreg.py +0 -1390
  39. dbdicom/manager.py +0 -2132
  40. dbdicom/message.py +0 -119
  41. dbdicom/pipelines.py +0 -66
  42. dbdicom/record.py +0 -1893
  43. dbdicom/types/database.py +0 -107
  44. dbdicom/types/instance.py +0 -231
  45. dbdicom/types/patient.py +0 -40
  46. dbdicom/types/series.py +0 -2874
  47. dbdicom/types/study.py +0 -58
  48. dbdicom-0.2.6.dist-info/METADATA +0 -72
  49. dbdicom-0.2.6.dist-info/RECORD +0 -66
  50. {dbdicom-0.2.6.dist-info → dbdicom-0.3.0.dist-info}/WHEEL +0 -0
  51. {dbdicom-0.2.6.dist-info → dbdicom-0.3.0.dist-info}/licenses/LICENSE +0 -0
  52. {dbdicom-0.2.6.dist-info → dbdicom-0.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,53 @@
1
+ dbdicom/__init__.py,sha256=DyogeTraV6o-FgWdBCbtVEaMmdkMQHkYkraDIE0t8OA,25
2
+ dbdicom/api.py,sha256=_baV2dR9Szay4z2_JY-QmTB9gTTc_PB7OzzgqRwmYHg,8945
3
+ dbdicom/const.py,sha256=BqBiRRjeiSqDr1W6YvaayD8WKCjG4Cny2NT0GeLM6bI,4269
4
+ dbdicom/dataset.py,sha256=IVTLq4pTydwKjS9-xCQAqiSd0Xm63JxCxos4HemtuVs,23945
5
+ dbdicom/dbd.py,sha256=MKZDnQu1R0s1RlJ5VAKcty4UFmtMg6aXz9epjLilYzc,29001
6
+ dbdicom/register.py,sha256=Nt-Q3Nvb72qRqSL1ervuunp2LBuOZEs-K8YUqihR_oQ,21210
7
+ dbdicom/external/__init__.py,sha256=XNQqfspyf6vFGedXlRKZsUB8k8E-0W19Uamwn8Aioxo,316
8
+ dbdicom/external/__pycache__/__init__.cpython-311.pyc,sha256=tvFkDCXniSXAqkZTFggZPxaPTVgaRmpeGYZlZw0Ibhc,534
9
+ dbdicom/external/dcm4che/README.md,sha256=0aAGRs36W3_0s5LzWHRGf_tqariS_JP4iJggaxnD4Xw,8987
10
+ dbdicom/external/dcm4che/__init__.py,sha256=YwpeMCLrxffGOkchsGjgAuB6ia3VX_tx9Y7ru9EWtoY,35
11
+ dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc,sha256=qbKEVGsXw9bmCxsR6KssmR3ZoGJAkkVv5LQ2eFVhs5M,248
12
+ dbdicom/external/dcm4che/bin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ dbdicom/external/dcm4che/bin/deidentify,sha256=64MNIEpp-CWzFSb6TV0KtyCBvD7XyEsovRjBeyxDqSc,1698
14
+ dbdicom/external/dcm4che/bin/deidentify.bat,sha256=kVXUkcy1C4Y3KjC2NJwmmR0pufSJWmaof_LR5CTAxMg,1455
15
+ dbdicom/external/dcm4che/bin/emf2sf,sha256=svCzkZ-QhdVTV0NNHOpBiwNBMODVWZHJIFA7cWaN2bM,1622
16
+ dbdicom/external/dcm4che/bin/emf2sf.bat,sha256=Vh0ry9KNJX_WXcyCrLSxbJ_6Crot9rjmwi__u2GZqLY,1375
17
+ dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc,sha256=NnB9_qHwjxDZrdid-_YGOWCzkEy8p9ka3FHiCUtFX-M,195
18
+ dbdicom/external/dcm4che/etc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ dbdicom/external/dcm4che/etc/emf2sf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ dbdicom/external/dcm4che/etc/emf2sf/log4j.properties,sha256=3hHcBFt2oNRjvHtix5bfuEsnKfdv5IYOkbsyoY9g7cM,223
21
+ dbdicom/external/dcm4che/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ dbdicom/external/dcm4che/lib/commons-cli-1.4.jar,sha256=_Tx8lUWpzbIFHR-RVcT3ax5KxaVzBEBKbu21eP-6cyg,53820
23
+ dbdicom/external/dcm4che/lib/dcm4che-core-5.23.1.jar,sha256=UEnSQwDE1IHv5kGtK8vkdaQ9OF_cNwOsxB5NSIMkS2s,506505
24
+ dbdicom/external/dcm4che/lib/dcm4che-emf-5.23.1.jar,sha256=fcspodANPlRz-3EIx3TEZWU45JDP4RXzLuWbFoQEPMY,13418
25
+ dbdicom/external/dcm4che/lib/dcm4che-tool-common-5.23.1.jar,sha256=3SN3NSTf4AIHuUCsk_5E2wXd3MuFvQZIYSSq1PHcgNM,21301
26
+ dbdicom/external/dcm4che/lib/dcm4che-tool-emf2sf-5.23.1.jar,sha256=pkpJRD00HQ4sEjaL7_iQ_8lBeQPttHelNAxcT-rMIVQ,7332
27
+ dbdicom/external/dcm4che/lib/log4j-1.2.17.jar,sha256=HTFpZEVpdyBScJF1Q2kIKmZRvUl4G2AF3rlOVnU0Bvk,489884
28
+ dbdicom/external/dcm4che/lib/slf4j-api-1.7.30.jar,sha256=zboHlk0btAoHYUhcax6ML4_Z6x0ZxTkorA1_lRAQXFc,41472
29
+ dbdicom/external/dcm4che/lib/slf4j-log4j12-1.7.30.jar,sha256=TUHgHEDK-KbHSt0rBzBV2KTOHDDlgVQXexPxLXirvns,12211
30
+ dbdicom/external/dcm4che/lib/macosx-x86-64/libopencv_java.jnilib,sha256=A2uOWIUQX3KcG850ElpW4lVtn2uyPpJHZq9cPlpJjMY,15137664
31
+ dbdicom/external/dcm4che/lib/windows-x86/clib_jiio.dll,sha256=C2dAjNyefOm3POrUxorEF6T-FTztpo0nfGAsUrDyQyg,720896
32
+ dbdicom/external/dcm4che/lib/windows-x86/clib_jiio_sse2.dll,sha256=uD9GLN_hPf9mM9APzlp9j6770awKP6xnlaooMrxHpkg,1089536
33
+ dbdicom/external/dcm4che/lib/windows-x86/clib_jiio_util.dll,sha256=wi4yyrI1gTRo_bBpj0E097BQBiHZd8IqVifKr6kfkRE,40960
34
+ dbdicom/external/dcm4che/lib/windows-x86/opencv_java.dll,sha256=QanyzLy0Cd79-aOVPwOcXwikUYeutne0Au-Um91_B4M,8505856
35
+ dbdicom/external/dcm4che/lib/windows-x86-64/opencv_java.dll,sha256=TmjW2SbG4MR3GQ95T8xCVVDLgsdKukgaHBPUvWkfXp8,11039232
36
+ dbdicom/sop_classes/ct_image.py,sha256=16PNv_0e1_7cfxE12JWlx5YQeaTAQVzwtXTjxs3aonk,2812
37
+ dbdicom/sop_classes/enhanced_mr_image.py,sha256=13j4EGXniBpJxpzzL3Xa4y3g5OKhMd5Ct7cjPGOYQY4,35496
38
+ dbdicom/sop_classes/mr_image.py,sha256=6V2OyjwkaZxoljImNREU0Du4NJLHHsY_GgOe2XQsmNg,10683
39
+ dbdicom/sop_classes/parametric_map.py,sha256=eyJdHUxh9KUI7qPaGANU2H3R1Br4CH0XHmRIGvrsKY8,10220
40
+ dbdicom/sop_classes/secondary_capture.py,sha256=wgNRX8qyhV7HR7Jq2tQWPPuGpiRzYl6qPOgK6qFbPUc,4541
41
+ dbdicom/sop_classes/segmentation.py,sha256=I8-PciIoIz27_-dZ4esBZSw0TBBbO8KbNYTiTmVe62g,11465
42
+ dbdicom/sop_classes/ultrasound_multiframe_image.py,sha256=j3KN5R90j6WwPMy01hAN2_XSum5TvksF2MYoNGfX_yE,2797
43
+ dbdicom/sop_classes/xray_angiographic_image.py,sha256=nWysCGaEWKVNItnOgyJfcGMpS3oEK1T0_uNR2D7p0Ls,3270
44
+ dbdicom/utils/arrays.py,sha256=wiqCczLXlNl0qIePVOwCYvbAJhPveNorplkhtGleS48,1121
45
+ dbdicom/utils/dcm4che.py,sha256=Vxq8NYWWK3BuqJkzhBQ89oMqzJlnxqTxgsgTo_Frznc,2317
46
+ dbdicom/utils/files.py,sha256=qhWNJqeWnRjDNbERpC6Mz962_TW9mFdvd2lnBbK3xt4,2259
47
+ dbdicom/utils/image.py,sha256=s1P8m-s64ygKSh_X4DdV96LC4DvCe3KO3_71l72zWoU,4057
48
+ dbdicom/utils/variables.py,sha256=vUh5cDnmCft5hoXDYXUvfkg5Cy5WlgMAogU38Y_BKRo,5753
49
+ dbdicom-0.3.0.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
50
+ dbdicom-0.3.0.dist-info/METADATA,sha256=0NHxTTJitzp6e80Ly6NFWNsAepbjRTQWsBk0L-FqsbE,1075
51
+ dbdicom-0.3.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
52
+ dbdicom-0.3.0.dist-info/top_level.txt,sha256=nJWxXg4YjD6QblfmhrzTMXcr8FSKNc0Yk-CAIDUsYkQ,8
53
+ dbdicom-0.3.0.dist-info/RECORD,,
dbdicom/create.py DELETED
@@ -1,457 +0,0 @@
1
- # Importing annotations to handle or sign in import type hints
2
- from __future__ import annotations
3
-
4
- import numpy as np
5
- from dbdicom.manager import Manager
6
- from dbdicom.types.database import Database
7
- from dbdicom.types.patient import Patient
8
- from dbdicom.types.study import Study
9
- from dbdicom.types.series import Series, _coords_size, _grid_to_coords
10
- from dbdicom.types.instance import Instance
11
-
12
-
13
- def create(manager, uid='Database', type=None, key=None, **kwargs):
14
-
15
- if uid is None:
16
- return
17
- if uid == 'Database':
18
- return Database(create, manager, **kwargs)
19
-
20
- # This case is included for convenience but should be avoided
21
- # at all costs because the lookup of type at creation is very expensive.
22
- # Considering removing and make type a requirement
23
- if type is None:
24
- type = manager.type(uid)
25
-
26
- if type == 'Patient':
27
- return Patient(create, manager, uid, key=key, **kwargs)
28
- if type == 'Study':
29
- return Study(create, manager, uid, key=key, **kwargs)
30
- if type == 'Series':
31
- return Series(create, manager, uid, key=key, **kwargs)
32
- if type == 'Instance':
33
- return Instance(create, manager, uid, key=key, **kwargs)
34
-
35
-
36
- def database(path:str=None, **kwargs) -> Database:
37
- """create a new database in memory or open an existing one on disk.
38
-
39
- Args:
40
- path (str, optional): path to an existing database. In case none is provided, this will create a new empty database.
41
- kwargs: any valid DICOM (tag, value) pair can be provided as keyword argument. These attributes will be assigned to the database and inherited by all DICOM objects later saved in the database.
42
-
43
- Returns:
44
- Database: Instance of the Database class.
45
-
46
- Note:
47
- If no path is provided, a new database is created in memory. Any changes or additions to that database will only exist in memory until the new database is saved with .save().
48
-
49
- See Also:
50
- :func:`~patient`
51
- :func:`~study`
52
- :func:`~series`
53
-
54
- Example:
55
-
56
- Create a new database in memory and print the contents:
57
-
58
- >>> database = db.database()
59
- >>> database.print()
60
- ---------- DATABASE --------------
61
- Location: In memory
62
- ----------------------------------
63
-
64
- Open an existing DICOM database and check the contents (in this example we are using an edited version of a RIDER dataset case):
65
-
66
- >>> database = db.database('path\\to\\RIDER\\case')
67
- >>> database.print()
68
- ---------- DATABASE --------------
69
- Location: path\to\DICOM\database
70
- Study BRAIN^RESEARCH [19040321]
71
- Series 014 [sag 3d gre +c]
72
- Nr of instances: 176
73
- Study BRAIN^RESEARCH [19040321]
74
- Series 017 [sag 3d flair +c]
75
- Nr of instances: 210
76
- Study BRAIN^RESEARCH [19040321]
77
- Series 005 [ax tensor]
78
- Nr of instances: 468
79
- Series 006 [ax 5 flip]
80
- Nr of instances: 16
81
- Series 007 [ax 10 flip]
82
- Nr of instances: 16
83
- Series 008 [ax 15 flip]
84
- Nr of instances: 16
85
- Series 009 [ax 20 flip]
86
- Nr of instances: 16
87
- Series 010 [ax 25 flip]
88
- Nr of instances: 16
89
- Series 011 [ax 30 flip]
90
- Nr of instances: 16
91
- Series 012 [perfusion]
92
- Nr of instances: 1040
93
- Study BRAIN^RESEARCH [19040323]
94
- Series 017 [sag 3d flair +c]
95
- Nr of instances: 160
96
- Series 018 [sag 3d flair +c_Copy]
97
- Nr of instances: 160
98
- Series 019 [MergedSeries]
99
- Nr of instances: 320
100
- Study BRAIN^RESEARCH [19040323]
101
- Series 005 [ax tensor]
102
- Nr of instances: 468
103
- Series 006 [ax 5 flip]
104
- Nr of instances: 16
105
- Series 007 [ax 10 flip]
106
- Nr of instances: 16
107
- Series 008 [ax 15 flip]
108
- Nr of instances: 16
109
- Series 009 [ax 20 flip]
110
- Nr of instances: 16
111
- Series 010 [ax 25 flip]
112
- Nr of instances: 16
113
- Series 011 [ax 30 flip]
114
- Nr of instances: 16
115
- Series 012 [perfusion]
116
- Nr of instances: 1040
117
- Study BRAIN^RESEARCH [19040323]
118
- Series 015 [sag 3d gre +c]
119
- Nr of instances: 176
120
- ----------------------------------
121
- """
122
- if path is None:
123
- mgr = Manager()
124
- else:
125
- mgr = Manager(path, **kwargs)
126
- mgr.open(path)
127
- return Database(create, mgr, **kwargs)
128
-
129
-
130
- def patient(in_database:Database=None, **kwargs)->Patient:
131
- """Create an empty DICOM patient record.
132
-
133
- Args:
134
- in_database (Database, optional): If provided, the patient is created in this database. Defaults to None.
135
- kwargs: Any valid DICOM (tag, value) pair to set properties of the new patient
136
-
137
- Returns:
138
- Study: DICOM patient with defaults for all attributes.
139
-
140
- See Also:
141
- :func:`~database`
142
- :func:`~study`
143
- :func:`~series`
144
-
145
- Example:
146
- Create an empty patient in memory:
147
-
148
- >>> patient = db.patient()
149
- >>> patient.print()
150
- ---------- PATIENT -------------
151
- Patient New Patient
152
- --------------------------------
153
-
154
- Note since no patient object is provided, a default database is created automatically.
155
-
156
- >>> patient.database().print()
157
- ---------- DATABASE --------------
158
- Location: In memory
159
- Patient New Patient
160
- ----------------------------------
161
- """
162
- if in_database is None:
163
- db = database()
164
- else:
165
- db = in_database
166
- patient = db.new_patient(**kwargs)
167
- if in_database is None:
168
- db.save()
169
- return patient
170
-
171
-
172
- def study(in_patient:Patient=None, in_database:Database=None, **kwargs)->Study:
173
- """Create an empty DICOM study record.
174
-
175
- Args:
176
- in_patient (Patient, optional): If provided, the study is created in this Patient. Defaults to None.
177
- in_database (Database, optional): If provided, the study is created in this database. Defaults to None.
178
- kwargs: Any valid DICOM (tag, value) pair to set properties of the new study
179
-
180
- Returns:
181
- Study: DICOM study with defaults for all attributes.
182
-
183
- See Also:
184
- :func:`~database`
185
- :func:`~patient`
186
- :func:`~series`
187
-
188
- Example:
189
- Create an empty study in memory:
190
-
191
- >>> study = db.study()
192
- >>> study.print()
193
- ---------- STUDY ---------------
194
- Study New Study [None]
195
- --------------------------------
196
-
197
- Note since no patient object is provided, a default hierarchy is created automatically:
198
-
199
- >>> study.database().print()
200
- ---------- DATABASE --------------
201
- Location: In memory
202
- Patient New Patient
203
- Study New Study [None]
204
- ----------------------------------
205
- """
206
-
207
- if in_patient is not None:
208
- study = in_patient.new_study(**kwargs)
209
- else:
210
- if in_database is None:
211
- db = database()
212
- else:
213
- db = in_database
214
- patient = db.new_patient()
215
- study = patient.new_study(**kwargs)
216
- if in_database is None:
217
- db.save()
218
- return study
219
-
220
-
221
- def series(dtype='mri', in_study:Study=None, in_database:Database=None, **kwargs)->Series:
222
- """Create an empty DICOM series.
223
-
224
- Args:
225
- dtype (str, optional): The type of the series to create. Defaults to 'mri'.
226
- in_study (Study, optional): If provided, the series is created in this study. Defaults to None.
227
- in_database (Database, optional): If provided, the series is created in this database. Defaults to None.
228
- kwargs: Any valid DICOM (tag, value) pair to set properties of the new patient
229
-
230
- Returns:
231
- Series: DICOM series with defaults for all attributes.
232
-
233
- Raises:
234
- ValueError: if a dtype is requested that is currently not yet implemented
235
-
236
- See Also:
237
- :func:`~database`
238
- :func:`~patient`
239
- :func:`~study`
240
- :func:`~as_series`
241
- :func:`~zeros`
242
-
243
- Example:
244
- Create an empty series in memory.
245
-
246
- >>> series = db.series()
247
- >>> series.print()
248
- ---------- SERIES --------------
249
- Series 001 [New Series]
250
- Nr of instances: 0
251
- --------------------------------
252
-
253
- Note since no patient and study records are provided, a default hierarchy is created automatically:
254
-
255
- >>> series.database().print()
256
- ---------- DATABASE --------------
257
- Location: In memory
258
- Patient New Patient
259
- Study New Study [None]
260
- Series 001 [New Series]
261
- Nr of instances: 0
262
- ----------------------------------
263
- """
264
- if dtype not in ['mri', 'MRImage']:
265
- message = 'dbdicom can only create images of type MRImage at this stage'
266
- raise ValueError(message)
267
-
268
- if in_study is not None:
269
- series = in_study.new_series()
270
- else:
271
- if in_database is None:
272
- _database = database()
273
- _database.mute()
274
- else:
275
- _database = in_database
276
- patient = _database.new_patient()
277
- study = patient.new_study()
278
- series = study.new_series(**kwargs)
279
- if in_database is None:
280
- _database.save()
281
- return series
282
-
283
-
284
-
285
-
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:
287
- """Create a DICOM series from a numpy array.
288
-
289
- Args:
290
- array (np.ndarray): numpy.ndarray with image 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.
293
- dtype (str, optional): The type of the series to create. Defaults to 'mri'.
294
- in_study (Study, optional): If provided, the series is created in this study. Defaults to None.
295
- in_database (Database, optional): If provided, the series is created in this database. Defaults to None.
296
- kwargs: Any valid DICOM (tag, value) pair to set properties of the new patient
297
-
298
- Returns:
299
- Series: DICOM series containing the provided array as image data and defaults for all other parameters.
300
-
301
- Raises:
302
- ValueError: if a dtype is requested that is currently not yet implemented
303
- ValueError: If the coords do not match up with the shape of the array.
304
-
305
- See Also:
306
- :func:`~series`
307
- :func:`~zeros`
308
-
309
- Example:
310
- Create a series containing a 4-dimensional array. Since the default format is single-frame MRImage, this produces 6 separate files.
311
-
312
- >>> array = np.zeros((128, 128, 3, 2))
313
- >>> zeros = db.as_series(array)
314
- >>> zeros.print()
315
- ---------- SERIES --------------
316
- Series 001 [New Series]
317
- Nr of instances: 6
318
- MRImage 000001
319
- MRImage 000002
320
- MRImage 000003
321
- MRImage 000004
322
- MRImage 000005
323
- MRImage 000006
324
- --------------------------------
325
-
326
- Since no coordinates are provided, these are assumed to be SliceLocation and AcquisitionTime with default values:
327
-
328
- >>> print(zeros.SliceLocation)
329
- [0.0, 1.0, 2.0]
330
- >>> print(zeros.AcquisitionTime)
331
- [0.0, 1.0]
332
-
333
- To override these defaults, set coordinates explicitly using a dictionary. For instance, for an MRI series of images acquired at a single slice location for 3 flip angles and 2 repetition times, the coordinates of the series are:
334
-
335
- >>> coords = {
336
- ... 'FlipAngle': [2, 15, 30],
337
- ... 'RepetitionTime': [2.5, 5.0],
338
- ... }
339
-
340
- Now create another series, providing coordinates, and list the unique values of flip angle and repetition time:
341
- >>> zeros = db.as_series(array, coords)
342
- >>> print(zeros.FlipAngle)
343
- [2.0, 15.0, 30.0]
344
- >>> print(zeros.RepetitionTime)
345
- [2.5, 5.0]
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)
372
- sery = series(dtype=dtype, in_study=in_study, in_database=in_database, **kwargs)
373
- if coords is None:
374
- return sery
375
- sery.expand(coords)
376
- return sery
377
-
378
-
379
- def zeros(shape:tuple, coords:dict=None, gridcoords:dict=None, **kwargs) -> Series:
380
- """Create a DICOM series populated with zeros.
381
-
382
- This is a convenience wrapper providing a numpy-like interface for :func:`~as_series`.
383
-
384
- Args:
385
- shape (tuple): shape of the array
386
- kwargs: see :func:`~series`
387
-
388
- Returns:
389
- Series: DICOM series with zero values
390
-
391
- See Also:
392
- :func:`~ones`
393
-
394
- Example:
395
- Create a series containing a 4-dimensional array of zeros:
396
-
397
- >>> zeros = db.zeros((128, 128, 2, 3))
398
- >>> zeros.print()
399
- ---------- SERIES --------------
400
- Series 001 [New Series]
401
- Nr of instances: 6
402
- MRImage 000001
403
- MRImage 000002
404
- MRImage 000003
405
- MRImage 000004
406
- MRImage 000005
407
- MRImage 000006
408
- --------------------------------
409
-
410
- This is effectively shorthand for:
411
-
412
- >>> array = np.zeros((128, 128, 2, 3))
413
- >>> zeros = db.as_series(array)
414
- """
415
-
416
- array = np.zeros(shape, dtype=np.float32)
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 DELETED
@@ -1,174 +0,0 @@
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()