dbdicom 0.2.0__py3-none-any.whl → 0.3.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. dbdicom/__init__.py +3 -25
  2. dbdicom/api.py +496 -0
  3. dbdicom/const.py +144 -0
  4. dbdicom/database.py +133 -0
  5. dbdicom/dataset.py +471 -0
  6. dbdicom/dbd.py +1290 -0
  7. dbdicom/external/__pycache__/__init__.cpython-311.pyc +0 -0
  8. dbdicom/external/dcm4che/__pycache__/__init__.cpython-311.pyc +0 -0
  9. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-311.pyc +0 -0
  10. dbdicom/external/dcm4che/bin/emf2sf +57 -57
  11. dbdicom/register.py +402 -0
  12. dbdicom/{ds/types → sop_classes}/ct_image.py +2 -16
  13. dbdicom/{ds/types → sop_classes}/enhanced_mr_image.py +206 -160
  14. dbdicom/sop_classes/mr_image.py +338 -0
  15. dbdicom/sop_classes/parametric_map.py +381 -0
  16. dbdicom/sop_classes/secondary_capture.py +140 -0
  17. dbdicom/sop_classes/segmentation.py +311 -0
  18. dbdicom/{ds/types → sop_classes}/ultrasound_multiframe_image.py +1 -15
  19. dbdicom/{ds/types → sop_classes}/xray_angiographic_image.py +2 -17
  20. dbdicom/utils/arrays.py +142 -0
  21. dbdicom/utils/files.py +0 -20
  22. dbdicom/utils/image.py +43 -466
  23. dbdicom/utils/pydicom_dataset.py +386 -0
  24. dbdicom-0.3.16.dist-info/METADATA +26 -0
  25. dbdicom-0.3.16.dist-info/RECORD +54 -0
  26. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/WHEEL +1 -1
  27. dbdicom/create.py +0 -450
  28. dbdicom/ds/__init__.py +0 -10
  29. dbdicom/ds/create.py +0 -63
  30. dbdicom/ds/dataset.py +0 -841
  31. dbdicom/ds/dictionaries.py +0 -620
  32. dbdicom/ds/types/mr_image.py +0 -267
  33. dbdicom/ds/types/parametric_map.py +0 -226
  34. dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  35. dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  36. dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  37. dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  38. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  39. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  40. dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  41. dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  42. dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  43. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  44. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  45. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  46. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  47. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  48. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  49. dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  50. dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  51. dbdicom/manager.py +0 -2077
  52. dbdicom/message.py +0 -119
  53. dbdicom/record.py +0 -1526
  54. dbdicom/types/database.py +0 -107
  55. dbdicom/types/instance.py +0 -184
  56. dbdicom/types/patient.py +0 -40
  57. dbdicom/types/series.py +0 -816
  58. dbdicom/types/study.py +0 -58
  59. dbdicom/utils/variables.py +0 -155
  60. dbdicom/utils/vreg.py +0 -2626
  61. dbdicom/wrappers/__init__.py +0 -7
  62. dbdicom/wrappers/dipy.py +0 -462
  63. dbdicom/wrappers/elastix.py +0 -855
  64. dbdicom/wrappers/numpy.py +0 -119
  65. dbdicom/wrappers/scipy.py +0 -1413
  66. dbdicom/wrappers/skimage.py +0 -1030
  67. dbdicom/wrappers/sklearn.py +0 -151
  68. dbdicom/wrappers/vreg.py +0 -273
  69. dbdicom-0.2.0.dist-info/METADATA +0 -276
  70. dbdicom-0.2.0.dist-info/RECORD +0 -81
  71. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info/licenses}/LICENSE +0 -0
  72. {dbdicom-0.2.0.dist-info → dbdicom-0.3.16.dist-info}/top_level.txt +0 -0
@@ -1,57 +1,57 @@
1
- #!/bin/sh
2
- # -------------------------------------------------------------------------
3
- # emf2sf Launcher
4
- # -------------------------------------------------------------------------
5
-
6
- MAIN_CLASS=org.dcm4che3.tool.emf2sf.Emf2sf
7
- MAIN_JAR=dcm4che-tool-emf2sf-5.23.1.jar
8
-
9
- DIRNAME="`dirname "$0"`"
10
-
11
- # OS specific support (must be 'true' or 'false').
12
- cygwin=false;
13
- case "`uname`" in
14
- CYGWIN*)
15
- cygwin=true
16
- ;;
17
- esac
18
-
19
- # For Cygwin, ensure paths are in UNIX format before anything is touched
20
- if $cygwin ; then
21
- [ -n "$DCM4CHE_HOME" ] &&
22
- DCM4CHE_HOME=`cygpath --unix "$DCM4CHE_HOME"`
23
- [ -n "$JAVA_HOME" ] &&
24
- JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
25
- fi
26
-
27
- # Setup DCM4CHE_HOME
28
- if [ "x$DCM4CHE_HOME" = "x" ]; then
29
- DCM4CHE_HOME=`cd "$DIRNAME"/..; pwd`
30
- fi
31
-
32
- # Setup the JVM
33
- if [ "x$JAVA_HOME" != "x" ]; then
34
- JAVA=$JAVA_HOME/bin/java
35
- else
36
- JAVA="java"
37
- fi
38
-
39
- # Setup the classpath
40
- CP="$DCM4CHE_HOME/etc/emf2sf/"
41
- CP="$CP:$DCM4CHE_HOME/lib/$MAIN_JAR"
42
- CP="$CP:$DCM4CHE_HOME/lib/dcm4che-core-5.23.1.jar"
43
- CP="$CP:$DCM4CHE_HOME/lib/dcm4che-emf-5.23.1.jar"
44
- CP="$CP:$DCM4CHE_HOME/lib/dcm4che-tool-common-5.23.1.jar"
45
- CP="$CP:$DCM4CHE_HOME/lib/slf4j-api-1.7.30.jar"
46
- CP="$CP:$DCM4CHE_HOME/lib/slf4j-log4j12-1.7.30.jar"
47
- CP="$CP:$DCM4CHE_HOME/lib/log4j-1.2.17.jar"
48
- CP="$CP:$DCM4CHE_HOME/lib/commons-cli-1.4.jar"
49
-
50
- # For Cygwin, switch paths to Windows format before running java
51
- if $cygwin; then
52
- JAVA=`cygpath --path --windows "$JAVA"`
53
- CP=`cygpath --path --windows "$CP"`
54
- fi
55
-
56
- # Execute the JVM
57
- exec "$JAVA" $JAVA_OPTS -cp "$CP" $MAIN_CLASS "$@"
1
+ #!/bin/sh
2
+ # -------------------------------------------------------------------------
3
+ # emf2sf Launcher
4
+ # -------------------------------------------------------------------------
5
+
6
+ MAIN_CLASS=org.dcm4che3.tool.emf2sf.Emf2sf
7
+ MAIN_JAR=dcm4che-tool-emf2sf-5.23.1.jar
8
+
9
+ DIRNAME="`dirname "$0"`"
10
+
11
+ # OS specific support (must be 'true' or 'false').
12
+ cygwin=false;
13
+ case "`uname`" in
14
+ CYGWIN*)
15
+ cygwin=true
16
+ ;;
17
+ esac
18
+
19
+ # For Cygwin, ensure paths are in UNIX format before anything is touched
20
+ if $cygwin ; then
21
+ [ -n "$DCM4CHE_HOME" ] &&
22
+ DCM4CHE_HOME=`cygpath --unix "$DCM4CHE_HOME"`
23
+ [ -n "$JAVA_HOME" ] &&
24
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
25
+ fi
26
+
27
+ # Setup DCM4CHE_HOME
28
+ if [ "x$DCM4CHE_HOME" = "x" ]; then
29
+ DCM4CHE_HOME=`cd "$DIRNAME"/..; pwd`
30
+ fi
31
+
32
+ # Setup the JVM
33
+ if [ "x$JAVA_HOME" != "x" ]; then
34
+ JAVA=$JAVA_HOME/bin/java
35
+ else
36
+ JAVA="java"
37
+ fi
38
+
39
+ # Setup the classpath
40
+ CP="$DCM4CHE_HOME/etc/emf2sf/"
41
+ CP="$CP:$DCM4CHE_HOME/lib/$MAIN_JAR"
42
+ CP="$CP:$DCM4CHE_HOME/lib/dcm4che-core-5.23.1.jar"
43
+ CP="$CP:$DCM4CHE_HOME/lib/dcm4che-emf-5.23.1.jar"
44
+ CP="$CP:$DCM4CHE_HOME/lib/dcm4che-tool-common-5.23.1.jar"
45
+ CP="$CP:$DCM4CHE_HOME/lib/slf4j-api-1.7.30.jar"
46
+ CP="$CP:$DCM4CHE_HOME/lib/slf4j-log4j12-1.7.30.jar"
47
+ CP="$CP:$DCM4CHE_HOME/lib/log4j-1.2.17.jar"
48
+ CP="$CP:$DCM4CHE_HOME/lib/commons-cli-1.4.jar"
49
+
50
+ # For Cygwin, switch paths to Windows format before running java
51
+ if $cygwin; then
52
+ JAVA=`cygpath --path --windows "$JAVA"`
53
+ CP=`cygpath --path --windows "$CP"`
54
+ fi
55
+
56
+ # Execute the JVM
57
+ exec "$JAVA" $JAVA_OPTS -cp "$CP" $MAIN_CLASS "$@"
dbdicom/register.py ADDED
@@ -0,0 +1,402 @@
1
+ import os
2
+ from pathlib import Path
3
+ import csv
4
+
5
+
6
+ class AmbiguousError(Exception):
7
+ pass
8
+
9
+
10
+ def add_instance(dbtree:list, attr, rel_path):
11
+
12
+ # Get patient and create if needed
13
+ pts = [pt for pt in sorted(dbtree, key=lambda pt: pt['PatientID']) if pt['PatientID']==attr['PatientID']]
14
+ if pts==[]:
15
+ pt = {
16
+ 'PatientName': attr['PatientName'],
17
+ 'PatientID': attr['PatientID'],
18
+ 'studies': [],
19
+ }
20
+ dbtree.append(pt)
21
+ else:
22
+ pt = pts[0]
23
+
24
+ # Get study and create if needed
25
+ sts = [st for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']) if st['StudyInstanceUID']==attr['StudyInstanceUID']]
26
+ if sts==[]:
27
+ st = {
28
+ 'StudyDescription': attr['StudyDescription'],
29
+ 'StudyID': attr['StudyID'],
30
+ 'StudyInstanceUID': attr['StudyInstanceUID'],
31
+ 'series': [],
32
+ }
33
+ pt['studies'].append(st)
34
+ else:
35
+ st = sts[0]
36
+
37
+ # Get series and create if needed
38
+ srs = [sr for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']) if sr['SeriesInstanceUID']==attr['SeriesInstanceUID']]
39
+ if srs==[]:
40
+ sr = {
41
+ 'SeriesNumber': attr['SeriesNumber'],
42
+ 'SeriesDescription': attr['SeriesDescription'],
43
+ 'SeriesInstanceUID': attr['SeriesInstanceUID'],
44
+ 'instances': {},
45
+ }
46
+ st['series'].append(sr)
47
+ else:
48
+ sr = srs[0]
49
+
50
+ # Add instance
51
+ sr['instances'][attr['InstanceNumber']] = rel_path
52
+
53
+ return dbtree
54
+
55
+
56
+ def files(dbtree, entity):
57
+ # Raises an error if the entity does not exist or has no files
58
+ relpath = index(dbtree, entity)
59
+ if relpath==[]:
60
+ raise ValueError(f'No files in entity {entity}')
61
+ if isinstance(entity, str):
62
+ return [os.path.join(entity, str(Path(*f))) for f in relpath]
63
+ else:
64
+ return [os.path.join(entity[0], str(Path(*f))) for f in relpath]
65
+
66
+
67
+ def index(dbtree, entity):
68
+ if isinstance(entity, str):
69
+ idx = []
70
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
71
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
72
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
73
+ idx += list(sr['instances'].values())
74
+ return idx
75
+ elif len(entity)==2:
76
+ patient_id = entity[1]
77
+ idx = []
78
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
79
+ if pt['PatientID'] == patient_id:
80
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
81
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
82
+ idx += list(sr['instances'].values())
83
+ return idx
84
+ raise ValueError(f'Patient {patient_id} not found')
85
+ elif len(entity)==3:
86
+ study_uid = uid(dbtree, entity)
87
+ idx = []
88
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
89
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
90
+ if st['StudyInstanceUID'] == study_uid:
91
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
92
+ idx += list(sr['instances'].values())
93
+ return idx
94
+ raise ValueError(f'Study {study_uid} not found')
95
+ elif len(entity)==4:
96
+ series_uid = uid(dbtree, entity)
97
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
98
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
99
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
100
+ if sr['SeriesInstanceUID'] == series_uid:
101
+ return list(sr['instances'].values())
102
+ raise ValueError(f'Series {series_uid} not found')
103
+
104
+ def remove(dbtree, entity):
105
+ if len(entity)==2:
106
+ patient_id = entity[1]
107
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
108
+ if pt['PatientID'] == patient_id:
109
+ dbtree.remove(pt)
110
+ elif len(entity)==3:
111
+ study_uid = uid(dbtree, entity)
112
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
113
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
114
+ if st['StudyInstanceUID'] == study_uid:
115
+ pt['studies'].remove(st)
116
+ elif len(entity)==4:
117
+ series_uid = uid(dbtree, entity)
118
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
119
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
120
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
121
+ if sr['SeriesInstanceUID'] == series_uid:
122
+ st['series'].remove(sr)
123
+ return dbtree
124
+
125
+
126
+ def drop(dbtree, relpaths):
127
+ for pt in sorted(dbtree[:], key=lambda pt: pt['PatientID']):
128
+ for st in sorted(pt['studies'][:], key=lambda st: st['StudyInstanceUID']):
129
+ for sr in sorted(st['series'][:], key=lambda sr: sr['SeriesNumber']):
130
+ for nr, relpath in list(sr['instances'].items()):
131
+ if relpath in relpaths:
132
+ del sr['instances'][nr]
133
+ if sr['instances'] == []:
134
+ st['series'].remove(sr)
135
+ if st['series'] == []:
136
+ pt['studies'].remove(st)
137
+ return dbtree
138
+
139
+
140
+
141
+ def uid(dbtree, entity): # uid from entity
142
+ if len(entity)==2:
143
+ return entity[1]
144
+ if len(entity)==3:
145
+ return study_uid(dbtree, entity)
146
+ if len(entity)==4:
147
+ return series_uid(dbtree, entity)
148
+
149
+
150
+ def study_uid(dbtree, study):
151
+ patient_id, study = study[1], study[2]
152
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
153
+ if pt['PatientID'] == patient_id:
154
+
155
+ uid_studies = {}
156
+ study_idx = {}
157
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
158
+ study_desc = st['StudyDescription']
159
+ uid_study = st['StudyInstanceUID']
160
+ if study_desc in study_idx:
161
+ study_idx[study_desc] += 1
162
+ else:
163
+ study_idx[study_desc] = 0
164
+ study_desc = (study_desc, study_idx[study_desc])
165
+ if study == study_desc:
166
+ return uid_study
167
+ uid_studies[study_desc] = uid_study
168
+
169
+ if isinstance(study, str):
170
+ studies_list = [s for s in uid_studies.keys() if s[0]==study]
171
+ if len(studies_list) == 1:
172
+ return uid_studies[(study, 0)]
173
+ elif len(studies_list) > 1:
174
+ raise AmbiguousError(
175
+ f"Multiple studies with name {study}. "
176
+ f"Please specify the index along with the description. "
177
+ f"For instance ({study}, {len(uid_studies)-1})'. "
178
+ )
179
+ raise ValueError(f"Study {study} not found in patient {patient_id}.")
180
+
181
+
182
+ def series_uid(dbtree, series): # absolute path to series
183
+ uid_study = study_uid(dbtree, series[:-1])
184
+ study, sery = series[2], series[3]
185
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
186
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
187
+ if st['StudyInstanceUID'] == uid_study:
188
+
189
+ series = {}
190
+ series_idx = {}
191
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
192
+ series_desc = sr['SeriesDescription']
193
+ uid_series = sr['SeriesInstanceUID']
194
+ if series_desc in series_idx:
195
+ series_idx[series_desc] += 1
196
+ else:
197
+ series_idx[series_desc] = 0
198
+ series_desc = (series_desc, series_idx[series_desc])
199
+ if sery == series_desc:
200
+ return uid_series
201
+ series[series_desc] = uid_series
202
+
203
+ if isinstance(sery, str):
204
+ series_list = [s for s in series.keys() if s[0]==sery]
205
+ if len(series_list) == 1:
206
+ return series[(sery, 0)]
207
+ elif len(series_list) > 1:
208
+ raise AmbiguousError(
209
+ f"Multiple series with name {sery}. "
210
+ f"Please specify the index along with the description. "
211
+ f"For instance ({sery}, {len(series)-1})'. "
212
+ )
213
+ raise ValueError(f"Series {sery} not found in study {study}.")
214
+
215
+
216
+ def patients(dbtree, database, name=None, contains=None, isin=None):
217
+
218
+ patients = []
219
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
220
+ patient_name = pt['PatientName']
221
+ append = True
222
+ if name is not None:
223
+ append = append and (patient_name==name)
224
+ if contains is not None:
225
+ append = append and (contains in patient_name)
226
+ if isin is not None:
227
+ append = append and (patient_name in isin)
228
+ if append:
229
+ patients.append(pt['PatientID'])
230
+
231
+ return [[database, p] for p in patients]
232
+
233
+
234
+ def studies(dbtree, pat, desc=None, contains=None, isin=None):
235
+ database, patient_id = pat[0], pat[1]
236
+ studies = []
237
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
238
+ if pt['PatientID'] == patient_id:
239
+ study_idx = {}
240
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
241
+ study_desc = st['StudyDescription']
242
+ if study_desc in study_idx:
243
+ study_idx[study_desc] += 1
244
+ else:
245
+ study_idx[study_desc] = 0
246
+ studies.append((study_desc, study_idx[study_desc]))
247
+
248
+ # Apply filters
249
+ if desc is not None:
250
+ studies = [s for s in studies if s[0]==desc]
251
+ if contains is not None:
252
+ studies = [s for s in studies if contains in s[0]]
253
+ if isin is not None:
254
+ studies = [s for s in studies if s[0] in isin]
255
+
256
+ # Return result
257
+ return [[database, patient_id, study] for study in studies]
258
+
259
+
260
+
261
+ def series(dbtree, stdy, desc=None, contains=None, isin=None):
262
+ database, patient_id, study = stdy[0], stdy[1], stdy[2]
263
+ study_as_str = isinstance(study, str)
264
+ if study_as_str:
265
+ study = (study, 0)
266
+ series = []
267
+ for pt in sorted(dbtree, key=lambda pt: pt['PatientID']):
268
+ if pt['PatientID'] == patient_id:
269
+ study_idx = {}
270
+ for st in sorted(pt['studies'], key=lambda st: st['StudyInstanceUID']):
271
+ study_desc = st['StudyDescription']
272
+ if study_desc in study_idx:
273
+ study_idx[study_desc] += 1
274
+ else:
275
+ study_idx[study_desc] = 0
276
+ if study[0] == study_desc:
277
+ if study_as_str:
278
+ if study_idx[study_desc] > 0:
279
+ raise AmbiguousError(
280
+ f"Multiple studies named {study_desc} in patient {patient_id}. Please provide an index along with the study description."
281
+ )
282
+ if study == (study_desc, study_idx[study_desc]):
283
+ series_idx = {}
284
+ for sr in sorted(st['series'], key=lambda sr: sr['SeriesNumber']):
285
+ series_desc = sr['SeriesDescription']
286
+ if series_desc in series_idx:
287
+ series_idx[series_desc] += 1
288
+ else:
289
+ series_idx[series_desc] = 0
290
+ series.append((series_desc, series_idx[series_desc]))
291
+ if not study_as_str:
292
+ break
293
+
294
+ # Apply filters (if any)
295
+ if desc is not None:
296
+ series = [s for s in series if s[0]==desc]
297
+ if contains is not None:
298
+ series = [s for s in series if contains in s[0]]
299
+ if isin is not None:
300
+ series = [s for s in series if s[0] in isin]
301
+
302
+ # Return result
303
+ return [[database, patient_id, study, s] for s in series]
304
+
305
+
306
+
307
+ # def append(dbtree, parent, child_name):
308
+ # if len(parent) == 1:
309
+ # return _new_patient(dbtree, parent, child_name)
310
+ # elif len(parent) == 2:
311
+ # return _new_study(dbtree, parent, child_name)
312
+ # elif len(parent) == 3:
313
+ # return _new_series(dbtree, parent, child_name)
314
+
315
+ # def _new_patient(dbtree, database, patient_id):
316
+ # if patient_id in patients(dbtree, database):
317
+ # raise ValueError(
318
+ # f"Cannot create a new patient with id {patient_id}."
319
+ # f"The ID is already taken."
320
+ # )
321
+ # return [database, patient_id]
322
+
323
+ # def new_study(dbtree, patient, study): #len(patient)=2
324
+ # desc = study if isinstance(study, str) else study[0]
325
+ # studies_in_patient = studies(dbtree, patient, desc=desc)
326
+ # cnt = len(studies_in_patient)
327
+ # return patient + [(desc, cnt)]
328
+
329
+ # def new_series(dbtree, study, sery): #len(study)=3
330
+ # desc = sery if isinstance(sery, str) else sery[0]
331
+ # series_in_study = series(dbtree, study, desc=desc)
332
+ # cnt = len(series_in_study)
333
+ # return study + [(desc, cnt)]
334
+
335
+
336
+
337
+ def print_tree(dbtree):
338
+ tree = summary(dbtree)
339
+ for patient, studies in tree.items():
340
+ print(f"Patient: ({patient[0]}, {patient[1]})")
341
+ for study, series in studies.items():
342
+ print(f" Study: ({study[0]}, {study[1]})")
343
+ for s in series:
344
+ print(f" Series: ({s[0]}, {s[1]})")
345
+
346
+
347
+ def summary(dbtree):
348
+ # A human-readable summary tree
349
+
350
+ summary = {}
351
+
352
+ for patient in sorted(dbtree, key=lambda pt: pt['PatientID']):
353
+ pat_id, pat_name = patient['PatientID'], patient['PatientName']
354
+ summary[pat_id, pat_name] = {}
355
+
356
+ study_idx = {}
357
+ for study in sorted(patient['studies'], key=lambda st: st['StudyInstanceUID']):
358
+ study_desc = study['StudyDescription']
359
+ if study_desc in study_idx:
360
+ study_idx[study_desc] += 1
361
+ else:
362
+ study_idx[study_desc] = 0
363
+ summary[pat_id, pat_name][study_desc, study_idx[study_desc]] = []
364
+
365
+ series_idx = {}
366
+ for series in sorted(study['series'], key=lambda sr: sr['SeriesNumber']):
367
+ series_desc = series['SeriesDescription']
368
+ if series_desc in series_idx:
369
+ series_idx[series_desc] += 1
370
+ else:
371
+ series_idx[series_desc] = 0
372
+ summary[pat_id, pat_name][study_desc, study_idx[study_desc]].append((series_desc, series_idx[series_desc]))
373
+
374
+ return summary
375
+
376
+
377
+ def to_csv(dbtree, csv_file):
378
+
379
+ columns = ['PatientID', 'PatientName', 'StudyDescription', 'study index', 'SeriesDescription', 'SeriesNumber', 'nr of files']
380
+
381
+ with open(csv_file, 'w', newline='') as file:
382
+ writer = csv.writer(file)
383
+ writer.writerow(columns)
384
+
385
+ for patient in sorted(dbtree, key=lambda pt: pt['PatientID']):
386
+ pat_id, pat_name = patient['PatientID'], patient['PatientName']
387
+
388
+ study_idx = {}
389
+ for study in sorted(patient['studies'], key=lambda st: st['StudyInstanceUID']):
390
+ study_desc = study['StudyDescription']
391
+ if study_desc in study_idx:
392
+ study_idx[study_desc] += 1
393
+ else:
394
+ study_idx[study_desc] = 0
395
+
396
+ for series in sorted(study['series'], key=lambda sr: sr['SeriesNumber']):
397
+ n_instances = len(series['instances'])
398
+ row = [pat_id, pat_name, study_desc, study_idx[study_desc], series['SeriesDescription'], series['SeriesNumber'], n_instances]
399
+ writer.writerow(row)
400
+
401
+
402
+
@@ -2,25 +2,11 @@
2
2
  # Produced by pydicom codify utility script
3
3
  import numpy as np
4
4
  import pydicom
5
- from pydicom.dataset import Dataset, FileMetaDataset
5
+ from pydicom.dataset import FileMetaDataset
6
6
  from pydicom.sequence import Sequence
7
7
 
8
- from dbdicom.ds.dataset import DbDataset
9
8
 
10
- class CTImage(DbDataset):
11
- def __init__(self, dataset=None, template=None):
12
- super().__init__()
13
-
14
- if (dataset is None) and (template is None):
15
- template = 'VPH'
16
-
17
- if dataset is not None:
18
- self.__dict__ = dataset.__dict__
19
-
20
- if template == 'VPH':
21
- vph(self)
22
-
23
- def vph(ds):
9
+ def default(ds): #VPH
24
10
 
25
11
  # File meta info data elements
26
12
  ds.file_meta = FileMetaDataset()