Существует ли библиотека настройки рабочего списка модальности Python DICOM?

Я был в нескольких кроличьих норах , пытаясь найти подходящие способы создания рабочего списка модальности DICOM (или, скорее, файлов рабочего списка .wl).

Что я настроил на данный момент:

  • У меня есть сервер Orthanc DICOM, работающий в локальном док-контейнере.
  • Я могу создавать текстовые файлы дампа DICOM с помощью небольшой программы Python. Посмотрите пример того, как это выглядит ниже.
  • Я могу преобразовать вышеупомянутые текстовые файлы дампа в файлы рабочего списка .wl с помощью команды dump2dcm .
  • Я могу переместить созданные файлы .wl в общую папку с докером.
  • Orthanc может «видеть» эти файлы и правильно передавать их медицинским машинам в локальной сети.
  • У меня кофемашина на таймере. Это позволяет последовательно дозировать кофеин.

Моя проблема связана с созданием файлов текстового дампа DICOM. В настоящее время я использую Python String.format()функция для форматирования строки шаблона. Затем это заменяет определенные заполнители в моей строке шаблона фактическими данными пациента. Хотя это и не элегантно, но работает. Но это очень статичное решение и может быть не очень надежным.

Существует ли библиотека Python, которую можно использовать для создания таких файлов текстового дампа? или даже лучше, файлы .wl? Я готов обменять 3 волшебных боба и наш семейный рецепт картофельного салата на такую ​​библиотеку. (Секретный ингредиент не паприка)

Для полноты картины вот как выглядит строка рабочего списка шаблона dicom:

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

2 ответа

Спасибо за ответ. Вот также пример кода для будущих посетителей.

      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)

Версия txt выглядит следующим образом:

      # 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

pydicom должен быть в состоянии сделать это и, вероятно, позволить вам пропустить шаг текстового дампа (отказ от ответственности - я участник 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)

Если вы решите пойти по этому пути, руководство по вводу набора данных — хорошее место для начала.

Другие вопросы по тегам