import requests
import pydicom
from pathlib import Path
from urllib3.filepost import encode_multipart_formdata, choose_boundary
from azure.identity import DefaultAzureCredential
Accessing the DICOM service from the TRE
1 Accessing the DICOM service from the TRE
Note: DICOM data accessed through this service has been anonymised to some degree and will not mirror data from the original source.
- PII has been removed
- Dates have been moved
1.0.1 Set api URL and version
="https://hdspixldflowehrprod-dicom-pixld-flowehr-prod.dicom.azurehealthcareapis.com"
service_url="v1"
version= f"{service_url}/{version}"
base_url print(service_url)
1.0.2 Authenticate to Azure
Enter the provided code in a browser outside of the TRE VM
!az login --use-device-code
Ensure the correct subscription is set as the ‘default’ subscription. Please select the subscription name you would like to use for futher authentication against the DICOM service from the list of subscriptions returned by the previous cell.
Replace your-subscription-name
with the actual subscription name in the below cell and run the cell.
!az account set --subscription "your-subscription-name"
1.0.3 Generate bearer token via DefaultAzureCredential
from azure.identity import DefaultAzureCredential, AzureCliCredential
= DefaultAzureCredential()
credential = credential.credentials[3].get_token('https://dicom.healthcareapis.azure.com')
token = f'Bearer {token.token}' bearer_token
1.0.4 Optional - Alternative token generation with AzureCliCredential
Generates an equivalent token to the above cell, may be used if problems with DefaultAzureCredential
are encountered.
= AzureCliCredential()
credential = f"Bearer {credential.get_token('https://dicom.healthcareapis.azure.com').token}" bearer_token
1.1 Create a requests session
= requests.session() client
1.2 Verify authentication has performed correctly
= {"Authorization":bearer_token}
headers = f'{base_url}/changefeed'
url
= client.get(url,headers=headers)
response if (response.status_code != 200):
print('Error! Likely not authenticated!')
print(response.status_code)
1.3 Querying the DICOM Service
1.3.1 Search for studies
= f"{base_url}/studies"
url = {'Accept':'application/dicom+json', "Authorization":bearer_token}
headers = client.get(url, headers=headers)
response_query print(f"{response_query.status_code=}, {response_query.content=}")
Extract study IDs from response content - returned as bytes
StudyInstanceUID corresponds to 0020000D - see the DICOM documentation for details
import json
= json.loads(response_query.content.decode())
r = [study["0020000D"]["Value"][0] for study in r] study_uids
1.3.2 Search by study UID
= study_uids[0] # as an example, use the previous query
study_uid = f"{base_url}/studies"
url = {'Accept':'application/dicom+json', "Authorization":bearer_token}
headers = {'StudyInstanceUID':study_uid}
params = client.get(url, headers=headers, params=params)
response_query print(f"{response_query.status_code=}, {response_query.content=}")
Return series UIDs within a single study
= f'{base_url}/studies/{study_uids[0]}/series'
url = {'Accept':'application/dicom+json', "Authorization":bearer_token}
headers = client.get(url, headers=headers)
response print(f"{response.status_code=}, {response.content=}")
Extract series IDs from response content - returned as bytes
SeriesInstanceUID corresponds to 0020000E - see the DICOM documentation for details
= json.loads(response.content.decode())
r = [study["0020000E"]["Value"][0] for study in r] series_uids
Search within study by series UID
= series_uids[0]
series_uid = f'{base_url}/studies/{study_uid}/series'
url = {'Accept':'application/dicom+json', "Authorization":bearer_token}
headers = {'SeriesInstanceUID':series_uid}
params
= client.get(url, headers=headers, params=params) #, verify=False)
response print(f"{response.status_code=}, {response.content=}")
Search all studies by series UID
= f'{base_url}/series'
url = {'Accept': 'application/dicom+json', "Authorization":bearer_token}
headers = {'SeriesInstanceUID': series_uid}
params = client.get(url, headers=headers, params=params)
response print(f"{response.status_code=}, {response.content=}")
1.4 Retrieve all instances within a study
1.4.1 For a single study UID
= f'{base_url}/studies/{study_uid}'
url = {'Accept':'multipart/related; type="application/dicom"; transfer-syntax=*', "Authorization":bearer_token}
headers
= client.get(url, headers=headers) response
Instances are retrieved as bytes - to return useful output, we’ll loop through returned items and convert to files that can be read by pydicom
import requests_toolbelt as tb
from io import BytesIO
= tb.MultipartDecoder.from_response(response)
mpd
= []
retrieved_dcm_files for part in mpd.parts:
# headers returned as binary
print(part.headers[b'content-type'])
= pydicom.dcmread(BytesIO(part.content))
dcm print(dcm.PatientName)
print(dcm.SOPInstanceUID)
retrieved_dcm_files.append(dcm)
print(retrieved_dcm_files[0].file_meta)
1.4.2 For multiple study UIDs
= []
response_array for study_uid in study_uids:
= f'{base_url}/studies/{study_uid}'
url = {'Accept':'multipart/related; type="application/dicom"; transfer-syntax=*', "Authorization":bearer_token}
headers = client.get(url, headers=headers)
response response_array.append(response)
Parse returned items and output a list of lists, with a list of instances per study
import requests_toolbelt as tb
from io import BytesIO
= []
retrieved_dcm_files_multistudy for r in response_array:
= tb.MultipartDecoder.from_response(r)
mpd
= []
retrieved_study_dcm_files for part in mpd.parts:
= pydicom.dcmread(BytesIO(part.content))
dcm
retrieved_study_dcm_files.append(dcm) retrieved_dcm_files_multistudy.append(retrieved_study_dcm_files)
print(retrieved_dcm_files_multistudy[0][0].file_meta)
1.5 View an image with matplotlib
Instance images can be viewed by plotting the pixel array with matplotlib (or a similar library)
import matplotlib.pyplot as plt
0].pixel_array, cmap=plt.cm.bone) plt.imshow(retrieved_dcm_files[
1.6 Retrieve a single instance within a study
Extract instance IDs from response content - returned as bytes
SOPInstanceUID corresponds to 00080018 - see the DICOM documentation for details
= study_uids[0], series_uids[0]
study_uid, series_uid = f'{base_url}/studies/{study_uid}/series/{series_uid}/instances'
url = {'Accept': 'application/dicom+json', "Authorization":bearer_token}
headers = client.get(url, headers=headers)
response
= json.loads(response.content.decode())
r = [series["00080018"]["Value"][0] for series in r] instance_uids
= instance_uids[0]
instance_uid = f'{base_url}/studies/{study_uid}/series/{series_uid}/instances/{instance_uid}'
url = {'Accept':'application/dicom; transfer-syntax=*', "Authorization":bearer_token}
headers
= client.get(url, headers=headers) response
Again, the single instance is returned as bytes, which we can pass to pydicom with
= pydicom.dcmread(BytesIO(response.content))
dicom_file print(dicom_file.PatientName)
print(dicom_file.SOPInstanceUID)
print(dicom_file.file_meta)
=plt.cm.bone) plt.imshow(dicom_file.pixel_array, cmap