Reputation: 21
I've been down a couple of rabbit holes trying to find suitable ways of creating a DICOM modality worklist (or .wl worklist files rather).
What I have setup so far:
My problem is with the creation of the DICOM text dump files.
I'm currently using Python's String.format()
function to format a template string. This then substitutes certain placeholders in my template string with actual patient data. Although not elegant, it works. But it's a very static solution and may not be very robust.
Is there a Python library that can be used to generate such text dump files? or even beter, the .wl files? I am willing to trade 3 magic beans, and our family recipe for potato salad, for such a library. (The secret ingredient is not paprika)
For completeness, here is how the template dicom worklist string looks:
dicom_wl_template_string = """
# Dicom-File-Format
# Dicom-Meta-Information-Header
# Used TransferSyntax: Unknown Transfer Syntax
# Dicom-Data-Set
# Used TransferSyntax: Little Endian Implicit
(0002,0000) UL [123]
(0002,0002) UI [1.2.111.222222.5.1.4.1.1.104.1]
(0002,0003) UI [1.2.3.4.5.6.132437.17.4.10123450.312346792082.12349.1]
(0002,0010) UI [1.2.840.10008.1.2.1]
(0002,0012) UI [1.2.276.0.7230010.3.0.3.6.6]
(0002,0013) SH [OFFIS_DCMTK_366]
(0008,0005) CS [{SpecificCharacterSet}] # 10, 1 SpecificCharacterSet e.g ISO_IR 100
(0008,0012) DA [{InstanceCreationDate}] # 8, 1 InstanceCreationDate e.g 20220101
(0008,0050) SH [{AccessionNumber}] # 8, 1 AccessionNumber e.g 1234
(0010,0010) PN [{PatientName}] # 14, 1 PatientName e.g SURNAME^ABC
(0010,0020) LO [{PatientID}] # 14, 1 PatientID e.g 7001011234080
(0010,0030) DA [{PatientBirthDate}] # 8, 1 PatientBirthDate e.g. 19700101
(0010,0040) CS [{PatientSex}] # 2, 1 PatientSex e.g. M
(0020,000d) UI [{StudyInstanceUID}] # 54, 1 StudyInstanceUID e.g 1.2.3.4.5.6.132437.17.4.10123450.312346792082.12349.1
(0032,1060) LO [{RequestedProcedureDescription}] # 16, 1 RequestedProcedureDescription
(0040,0100) SQ (Sequence with explicit length #=1) # 90, 1 ScheduledProcedureStepSequence
(fffe,e000) na (Item with ??explicit length #=5??) # 82, 1 Item
(0008,0060) CS [{Modality}] # 4, 1 Modality e.g. CT, MR, CR, NM, PT, US, XA
(0040,0001) AE [{ScheduledStationAETitle}] # 4, 1 ScheduledStationAETitle e.g Foo
(0040,0002) DA [{ScheduledProcedureStepStartDate}] # 8, 1 ScheduledProcedureStepStartDate e.g. 20220101
(0040,0003) TM [{ScheduledProcedureStepStartTime}] # 8, 1 ScheduledProcedureStepStartTime e.g. 080000
(0040,0006) PN [{ScheduledPhysicianName}] # 8, 1 Scheduled Performing Physicians Name e.g. EMMETBROWN
(0040,0007) LO [{ScheduledProcedureStepDescription}] # 22, 1 ScheduledProcedureStepDescription e.g SOMETHING
(0040,0009) SH [{ScheduledProcedureStepID}] # 4, 1 ScheduledProcedureStepID e.g 0001
(fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem
(0040,1001) SH [unknown] # 8, 1 RequestedProcedureID
"""
Upvotes: 2
Views: 2215
Reputation: 21
Thank you for the response. Here is also some example code for future visitors.
import os
from os import path
from pydicom.dataset import Dataset, FileMetaDataset
from pydicom.uid import ExplicitVRLittleEndian
wl_file_name = "directory/file.wl"
txt_file_name = "directory/file.txt"
# Create data set
ds = Dataset()
# Add file meta information elements
ds.file_meta = FileMetaDataset()
ds.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
ds.file_meta.MediaStorageSOPClassUID = "0"
ds.file_meta.MediaStorageSOPInstanceUID = "0"
# Fill out the worklist query elements
ds.SpecificCharacterSet = "ISO_IR 6"
ds.InstanceCreationDate = "20220101"
ds.AccessionNumber = "12345-abc"
ds.PatientName = "SURNAME^NAME"
ds.PatientID = "123456"
ds.PatientBirthDate = "19700101"
ds.PatientSex = "M"
ds.StudyInstanceUID = "1a-2b-3c"
ds.RequestedProcedureDescription = "ProcedureDescription"
ds.ScheduledProcedureStepSequence = [Dataset()]
ds.ScheduledProcedureStepSequence[0].Modality = "OT"
ds.ScheduledProcedureStepSequence[0].ScheduledStationAETitle = "OT"
ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20220101"
ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime = "080000"
ds.ScheduledProcedureStepSequence[0].ScheduledPerformingPhysicianName = "Doctor Emmet Brown"
ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepDescription = "SchedProcStepDesc"
ds.ScheduledProcedureStepID = "0001"
# more stuff if you need
# Save directly as a .wl file.
# Set write_like_original=False to be certain you’re writing the dataset in the DICOM File Format
ds.save_as(wl_file_name, write_like_original=False)
# Additionally, you can also make a readable txt file for humans
# Check if txt file already exists
if(path.exists(txt_file_name)): #if txt file exists, remove it first
try:
os.remove(txt_file_name)
except OSError as e:
print("Error: %s : %s" % (txt_file_name, e.strerror))
# Run dcmdump command to convert wl file to txt
convert_wl_to_txt_cmd = "dcmdump " + wl_file_name + " > " + txt_file_name
os.system(convert_wl_to_txt_cmd)
The txt version then looks like this:
# Dicom-File-Format
# Dicom-Meta-Information-Header
# Used TransferSyntax: Little Endian Explicit
(0002,0000) UL 120 # 4, 1 FileMetaInformationGroupLength
(0002,0001) OB 00\01 # 2, 1 FileMetaInformationVersion
(0002,0002) UI [0] # 2, 1 MediaStorageSOPClassUID
(0002,0003) UI [0] # 2, 1 MediaStorageSOPInstanceUID
(0002,0010) UI =LittleEndianExplicit # 20, 1 TransferSyntaxUID
(0002,0012) UI [1.2.826.0.1.3680043.8.498.1] # 28, 1 ImplementationClassUID
(0002,0013) SH [PYDICOM 2.2.2] # 14, 1 ImplementationVersionName
# Dicom-Data-Set
# Used TransferSyntax: Little Endian Explicit
(0008,0005) CS [ISO_IR 6] # 8, 1 SpecificCharacterSet
(0008,0012) DA [20220101] # 8, 1 InstanceCreationDate
(0008,0050) SH [12345-abc] # 10, 1 AccessionNumber
(0010,0010) PN [SURNAME^NAME] # 12, 1 PatientName
(0010,0020) LO [123456] # 6, 1 PatientID
(0010,0030) DA [19700101] # 8, 1 PatientBirthDate
(0010,0040) CS [M] # 2, 1 PatientSex
(0020,000d) UI [1a-2b-3c] # 8, 1 StudyInstanceUID
(0032,1060) LO [ProcedureDescription] # 20, 1 RequestedProcedureDescription
(0040,0009) SH [0001] # 4, 1 ScheduledProcedureStepID
(0040,0100) SQ (Sequence with explicit length #=1) # 110, 1 ScheduledProcedureStepSequence
(fffe,e000) na (Item with explicit length #=6) # 102, 1 Item
(0008,0060) CS [OT] # 2, 1 Modality
(0040,0001) AE [OT] # 2, 1 ScheduledStationAETitle
(0040,0002) DA [20220101] # 8, 1 ScheduledProcedureStepStartDate
(0040,0003) TM [080000] # 6, 1 ScheduledProcedureStepStartTime
(0040,0006) PN [Doctor Emmet Brown] # 18, 1 ScheduledPerformingPhysicianName
(0040,0007) LO [SchedProcStepDesc] # 18, 1 ScheduledProcedureStepDescription
(fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem
Upvotes: 0
Reputation: 1300
pydicom should be able to do this and probably allow you to skip the text dump step (disclaimer - I'm a contributor to pydicom):
from pydicom.dataset import Dataset, FileMetaDataset
from pydicom.uid import ExplicitVRLittleEndian
ds = Dataset()
# Add file meta information elements
ds.file_meta = FileMetaDataset()
ds.file_meta.TransferSyntaxUID = ExplicitVRLittleEndian
# Fill out the worklist query elements
ds.SpecificCharacterSet = "ISO_IR 6"
ds.ScheduledProcedureStepSequence = [Dataset()]
ds.ScheduledProcedureStepSequence[0].Modality = "CT"
# etc...
ds.save_as("query.wl", write_like_original=False)
If you decide to go this way, the dataset introduction tutorial is a good place to start.
Upvotes: 0