User guide

The client can be used with any DICOMweb server, such as dcm4che, orthanc or DICOMcloud.

Application Programming Interface (API)

Interacting with a remote DICOMweb server

To interact with a publicly accessible server, you only need to provide the url for the server address.

from dicomweb_client.api import DICOMwebClient

client = DICOMwebClient(url="https://mydicomwebserver.com")

Some servers expose the different DICOMweb RESTful services using different path prefixes. For example, the publicly accessible DICOMcloud server uses the prefixes "qidors", "wadors", and "stowrs" for QIDO-RS, WADO-RS, and STOW-RS, respectively. You can specify these prefixes using qido_url_prefix, wado_url_prefix, and stow_url_prefix.

from dicomweb_client.api import DICOMwebClient

client = DICOMwebClient(
    url="https://dicomcloud.azurewebsites.net",
    qido_url_prefix="qidors",
    wado_url_prefix="wadors",
    stow_url_prefix="stowrs"
)

Authentication and authorization

To interact with servers requiring authentication, DICOMwebClient accepts arbitrary authentication handlers derived from requests.auth.AuthBase (see here for details).

from requests.auth import HTTPBasicAuth
from dicomweb_client.api import DICOMwebClient
from dicomweb_client.session_utils import create_session_from_auth

auth = HTTPBasicAuth('myusername', 'mypassword')
session = create_session_from_auth(auth)

client = DICOMwebClient(
    url="https://mydicomwebserver.com",
    session=session
)

To simplify usage for basic HTTP authentication, you may also directly provide a username and password using the corresponding arguments.

from dicomweb_client.api import DICOMwebClient
from dicomweb_client.session_utils import create_session_from_user_pass

session = create_session_from_user_pass(
    username='myusername',
    password='mypassword'
)

client = DICOMwebClient(
    url="https://mydicomwebserver.com",
    session=session
)

To interact with servers supporting token-based authorization, you can provide the access token using the headers argument (the header will be included in every client request message).

from dicomweb_client.api import DICOMwebClient

access_token = "mytoken"
client = DICOMwebClient(
    url="https://mydicomwebserver.com",
    headers={"Authorization": "Bearer {}".format(access_token)}
)

To interact with servers requiring certificate-based authentication, you can provide the CA bundle and client certificate using the ca_bundle and cert arguments, respectively.

from dicomweb_client.api import DICOMwebClient
from dicomweb_client.session_utils import (
    create_session,
    add_certs_to_session
)

session = create_session()
session = add_certs_to_session(
    session=session,
    ca_bundle="/path/to/ca.crt",
    cert="/path/to/cert.pem"
)

client = DICOMwebClient(url="https://mydicomwebserver.com")

To interact with a server of the Google Healthcare API requiring OpenID Connect based authentication and authorization, provide a session authenticated using the Google Cloud Platform (GCP) credentials. See GCP documentation for details.

The library provides the gcp extension, which facilitates interacting with the DICOMweb interface of the Google Healthcare API. Note that the gcp extension is optional and requires installation of the package distribution with the gcp extra requirements: $ pip install dicomweb-client[gcp].

from dicomweb_client.api import DICOMwebClient
from dicomweb_client.ext.gcp.session_utils import create_session_from_gcp_credentials
from dicomweb_client.ext.gcp.uri import GoogleCloudHealthcareURL

session = create_session_from_gcp_credentials()

url = GoogleCloudHealthcareURL(
    project_id='my-project',
    location='us-east4',
    dataset_id='my-dataset',
    dicom_store_id='my-store'
)

client = DICOMwebClient(
    url=str(url),
    session=session
)

Accessing local DICOM Part10 files

The package provides the dicomweb_client.api.DICOMfileClient class for accessing data stored as DICOM Part10 files on a file system. The class exposes the same dicomweb_client.api.DICOMClient interface as the dicomweb_client.api.DICOMwebClient and can be used as a drop-in replacement.

To create a dicomweb_client.api.DICOMfileClient instance, you should pass the location of the desired data store on the file system. Note that the file:// scheme designator is required.

from dicomweb_client.api import DICOMfileClient

client = DICOMfileClient("file:///path/to/directory")

STOW-RS StoreInstances

Store a single dataset obtained from a PS3.10 file:

import pydicom

filename = "/path/to/file.dcm"
dataset = pydicom.dcmread(filename)

client.store_instances(datasets=[dataset])

QIDO-RS SeachForStudies

Search for all studies (up to server-defined maximum set per call - see below to iteratively get all studies):

studies = client.search_for_studies()

Search for studies filtering by PatientID:

studies = client.search_for_studies(search_filters={'PatientID': 'ABC123'})

Note that attributes can be specified in search_filters using either the keyword or the tag:

studies = client.search_for_studies(search_filters={'00100020': 'ABC123'})

Search for all studies but limit the number of returned results using the limit parameter.

studies_subset = client.search_for_studies(limit=100)

A server may also automatically limit the number of results that it returns per search request. In this case, the method can be called repeatedly to request remaining results using the offset parameter.

studies = []
offset = 0
while True:
    subset = client.search_for_studies(offset=offset)
    if len(subset) == 0:
        break
    studies.extend(subset)
    offset += len(subset)

The same can be achieved more conveniently using the get_remaining parameter.

studies = client.search_for_studies(get_remaining=True)

QIDO-RS SeachForSeries

Search for all series:

series = client.search_for_series()

Search for series of a given study:

series = client.search_for_series('1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639')

Search for series filtering by AccessionNumber:

series = client.search_for_series(search_filters={'AccessionNumber': '123456'})

Search for series filtering by AccessionNumber (using wildcard ? to match a range of numbers):

series = client.search_for_series(search_filters={'AccessionNumber': '12345?'})

Search for series filtering by SeriesDescription:

series = client.search_for_series(search_filters={'SeriesDescription': 'T2 AXIAL'})

Search for series filtering by SeriesDescription (using wildcard * to match a range of descriptions):

series = client.search_for_series(search_filters={'SeriesDescription': 'T2 AX*'})

Search for series filtering by Modality:

series = client.search_for_series(search_filters={'Modality': 'SM'})

QIDO-RS SeachForInstances

Search for all instances:

instances = client.search_for_instances()

Search for instances of a given study and series:

instances = client.search_for_instances(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
)

Search for instances filtering by SOPClassUID:

instances = client.search_for_instances(search_filters={'SOPClassUID': '1.2.840.10008.5.1.4.1.1.2'})

WADO-RS RetrieveStudy

Retrieve instances of a given study:

instances = client.retrieve_study('1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639')

WADO-RS RetrieveSeries

Retrieve instances of a given series:

instances = client.retrieve_series(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
)

Retrieve full instances of a given series using specific JPEG 2000 transfer syntax for encoding of bulk data:

instance = client.retrieve_instance(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    media_types=(('application/dicom', '1.2.840.10008.1.2.4.90', ), )
)

Retrieve bulk data of instances of a given series using specific JPEG 2000 transfer syntax:

instance = client.retrieve_instance(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    media_types=(('image/jp2', '1.2.840.10008.1.2.4.90', ), )
)

WADO-RS RetrieveInstance

Retrieve full instance using default Explicit VR Little Endian transfer syntax for encoding of bulk data:

instance = client.retrieve_instance(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534'
)

Retrieve full instance using specific JPEG 2000 transfer syntax for encoding of bulk data:

instance = client.retrieve_instance(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    media_types=(('application/dicom', '1.2.840.10008.1.2.4.90', ), )
)

Retrieve bulk data of instance using specific JPEG 2000 transfer syntax:

instance = client.retrieve_instance(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    media_types=(('image/jp2', '1.2.840.10008.1.2.4.90', ), )
)

WADO-RS RetrieveMetadata

Retrieve metadata for instances of a given study:

metadata = client.retrieve_study_metadata('1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639')

Retrieve metadata for instances of a given series:

metadata = client.retrieve_series_metadata(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034'
)

Retrieve metadata for a particular instance:

metadata = client.retrieve_instance_metadata(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534'
)

Note

WADO-RS RetrieveMetadata always returns metadata at the instance-level, retrieve_study_metadata() and retrieve_series_metadata() return an array of metadata items for each instance belonging to a given study and series, respectively.

WADO-RS RetrieveFrames

Retrieve a set of frames with default transfer syntax (“application/octet-stream”):

frames = client.retrieve_instance_frames(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1, 2]
)

Retrieve a set of frames of a given instances as JPEG compressed image:

frames = client.retrieve_instance_frames(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1, 2],
    media_types=('image/jpeg', )
)

Retrieve a set of frames of a given instances as compressed image in any available format:

frames = client.retrieve_instance_frames(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1, 2],
    media_types=('image/*', )
)

Retrieve a set of frames of a given instances as either JPEG 2000 or JPEG-LS compressed image:

frames = client.retrieve_instance_frames(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1, 2],
    media_types=('image/jp2', 'image/jls', )
)

Retrieve a set of frames of a given instances as either JPEG, JPEG 2000 or JPEG-LS lossless compressed image using specific transfer syntaxes:

frames = client.retrieve_instance_frames(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1, 2],
    media_types=(
        ('image/jpeg', '1.2.840.10008.1.2.4.57', ),
        ('image/jp2', '1.2.840.10008.1.2.4.90', ),
        ('image/jls', '1.2.840.10008.1.2.4.80', ),
    )
)

WADO-RS RetrieveBulkdata

Retrieve bulk data given a URL:

data = client.retrieve_bulkdata('https://mydicomwebserver.com/studies/...')

WADO-RS RetrieveRenderedTransaction

Retrieve a single-frame image instance rendered as a PNG compressed image:

frames = client.retrieve_instance_rendered(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    media_types=('image/png', )
)

Retrieve a single frame of a multi-frame image instance rendered as a high-quality JPEG compressed image that includes an ICC profile:

frames = client.retrieve_instance_frames_rendered(
    study_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639',
    series_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034',
    sop_instance_uid='1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534',
    frame_numbers=[1],
    media_types=('image/jpeg', ),
    params={'quality': 95, 'iccprofile': 'yes'}
)

When frames are retrieved in image format, they can be converted into a NumPy array using the PIL module:

from io import BytesIO

import numpy as np
from PIL import Image

image = Image.open(BytesIO(frames[0]))
array = np.array(image)

Warning

Retrieving images using lossy compression methods may lead to image recompression artifacts if the images have been stored lossy compressed.

Loading JSON Data To pydicom

Load metadata from JSON format into a pydicom.dataset.Dataset object. A common use for this is translating metadata received from a RetrieveMetadata or a SearchFor-style request:

from pydicom.dataset import Dataset

metadata = client.retrieve_study_metadata('1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639')
metadata_datasets = [Dataset.from_json(ds) for ds in metadata]

Note that the metadata may include references to BulkData elements. By default, BulkData elements will not be handled and the values not be automatically retrieved. To handle BulkData elements and retrieve their values, one has to provide a bulk_data_uri_handler callable to the pydicom.dataset.Dataset.from_json() method.

Command Line Interface (CLI)

Search for studies:

dicomweb_client --url https://dicomcloud.azurewebsites.net/qidors search studies

Retrieve metadata for all instances of a given study:

dicomweb_client --url https://dicomcloud.azurewebsites.net/wadors \
    retrieve studies \
    --study 1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639 \
    metadata

The output can be dicomized for human interpretation:

dicomweb_client --url https://dicomcloud.azurewebsites.net/wadors \
    retrieve studies \
    --study 1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639 \
    metadata \
    --dicomize

Retrieve the full Part 3.10 files for all instances of a given study:

dicomweb_client --url https://dicomcloud.azurewebsites.net/wadors \
    retrieve studies \
    --study 1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639 \
    full

Retrieve a single frame of a given instances as JPEG compressed image:

dicomweb_client --url https://dicomcloud.azurewebsites.net/wadors \
    retrieve instances \
    --study 1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639 \
    --series 1.2.826.0.1.3680043.8.1055.1.20111103111208937.49685336.24517034 \
    --instance 1.2.826.0.1.3680043.8.1055.1.20111103111208937.40440871.13152534 \
    frames \
    --numbers 1 \
    --media-type image/jpeg

Store instances to a Google DICOMweb store:

dicomweb_client --url https://healthcare.googleapis.com/v1beta1/projects/MYPROJECT/locations/us-central1/datasets/MYDATASET/dicomStores/MYDICOMSTORE/dicomWeb \
    --token $(gcloud auth print-access-token) \
    store instances \
    dicomfiles/*