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"))
Trolley search¶
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')
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))
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.