pydicom / pynetdicom

A Python implementation of the DICOM networking protocol
https://pydicom.github.io/pynetdicom
MIT License
500 stars 176 forks source link

C-STORE SCP Unable to retrieve Video Endoscopic Image Storage SOP #915

Closed javitab closed 7 months ago

javitab commented 7 months ago

Describe the bug I am trying to retrieve Video Endoscopic Image Storage instances and while negotiations are occurring between our VNA and my pynetdicom C-STORE SCP the association is being aborted. This is seemingly due to important transfer syntaxes being rejected by pynetdicom.

Relevant portion of incoming request:

2024-02-02T14:44:46.620576616Z D:   Context ID:        147 (Proposed)
2024-02-02T14:44:46.620621117Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620630113Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620661887Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620740378Z D:       =MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1
2024-02-02T14:44:46.620746258Z D:   Context ID:        149 (Proposed)
2024-02-02T14:44:46.620748678Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620764771Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620800713Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620804980Z D:       =Implicit VR Little Endian
2024-02-02T14:44:46.620806946Z D:   Context ID:        151 (Proposed)
2024-02-02T14:44:46.620843076Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620847702Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620871705Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620884590Z D:       =RLE Lossless
2024-02-02T14:44:46.620896180Z D:   Context ID:        153 (Proposed)
2024-02-02T14:44:46.620946815Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620954089Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621002237Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621006964Z D:       =MPEG-4 AVC/H.264 High Profile / Level 4.1
2024-02-02T14:44:46.621008889Z D:   Context ID:        155 (Proposed)
2024-02-02T14:44:46.621027067Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621056674Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621059490Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621122717Z D:       =MPEG2 Main Profile / High Level
2024-02-02T14:44:46.621126013Z D:   Context ID:        157 (Proposed)
2024-02-02T14:44:46.621182371Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621188625Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621190618Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621226467Z D:       =MPEG2 Main Profile / Main Level
2024-02-02T14:44:46.621230953Z D:   Context ID:        159 (Proposed)
2024-02-02T14:44:46.621259993Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621264903Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621289060Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621315863Z D:       =Explicit VR Little Endian

Response:

2024-02-02T14:44:46.620576616Z D:   Context ID:        147 (Proposed)
2024-02-02T14:44:46.620621117Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620630113Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620661887Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620740378Z D:       =MPEG-4 AVC/H.264 BD-compatible High Profile / Level 4.1
2024-02-02T14:44:46.620746258Z D:   Context ID:        149 (Proposed)
2024-02-02T14:44:46.620748678Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620764771Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620800713Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620804980Z D:       =Implicit VR Little Endian
2024-02-02T14:44:46.620806946Z D:   Context ID:        151 (Proposed)
2024-02-02T14:44:46.620843076Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620847702Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.620871705Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.620884590Z D:       =RLE Lossless
2024-02-02T14:44:46.620896180Z D:   Context ID:        153 (Proposed)
2024-02-02T14:44:46.620946815Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.620954089Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621002237Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621006964Z D:       =MPEG-4 AVC/H.264 High Profile / Level 4.1
2024-02-02T14:44:46.621008889Z D:   Context ID:        155 (Proposed)
2024-02-02T14:44:46.621027067Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621056674Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621059490Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621122717Z D:       =MPEG2 Main Profile / High Level
2024-02-02T14:44:46.621126013Z D:   Context ID:        157 (Proposed)
2024-02-02T14:44:46.621182371Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621188625Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621190618Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621226467Z D:       =MPEG2 Main Profile / Main Level
2024-02-02T14:44:46.621230953Z D:   Context ID:        159 (Proposed)
2024-02-02T14:44:46.621259993Z D:     Abstract Syntax: =Video Endoscopic Image Storage
2024-02-02T14:44:46.621264903Z D:     Proposed SCP/SCU Role: Default
2024-02-02T14:44:46.621289060Z D:     Proposed Transfer Syntax:
2024-02-02T14:44:46.621315863Z D:       =Explicit VR Little Endian

Expected behavior I would expect these transfer syntaxes not to be rejected as they all (seem to) appear in the ALL_TRANSFER_SYNTAXES global.

Steps To Reproduce A C-MOVE request is sent to the VNA for and images are then sent to the C-STORE SCP as implemented below.

def startStorageServer(LocalAE,StoragePath):

    # Print Variables
    print(f"Local AETitle:              {LocalAE}")
    print(f"Listening on Internal Port: 104")
    print(f"Listening on External Port: {cfg['dicom_tools']['local_node']['dicom_port']}")
    print(f"Storing DICOM data to:      {StoragePath}")

    # Implement a handler for evt.EVT_C_STORE
    def handle_store(event: evt):
        """Handle a C-STORE request event."""
        # Decode the C-STORE request's *Data Set* parameter to a pydicom Dataset
        ds = event.dataset

        # Add the File Meta Information
        # ds.file_meta = event.file_meta

        # Save the dataset using the SOP Instance UID as the filename
        os.makedirs(f"{StoragePath}/{ds.StudyInstanceUID}/{ds.SeriesInstanceUID}/", exist_ok=True)
        ds.save_as(f"{StoragePath}/{ds.StudyInstanceUID}/{ds.SeriesInstanceUID}/{ds.SOPInstanceUID}.dcm", write_like_original=False)

        # Return a 'Success' status
        return 0x0000

    handlers = [
        (evt.EVT_C_STORE, handle_store)
        ]

    # Initialise the Application Entity
    ae = AE()
    ae.ae_title=LocalAE

    # Support presentation contexts for all storage SOP Classes and add context for dicom echo.
    ae.supported_contexts = AllStoragePresentationContexts
    ae.add_supported_context('1.2.840.10008.1.1')
    ae.add_supported_context('1.2.840.10008.5.1.4.1.1.77.1.1.1')

    # Start listening for incoming association requests
    ae.start_server(address=('0.0.0.0', 104), evt_handlers=handlers)

Your environment Please run the following and paste the output.

$ python -c "import platform; print(platform.platform())"
$ python -c "import sys; print('Python ', sys.version)"
$ python -c "import pydicom; print('pydicom ', pydicom.__version__)"
$ python -c "import pynetdicom; print('pynetdicom ', pynetdicom.__version__)"

Output:

Linux-5.15.0-91-generic-x86_64-with-glibc2.35
Python  3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
pydicom  2.4.4
pynetdicom  2.0.2
javitab commented 7 months ago

Nevermind, I figured out my problem. I added the appropriate transfer syntaxes for endo and I was able to store the files:

ae.add_supported_context(abstract_syntax="1.2.840.10008.5.1.4.1.1.77.1.1.1",transfer_syntax="1.2.840.10008.1.2.4.102")