The client can be used with any DICOMweb server, such as dcm4che, orthanc or DICOMcloud.
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"
)
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
)
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")
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])
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)
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'})
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'})
Retrieve instances of a given study:
instances = client.retrieve_study('1.2.826.0.1.3680043.8.1055.1.20111103111148288.98361414.79379639')
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', ), )
)
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', ), )
)
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.
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', ),
)
)
Retrieve bulk data given a URL:
data = client.retrieve_bulkdata('https://mydicomwebserver.com/studies/...')
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.
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.
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/*