pythondicomorthanc-server

Is there a Python DICOM Modality Worklist setup library?


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
    """

Solution

  • 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