1
+ """
2
+ AHLItoDICOM Module : This class contains the logic to encapsulate the data and the pixels into a DICOM object.
3
+
4
+ SPDX-License-Identifier: Apache-2.0
5
+ """
6
+ from time import sleep
7
+ from multiprocessing import Process , Queue
8
+ import pydicom
9
+ import logging
10
+ from pydicom .sequence import Sequence
11
+ from pydicom import Dataset , DataElement
12
+ from pydicom .dataset import FileDataset , FileMetaDataset
13
+ from pydicom .uid import UID
14
+ import base64
15
+
16
+
17
+ class AHLIDataDICOMizer ():
18
+
19
+ ds = Dataset ()
20
+ InstanceId = None
21
+ thread_running = True
22
+ AHLI_metadata = None
23
+ process = None
24
+
25
+ def __init__ (self , InstanceId , AHLI_metadata ) -> None :
26
+ self .InstanceId = InstanceId
27
+ self .DICOMizeJobs = Queue ()
28
+ self .DICOMizeJobsCompleted = Queue ()
29
+ self .AHLI_metadata = AHLI_metadata
30
+ self .process = Process (target = self .ProcessJobs , args = (self .DICOMizeJobs , self .DICOMizeJobsCompleted , ))
31
+ self .process .start ()
32
+
33
+
34
+
35
+ def AddDICOMizeJob (self ,FetchJob ):
36
+ self .DICOMizeJobs .put (FetchJob )
37
+ logging .debug ("[AHLIFrameFetcher][AddFetchJob][" + self .InstanceId + "] - Fetch Job added " + str (FetchJob )+ "." )
38
+
39
+ def ProcessJobs (self , DICOMizeJobs , DICOMizeJobsCompleted ):
40
+ while (self .thread_running ):
41
+ if not DICOMizeJobs .empty ():
42
+ self .status = "busy"
43
+ try :
44
+ ImageFrame = DICOMizeJobs .get ()
45
+ vrlist = []
46
+ file_meta = FileMetaDataset ()
47
+ self .ds = FileDataset (None , {}, file_meta = file_meta , preamble = b"\0 " * 128 )
48
+ self .getDICOMVRs (self .AHLI_metadata ["Study" ]["Series" ][ImageFrame ["SeriesUID" ]]["Instances" ][ImageFrame ["SOPInstanceUID" ]]["DICOMVRs" ] , vrlist )
49
+ PatientLevel = self .AHLI_metadata ["Patient" ]["DICOM" ]
50
+ self .getTags (PatientLevel , self .ds , vrlist )
51
+ StudyLevel = self .AHLI_metadata ["Study" ]["DICOM" ]
52
+ self .getTags (StudyLevel , self .ds , vrlist )
53
+ SeriesLevel = self .AHLI_metadata ["Study" ]["Series" ][ImageFrame ["SeriesUID" ]]["DICOM" ]
54
+ self .getTags (SeriesLevel , self .ds , vrlist )
55
+ InstanceLevel = self .AHLI_metadata ["Study" ]["Series" ][ImageFrame ["SeriesUID" ]]["Instances" ][ImageFrame ["SOPInstanceUID" ]]["DICOM" ]
56
+ self .getTags (InstanceLevel , self .ds , vrlist )
57
+ self .ds .file_meta .TransferSyntaxUID = pydicom .uid .ExplicitVRLittleEndian
58
+ self .ds .is_little_endian = True
59
+ self .ds .is_implicit_VR = False
60
+ file_meta .MediaStorageSOPInstanceUID = UID (ImageFrame ["SOPInstanceUID" ])
61
+ pixels = ImageFrame ["PixelData" ]
62
+ if (pixels is not None ):
63
+ self .ds .PixelData = pixels .tobytes ()
64
+ vrlist .clear ()
65
+ DICOMizeJobsCompleted .put (self .ds )
66
+ except Exception as FetchError :
67
+ logging .error (f"[AHLIFrameFetcher][{ str (self .InstanceId )} ] - { FetchError } " )
68
+ else :
69
+ self .status = 'idle'
70
+ sleep (0.05 )
71
+
72
+ def getFramesDICOMized (self ):
73
+ if not self .DICOMizeJobsCompleted .empty ():
74
+ obj = self .DICOMizeJobsCompleted .get ()
75
+ return obj
76
+ else :
77
+ return None
78
+
79
+ def getDataset (self ):
80
+ return self .ds
81
+
82
+
83
+ def getDICOMVRs (self ,taglevel , vrlist ):
84
+ for theKey in taglevel :
85
+ vrlist .append ( [ theKey , taglevel [theKey ] ])
86
+ logging .debug (f"[AHLIDataDICOMizer][getDICOMVRs] - List of private tags VRs: { vrlist } \r \n " )
87
+
88
+
89
+
90
+ def getTags (self ,tagLevel , ds , vrlist ):
91
+ for theKey in tagLevel :
92
+ try :
93
+ try :
94
+ tagvr = pydicom .datadict .dictionary_VR (theKey )
95
+ except : #In case the vr is not in the pydicom dictionnary, it might be a private tag , listed in the vrlist
96
+ tagvr = None
97
+ for vr in vrlist :
98
+ if theKey == vr [0 ]:
99
+ tagvr = vr [1 ]
100
+ datavalue = tagLevel [theKey ]
101
+ #print(f"{theKey} : {datavalue}")
102
+ if (tagvr == 'SQ' ):
103
+ logging .debug (f"{ theKey } : { tagLevel [theKey ]} , { vrlist } " )
104
+ seqs = []
105
+ for underSeq in tagLevel [theKey ]:
106
+ seqds = Dataset ()
107
+ self .getTags (underSeq , seqds , vrlist )
108
+ seqs .append (seqds )
109
+ datavalue = Sequence (seqs )
110
+ continue
111
+ if (tagvr == 'US or SS' ):
112
+ datavalue = tagLevel [theKey ]
113
+ if (int (datavalue ) > 32767 ):
114
+ tagvr = 'US'
115
+ if ( tagvr in [ 'OB' , 'OD' , 'OF' , 'OL' , 'OW' , 'UN' ] ):
116
+ base64_str = tagLevel [theKey ]
117
+ base64_bytes = base64_str .encode ('utf-8' )
118
+ datavalue = base64 .decodebytes (base64_bytes )
119
+ if theKey == 'PrivateCreatorID' : # Ignore this attribute, otherwise it creates an issue because it doesn't resolve to a DICOM tag
120
+ continue
121
+ data_element = DataElement (theKey , tagvr , datavalue )
122
+ if data_element .tag .group != 2 :
123
+ try :
124
+ if (int (data_element .tag .group ) % 2 ) == 0 : # we are skipping all the private tags
125
+ ds .add (data_element )
126
+ except :
127
+ continue
128
+ except Exception as err :
129
+ logging .debug (f"[AHLIDataDICOMizer][getTags] - { err } " )
130
+ continue
131
+
132
+ def Dispose (self ):
133
+ self .thread_running = False
134
+ self .process .terminate ()
0 commit comments