Skip to content

Concepts

Explains the building blocks dicomtrolley in more detail. For quick examples see usage

Trolley

Allows you to query for DICOM objects and download DICOM images. Contains a Searcher and Downloader instance:

trolley = Trolley(searcher=Mint(a_session, "https://server/mint"),
                  downloader=WadoURI(a_session, "https://server/wado_uri"))

You query for DICOM objects by calling Trolley.find_studies() with a Query instance. This will send back one or more DICOMObjects.

studies = trolley.find_studies(Query(PatientName='B*'))

sequenceDiagram
  autonumber
  User->>Trolley: find_studies(Query)
  Trolley->>DICOM server: send query  
  DICOM server->>Trolley: response
  Trolley->>User: DICOMObjects

Trolley download

You download DICOM images by calling Trolley.download() with one or more DICOMdownloadable objects. This will write pydicom Datasets to disk.

trolley.download(StudyReference(study_uid='1.2'), '/tmp')
sequenceDiagram
  autonumber
  User->>Trolley: download()
  Trolley->>DICOM server: request data
  DICOM server->>Trolley: response
  Trolley->>User: writes Dataset

Trolley advantage

The Searcher and Downloader contained in a trolley can be used stand-alone. Using them together in a trolley has two advantages.

Integration

The first advantage is that search and download are integrated. Missing information for a download is queried for automatically. This means you can do this one-line download of a study 111 for example:

trolley = Trolley(downloader=WadoURI(requests.session(), "https://server/wado_uri"),
                  searcher=Mint(requests.session(), "https://server/mint"))

trolley.download(StudyReference(study_uid='111'), '/tmp')
Most downloaders, including WadoURI, must download each slice individually. A download command therefore should include a series and instance UIDs for each slice in study. Trolley takes care of that automatically. This is how the download command above is handled in trolley:
sequenceDiagram
  autonumber
  User->>Trolley: download(study)
  Trolley->>Downloader: get datasets (study ID)  
  Downloader->>Trolley: Exception! I need instance IDs  
  Trolley->>Searcher: find instance IDs (study ID)  
  Searcher->>Trolley: instance IDs
  Trolley->>Downloader: get datasets (instance IDs)
  Downloader->>DICOM server: request data 
  DICOM server->>Downloader: response
  Downloader->>Trolley: Datasets
  Trolley->>User: writes Datasets
Trolley will catch exceptions and query for missing information. Query results are cached to avoid unneeded queries.

Interchangeable backends

The second advantage is that search and download backends can be switched around with minimal effort:

# Two trollies with different backends
trolley = Trolley(searcher=DICOMQR("host","123","aet","aec"),
                  downloader=WadoURI(requests.session(), 
                                     "https://server/wado"))

# Switch to a different searcher. Trolley interface will not change
trolley.searcher = QidoRS(session=requests.session(), url="http://server/qido")

Query

An information request to a DICOM server is done using a Query object. For example

studies = trolley.find_studies(
    Query(PatientName='Bak*',                
          min_study_date=datetime(year=2015, month=3, day=1),
          max_study_date=datetime(year=2020, month=3, day=1),
          include_fields=['PatientBirthDate', 'SOPClassesInStudy'],
          query_level="INSTANCE"))

Note

String parameters (like PatientName='Bak*') can include asterisk wildcards. The implementation of this is up to the DICOM server you are talking to, however. Dicomtrolley will pass the wildcard the server as-is and not transform it in any way.

Query parameters

The following parameters can be set for a Query:

Query

key type required default
StudyInstanceUID str False
AccessionNumber str False
PatientName str False
PatientID str False
ModalitiesInStudy str False
SeriesInstanceUID str False
query_level QueryLevels False QueryLevels.STUDY
max_study_date typing.Optional[datetime.datetime] False None
min_study_date typing.Optional[datetime.datetime] False None
include_fields typing.Optional[typing.List[str]] False None

Most of these parameters have string values, possibly containing a * wildcard that will be matched as part of the query. More information on non-string parameters below:

query_level

Depth of the search. One of dicomtrolley.core.QueryLevels. Study, Series or Instance. Setting to instance will yield information on each slice in a series and make the query much slower.

include_fields

A list of valid DICOM field names to include in the query result. Examples of fields can be found in dicomtrolley.fields. The fields that can be included depend on query level. For instance, asking for an instance-level field like InstanceNumber makes no sense for a study-level query.

Note

Fields returned from a query are determined by the specific DICOM server you are talking to. Many servers will return a common subset of fields even without explicit 'include_fields' values. The DICOM server manual should describe which fields can be returned for which query level.

Query subtypes

The base Query object is acceptable to all Searchers. Some Searchers accept specialized query subtypes. For example MINT searcher can take a specialized MintQuery, which allows an additional limit parameter:

session = requests.Session()
trolley = Trolley(searcher=Mint(session, "https://server/mint"),
                  downloader=WadoURI(session, "https://server/wado"))
trolley.find_studies(MintQuery(PatientID='1234', limit=5))
See Searcher for all query subtypes

DICOMObject

DICOM distinguishes four hierarchical levels of organisation for images. Patient, Study, Series or Instance:

graph LR
  A[Patient] --> B[Study];
  A --> C[Study];
  B --> E[Series];
  B --> F[Series];
  E --> H[Instance];
  E --> I[Instance];

A patient has one or more studies. A study contains one or more Series. Each series contains one or more instances. As a first approximation, a study contains all data of a single scanning session, a series contains all data for a single pass through a scanner, and an instance represents a single image or slice.

DICOM objects are represented by the dicomtrolley.core.DICOMObject class. Trolley queries return dicomtrolley.core.Study instances which are DICOMObjects. A study can contain series, and instances:

studies = trolley.find_studies(Query(PatientName='B*',
                                     query_level=QueryLevels.INSTANCE))

studies                             # all studies
studies[0]                          # a single study
studies[0].series[0]                # a single series
studies[0].series[0].instances[:3]  # first 3 instances

Note

dicomtrolley models up to the Study object and does not model the Patient object directly

DICOMDownloadable

A reference to image data that can be downloaded by a trolley instance. There are two families of classes that implement DICOMDownloadable:

Firstly, You can download any DICOM object:

studies = trolley.find_studies(Query(PatientName='B*',
                                    query_level=QueryLevels.INSTANCE))

trolley.download(studies, "/tmp")                             # all studies
trolley.download(studies[0], "/tmp")                          # a single study
trolley.download(studies[0].series[0], "/tmp")                # a single series
trolley.download(studies[0].series[0].instances[:3], "/tmp")  # first 3 instances

Secondly, a dicomtrolley.core.DICOMObjectReference can be used without requiring a query first:

trolley.download(StudyReference(study_uid="1.1"), "/tmp")
trolley.download(SeriesReference(study_uid="1.1", 
                                 series_uid='2.2'), "/tmp")
trolley.download(InstanceReference(study_uid="1.1", 
                                   series_uid='2.2', 
                                   instance_uid='3.3'), "/tmp")

Searcher

Something that can search for DICOM studies. Accepts a query and returns a list of DICOM objects. The usage page lists several search system implementations.

Downloader

Something that can download DICOM images. Takes a DICOMDownloadable and returns pydicom Datasets. The usage page lists several download system implementations.