Relevant Patient Information Query Service Examples

The DICOM Relevant Patient Information Query Service provides a mechanism for an SCU to access relevant patient information managed by an SCP. This is accomplished through the DIMSE C-FIND service.

Relevant Patient Information SCU

Associate with a peer DICOM Application Entity and request information on a single patient with ID 1234567.

from pydicom.dataset import Dataset

from pynetdicom import AE, debug_logger
from pynetdicom.sop_class import GeneralRelevantPatientInformationQuery

debug_logger()

# Initialise the Application Entity
ae = AE()

# Add a requested presentation context
ae.add_requested_context(GeneralRelevantPatientInformationQuery)

# Create our Identifier (query) dataset
ds = Dataset()
ds.PatientName = ''
ds.PatientID = '1234567'
ds.ContentTemplateSequence = [Dataset()]
# Request the General Relevant Patient Information template (TID 9007)
# See DICOM Standard, Part 16, Annex A, TID 9000-9007
ds.ContentTemplateSequence[0].MappingResource = 'DCMR'
ds.ContentTemplateSequence[0].TemplateIdentifier = '9007'

# Associate with peer AE at IP 127.0.0.1 and port 11112
assoc = ae.associate("127.0.0.1", 11112)

if assoc.is_established:
    # Use the C-FIND service to send the identifier
    responses = assoc.send_c_find(ds, GeneralRelevantPatientInformationQuery)
    for (status, identifier) in responses:
        if status:
            print('C-FIND query status: 0x{0:04x}'.format(status.Status))
        else:
            print('Connection timed out, was aborted or received invalid response')

    # Release the association
    assoc.release()
else:
    print('Association rejected, aborted or never connected')

Relevant Patient Information SCP

The following represents a toy implementation of a Relevant Patient Information Query SCP where the SCU has sent the following Identifier dataset under the General Relevant Patient Information Model Query context. Its important to note that in the case of a successful match the response from the SCP includes an Identifier that meets the requirements of the requested template.

ds = Dataset()
ds.PatientName = ''
ds.PatientID = '1234567'
ds.ContentTemplateSequence = [Dataset()]
ds.ContentTemplateSequence[0].MappingResource = 'DCMR'
ds.ContentTemplateSequence[0].TemplateIdentifier = '9007'

This is a very bad way of managing stored SOP Instances, in reality its probably best to store the instance attributes in a database and run the query against that.

Check the handler implementation documentation to see the requirements for the evt.EVT_C_FIND handler.

import os

from pydicom import dcmread
from pydicom.dataset import Dataset

from pynetdicom import AE, evt
from pynetdicom.sop_class import GeneralRelevantPatientInformationQuery

# Implement the evt.EVT_C_FIND handler
def handle_find(event):
    """Handle a C-FIND service request"""
    ds = event.identifier

    # Import stored SOP Instances
    instances = []
    fdir = '/path/to/directory'
    for fpath in os.listdir(fdir):
       instances.append(dcmread(os.path.join(fdir, fpath)))

    # Not a good example of how to match
    matching = [
        inst for inst in instances if inst.PatientID == ds.PatientID
    ]

    # There must either be no match or 1 match, everything else
    #   is a failure
    if len(matching) == 1:
        # User-defined function to create the identifier based off a
        #   template, outside the scope of the current example
        identifier = create_template(matching[0], ds)
        yield (0xFF00, identifier)
    elif len(matching) > 1:
        # More than 1 match found
        yield (0xC100, None)

handlers = [(evt.EVT_C_FIND, handle_find)]

# Initialise the Application Entity and specify the listen port
ae = AE()

# Add the supported presentation context
ae.add_supported_context(GeneralRelevantPatientInformationQuery)

# Start listening for incoming association requests
ae.start_server(("127.0.0.1", 11112), evt_handlers=handlers)