def send(self): self.progressCallback("Starting send to %s using self.protocol" % self.destinationUrl.toString()) if self.protocol == "DICOMweb": # DICOMweb try: import dicomweb_client except ModuleNotFoundError: logging.info( "Installing dicomweb-client for sending DICOM using DICOMweb protocol" ) pip_install('dicomweb-client') for file in self.files: if not self.progressCallback( "Sending %s to %s using %s" % (file, self.destinationUrl.toString(), self.protocol)): raise UserWarning( "Sending was cancelled, upload is incomplete.") from dicomweb_client.api import DICOMwebClient client = DICOMwebClient(url=self.destinationUrl.toString(), chunk_size=500000) import pydicom dataset = pydicom.dcmread(file) client.store_instances(datasets=[dataset]) else: # DIMSE (traditional DICOM networking) for file in self.files: self.start(file) if not self.progressCallback("Sent %s to %s:%s" % (file, self.destinationUrl.host(), self.destinationUrl.port())): raise UserWarning( "Sending was cancelled, upload is incomplete.")
def test_headers(httpserver): name = 'my-token' value = 'topsecret' headers = {name: value} client = DICOMwebClient(httpserver.url, headers=headers) client.store_instances([]) request = httpserver.requests[0] assert request.headers[name] == value
def _search_for_series(args): '''Searches for Series and writes metadata to standard output.''' params = _parse_search_parameters(args) client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) series = client.search_for_series(args.study_instance_uid, **params) _print_metadata(series, args.prettify, args.dicomize)
def _store_instances(args): '''Loads Instances from files on disk and stores them.''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) datasets = list() for f in args.files: ds = pydicom.dcmread(f) datasets.append(ds) client.store_instances(datasets)
def _retrieve_bulkdata(args): '''Retrieves bulk data and either writes them to standard output or to a file on disk. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) data = client.retrieve_bulkdata(args.bulkdata_uri, args.media_type) print(data) print('\n')
def test_set_http_retry_params(httpserver, client): retry = True retriable_error_codes = (HTTPStatus.TOO_MANY_REQUESTS, HTTPStatus.SERVICE_UNAVAILABLE) max_attempts = 10 wait_exponential_multiplier = 100 client = DICOMwebClient(httpserver.url) client.set_http_retry_params(retry, max_attempts, wait_exponential_multiplier, retriable_error_codes) assert client._http_retry == retry assert client._http_retrable_errors == retriable_error_codes assert client._max_attempts == max_attempts assert client._wait_exponential_multiplier == wait_exponential_multiplier
def create_client(url): ''' Function to create the dicomweb client for future requests''' webclient = DICOMwebClient(url=url, qido_url_prefix='rs', wado_url_prefix='rs', stow_url_prefix='rs') return webclient
def main(): '''Main entry point for the ``dicomweb_client`` command line program.''' parser = _get_parser() args = parser.parse_args() if args.username: if not args.password: message = 'Enter password for user "{0}": '.format(args.username) args.password = getpass.getpass(message) configure_logging(args.logging_verbosity) try: client = DICOMwebClient( args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert, headers=_create_headers(args), chunk_size=args.chunk_size ) args.func(client, args) sys.exit(0) except Exception as err: logger.error(str(err)) if args.logging_verbosity > 3: tb = traceback.format_exc() logger.error(tb) sys.exit(1)
def main(args): """Main entry point for the ``dicomweb_client`` command line program.""" configure_logging(args.logging_verbosity) if args.username: if not args.password: message = 'Enter password for user "{0}": '.format(args.username) args.password = getpass.getpass(message) session = create_session_from_user_pass(args.username, args.password) else: session = create_session() try: session = add_certs_to_session(session, args.ca_bundle, args.cert) session.headers.update(_create_headers(args)) client = DICOMwebClient( args.url, session=session, chunk_size=args.chunk_size ) args.func(client, args) sys.exit(0) except Exception as err: logger.error(str(err)) if args.logging_verbosity > 3: tb = traceback.format_exc() logger.error(tb) sys.exit(1)
def test_retrieve_instance(httpserver, client, cache_dir): cache_filename = str(cache_dir.joinpath('file.dcm')) with open(cache_filename, 'rb') as f: data = f.read() media_type = 'application/dicom' boundary = 'boundary' headers = { 'content-type': ('multipart/related; ' f'type="{media_type}"; ' f'boundary="{boundary}"'), } message = DICOMwebClient._encode_multipart_message( content=[data], content_type=headers['content-type']) httpserver.serve_content(content=message, code=200, headers=headers) study_instance_uid = '1.2.3' series_instance_uid = '1.2.4' sop_instance_uid = '1.2.5' response = client.retrieve_instance(study_instance_uid, series_instance_uid, sop_instance_uid) with BytesIO() as fp: pydicom.dcmwrite(fp, response) raw_result = fp.getvalue() assert raw_result == data request = httpserver.requests[0] expected_path = (f'/studies/{study_instance_uid}' f'/series/{series_instance_uid}' f'/instances/{sop_instance_uid}') assert request.path == expected_path assert request.accept_mimetypes[0][0][:43] == headers['content-type'][:43]
def test_retrieve_instance_default_transfer_syntax(httpserver, client, cache_dir): cache_filename = str(cache_dir.joinpath('file.dcm')) with open(cache_filename, 'rb') as f: data = f.read() media_type = 'application/dicom' boundary = 'boundary' headers = { 'content-type': ( 'multipart/related; ' f'type="{media_type}"; ' f'boundary="{boundary}"' ), } message = DICOMwebClient._encode_multipart_message( content=[data], content_type=headers['content-type'] ) httpserver.serve_content(content=message, code=200, headers=headers) study_instance_uid = '1.2.3' series_instance_uid = '1.2.4' sop_instance_uid = '1.2.5' client.retrieve_instance( study_instance_uid, series_instance_uid, sop_instance_uid, media_types=(('application/dicom', '1.2.840.10008.1.2.1', ), ) ) request = httpserver.requests[0] assert request.accept_mimetypes[0][0][:43] == headers['content-type'][:43]
def init(url, cert_file, ignore_ssl_verify): global client kaapana_url = url + "/dicomweb" client = DICOMwebClient(url=kaapana_url, ca_bundle=cert_file) if ignore_ssl_verify: print("Warning: You are disabling https verification!") client._session.verify = False
def _retrieve_instance_metadata(args): '''Retrieves metadata for an individual Instances and either writes it to standard output or to a file on disk. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) metadata = client.retrieve_instance_metadata(args.study_instance_uid, args.series_instance_uid, args.sop_instance_uid) if args.save: _save_metadata(metadata, args.output_dir, args.sop_instance_uid, args.prettify, args.dicomize) else: _print_metadata(metadata, args.prettify, args.dicomize)
def _retrieve_study_metadata(args): '''Retrieves metadata for all Instances of a given Study and either writes it to standard output or to files on disk. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) metadata = client.retrieve_study_metadata(args.study_instance_uid) if args.save: for md in metadata: tag = client.lookup_tag('SOPInstanceUID') sop_instance_uid = md[tag]['Value'][0] _save_metadata(md, args.output_dir, sop_instance_uid, args.prettify, args.dicomize) else: _print_metadata(metadata, args.prettify, args.dicomize)
def _retrieve_instance(args): '''Retrieves an Instances and either writes it to standard output or to a file on disk. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) instance = client.retrieve_instance( args.study_instance_uid, args.series_instance_uid, args.sop_instance_uid, media_types=args.media_types, ) if args.save: _save_instance(instance, args.output_dir, args.sop_instance_uid) else: _print_instance(instance)
def _retrieve_study(args): '''Retrieves all Instances of a given Study and either writes them to standard output or to files on disk. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) instances = client.retrieve_study( args.study_instance_uid, media_types=args.media_types, ) for inst in instances: sop_instance_uid = inst.SOPInstanceUID if args.save: _save_instance(inst, args.output_dir, sop_instance_uid) else: _print_instance(inst)
def init(pacs_origin, port, aetitle): global client pacsURL = pacs_origin + ":" + port + "/dcm4chee-arc/aets/" + aetitle.upper( ) client = DICOMwebClient(url=pacsURL, qido_url_prefix="rs", wado_url_prefix="rs", stow_url_prefix="rs")
def _retrieve_instance_frames(args): '''Retrieves frames for an individual instances and either writes them to standard output or files on disk or displays them in a GUI (depending on the requested content type). Frames can only be saved and shown if they are retrieved using image media types. ''' client = DICOMwebClient(args.url, username=args.username, password=args.password, ca_bundle=args.ca_bundle, cert=args.cert) pixel_data = client.retrieve_instance_frames( args.study_instance_uid, args.series_instance_uid, args.sop_instance_uid, args.frame_numbers, media_types=args.media_types, ) for i, data in enumerate(pixel_data): if args.save or args.show: try: image = Image.open(BytesIO(data)) except Exception: try: import jpeg_ls image = jpeg_ls.decode(np.fromstring(data, dtype=np.uint8)) except Exception: raise IOError('Cannot load retrieved frame as an image.') if args.save: filename = ( '{sop_instance_uid}_{frame_number}.{extension}'.format( sop_instance_uid=args.sop_instance_uid, frame_number=args.frame_numbers[i], extension=image.format.lower())) filepath = os.path.join(args.output_dir, filename) _save_image(image, filepath) elif args.show: _show_image(image) else: _print_pixel_data(data)
def importFromDICOMWeb(dicomWebEndpoint, studyInstanceUID, seriesInstanceUID=None, accessToken=None): """ Downloads and imports DICOM series from a DICOMweb instance. Example usage: from DICOMLib import DICOMUtils loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint", studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338") accessToken="YOUR_ACCESS_TOKEN") :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb :param studyInstanceUID: UID for the study to be downloaded :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study :param accessToken: Optional access token for the query :return: List of imported study UIDs """ from dicomweb_client.api import DICOMwebClient import random if accessToken is None: client = DICOMwebClient(url = dicomWebEndpoint) else: client = DICOMwebClient( url = dicomWebEndpoint, headers = { "Authorization": "Bearer {}".format(accessToken) }, ) seriesList = client.search_for_series(study_instance_uid=studyInstanceUID) seriesInstanceUIDs = [] if not seriesInstanceUID is None: seriesInstanceUIDs = [seriesInstanceUID] else: for series in seriesList: currentSeriesInstanceUID = series['0020000E']['Value'][0] seriesInstanceUIDs.append(currentSeriesInstanceUID) fileNumber = 0 for currentSeriesInstanceUID in seriesInstanceUIDs: instances = client.retrieve_series( study_instance_uid=studyInstanceUID, series_instance_uid=currentSeriesInstanceUID) outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb" if not os.access(outputDirectoryBase, os.F_OK): os.makedirs(outputDirectoryBase) outputDirectoryBase += "/" + qt.QDateTime.currentDateTime().toString("yyyyMMdd-hhmmss") outputDirectory = qt.QTemporaryDir(outputDirectoryBase) # Add unique substring to directory outputDirectory.setAutoRemove(False) outputDirectoryPath = outputDirectory.path() for instance in instances: filename = outputDirectoryPath + "/" + str(fileNumber) + ".dcm" instance.save_as(filename) fileNumber += 1 slicer.app.processEvents() importDicom(outputDirectoryPath) return seriesInstanceUIDs
def test_url_prefixes(httpserver): wado_url_prefix = 'wado' qido_url_prefix = 'qido' stow_url_prefix = 'stow' client = DICOMwebClient( httpserver.url, wado_url_prefix=wado_url_prefix, qido_url_prefix=qido_url_prefix, stow_url_prefix=stow_url_prefix, ) assert client.url_prefix == '' assert client.qido_url_prefix == qido_url_prefix assert client.wado_url_prefix == wado_url_prefix assert client.stow_url_prefix == stow_url_prefix
def test_url(httpserver): protocol = 'http' host = 'localhost' port = 8080 path = '/dcm4chee-arc/aets/DCM4CHEE/rs' url = '{protocol}://{host}:{port}{path}'.format( protocol=protocol, host=host, port=port, path=path ) client = DICOMwebClient(url) assert client.protocol == protocol assert client.host == host assert client.port == port assert client.url_prefix == path assert client.qido_url_prefix is None assert client.wado_url_prefix is None assert client.stow_url_prefix is None
def test_iter_instance_frames_jpeg(httpserver, client, cache_dir): cache_filename = str(cache_dir.joinpath('retrieve_instance_pixeldata.jpg')) with open(cache_filename, 'rb') as f: data = f.read() n_resources = 2 chunk_size = 10**2 media_type = 'image/jpeg' boundary = 'boundary' headers = { 'content-type': ( 'multipart/related; ' f'type="{media_type}"; ' f'boundary="{boundary}"' ), 'transfer-encoding': 'chunked' } message = DICOMwebClient._encode_multipart_message( content=[data for _ in range(n_resources)], content_type=headers['content-type'] ) chunked_message = _chunk_message(message, chunk_size) httpserver.serve_content(content=chunked_message, code=200, headers=headers) study_instance_uid = '1.2.3' series_instance_uid = '1.2.4' sop_instance_uid = '1.2.5' frame_numbers = [x + 1 for x in range(n_resources)] frame_list = ','.join([str(n) for n in frame_numbers]) iterator = client.iter_instance_frames( study_instance_uid, series_instance_uid, sop_instance_uid, frame_numbers, media_types=(media_type, ) ) response = list(iterator) request = httpserver.requests[0] expected_path = ( f'/studies/{study_instance_uid}' f'/series/{series_instance_uid}' f'/instances/{sop_instance_uid}' f'/frames/{frame_list}' ) assert isinstance(iterator, Generator) assert request.path == expected_path assert request.accept_mimetypes[0][0][:36] == headers['content-type'][:36] assert len(response) == n_resources
def test_iter_series(client, httpserver, cache_dir): cache_filename = str(cache_dir.joinpath('file.dcm')) with open(cache_filename, 'rb') as f: data = f.read() n_resources = 3 chunk_size = 10**3 media_type = 'application/dicom' boundary = 'boundary' headers = { 'content-type': ( 'multipart/related; ' f'type="{media_type}"; ' f'boundary="{boundary}"' ), 'transfer-encoding': 'chunked' } message = DICOMwebClient._encode_multipart_message( content=[data for _ in range(n_resources)], content_type=headers['content-type'] ) chunked_message = _chunk_message(message, chunk_size) httpserver.serve_content(content=chunked_message, code=200, headers=headers) study_instance_uid = '1.2.3' series_instance_uid = '1.2.4' iterator = client.iter_series( study_instance_uid, series_instance_uid ) assert isinstance(iterator, Generator) response = list(iterator) for instance in response: with BytesIO() as fp: pydicom.dcmwrite(fp, instance) raw_result = fp.getvalue() assert raw_result == data request = httpserver.requests[0] expected_path = ( f'/studies/{study_instance_uid}' f'/series/{series_instance_uid}' ) assert request.path == expected_path assert request.accept_mimetypes[0][0][:43] == headers['content-type'][:43] assert len(response) == n_resources
def client(httpserver): '''Instance of `dicomweb_client.api.DICOMwebClient`.''' return DICOMwebClient(httpserver.url)
def test_proxies(httpserver): protocol = 'http' address = 'foo.com' proxies = {protocol: address} client = DICOMwebClient(httpserver.url, proxies=proxies) assert client._session.proxies[protocol] == address
def importFromDICOMWeb(dicomWebEndpoint, studyInstanceUID, seriesInstanceUID=None, accessToken=None): """ Downloads and imports DICOM series from a DICOMweb instance. Example usage: from DICOMLib import DICOMUtils loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint", studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338") accessToken="YOUR_ACCESS_TOKEN") :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb :param studyInstanceUID: UID for the study to be downloaded :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study :param accessToken: Optional access token for the query :return: List of imported study UIDs """ from dicomweb_client.api import DICOMwebClient import random progressDialog = slicer.util.createProgressDialog( parent=slicer.util.mainWindow(), value=0, maximum=100) progressDialog.labelText = f'Retrieving series list...' slicer.app.processEvents() if accessToken is None: client = DICOMwebClient(url=dicomWebEndpoint, callback=progressCallback) else: client = DICOMwebClient( url=dicomWebEndpoint, headers={"Authorization": f"Bearer {accessToken}"}, ) seriesList = client.search_for_series(study_instance_uid=studyInstanceUID) seriesInstanceUIDs = [] if not seriesInstanceUID is None: seriesInstanceUIDs = [seriesInstanceUID] else: for series in seriesList: currentSeriesInstanceUID = series['0020000E']['Value'][0] seriesInstanceUIDs.append(currentSeriesInstanceUID) fileNumber = 0 cancelled = False for seriesIndex, currentSeriesInstanceUID in enumerate(seriesInstanceUIDs): progressDialog.labelText = f'Retrieving series {seriesIndex+1} of {len(seriesInstanceUIDs)}...' slicer.app.processEvents() instances = client.retrieve_series( study_instance_uid=studyInstanceUID, series_instance_uid=currentSeriesInstanceUID) progressDialog.setValue( int(100 * seriesIndex / len(seriesInstanceUIDs))) slicer.app.processEvents() cancelled = progressDialog.wasCanceled if cancelled: break outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb" if not os.access(outputDirectoryBase, os.F_OK): os.makedirs(outputDirectoryBase) outputDirectoryBase += "/" + qt.QDateTime.currentDateTime().toString( "yyyyMMdd-hhmmss") outputDirectory = qt.QTemporaryDir( outputDirectoryBase) # Add unique substring to directory outputDirectory.setAutoRemove(False) outputDirectoryPath = outputDirectory.path() for instanceIndex, instance in enumerate(instances): filename = outputDirectoryPath + "/" + str(fileNumber) + ".dcm" instance.save_as(filename) fileNumber += 1 importDicom(outputDirectoryPath) if cancelled: break progressDialog.close() return seriesInstanceUIDs
def importFromDICOMWeb(dicomWebEndpoint, studyInstanceUID, seriesInstanceUID=None, accessToken=None): """ Downloads and imports DICOM series from a DICOMweb instance. Progress is displayed and if errors occur then they are displayed in a popup window in the end. If all the instances in a series are already imported then the series will not be retrieved and imported again. :param dicomWebEndpoint: Endpoint URL for retrieving the study/series from DICOMweb :param studyInstanceUID: UID for the study to be downloaded :param seriesInstanceUID: UID for the series to be downloaded. If not specified, all series will be downloaded from the study :param accessToken: Optional access token for the query :return: List of imported study UIDs Example: calling from PythonSlicer console .. code-block:: python from DICOMLib import DICOMUtils loadedUIDs = DICOMUtils.importFromDICOMWeb(dicomWebEndpoint="https://yourdicomweburl/dicomWebEndpoint", studyInstanceUID="2.16.840.1.113669.632.20.1211.10000509338") accessToken="YOUR_ACCESS_TOKEN") """ from dicomweb_client.api import DICOMwebClient seriesImported = [] errors = [] clientLogger = logging.getLogger('dicomweb_client') originalClientLogLevel = clientLogger.level progressDialog = slicer.util.createProgressDialog( parent=slicer.util.mainWindow(), value=0, maximum=100) try: progressDialog.labelText = f'Retrieving series list...' slicer.app.processEvents() if accessToken is None: client = DICOMwebClient(url=dicomWebEndpoint) else: client = DICOMwebClient( url=dicomWebEndpoint, headers={"Authorization": f"Bearer {accessToken}"}, ) seriesList = client.search_for_series( study_instance_uid=studyInstanceUID) seriesInstanceUIDs = [] if seriesInstanceUID is not None: seriesInstanceUIDs = [seriesInstanceUID] else: for series in seriesList: currentSeriesInstanceUID = series['0020000E']['Value'][0] seriesInstanceUIDs.append(currentSeriesInstanceUID) # Turn off detailed logging, because it would slow down the file transfer clientLogger.setLevel(logging.WARNING) fileNumber = 0 cancelled = False for seriesIndex, currentSeriesInstanceUID in enumerate( seriesInstanceUIDs): progressDialog.labelText = f'Retrieving series {seriesIndex+1} of {len(seriesInstanceUIDs)}...' slicer.app.processEvents() try: seriesInfo = client.retrieve_series_metadata( study_instance_uid=studyInstanceUID, series_instance_uid=currentSeriesInstanceUID) numberOfInstances = len(seriesInfo) # Skip retrieve and import of this series if it is already imported alreadyImportedInstances = slicer.dicomDatabase.instancesForSeries( currentSeriesInstanceUID) seriesAlreadyImported = True for serieInfo in seriesInfo: sopInstanceUID = serieInfo['00080018']['Value'][0] if sopInstanceUID not in alreadyImportedInstances: seriesAlreadyImported = False break if seriesAlreadyImported: seriesImported.append(currentSeriesInstanceUID) continue instances = client.iter_series( study_instance_uid=studyInstanceUID, series_instance_uid=currentSeriesInstanceUID) slicer.app.processEvents() cancelled = progressDialog.wasCanceled if cancelled: break outputDirectoryBase = slicer.dicomDatabase.databaseDirectory + "/DICOMweb" if not os.access(outputDirectoryBase, os.F_OK): os.makedirs(outputDirectoryBase) outputDirectoryBase += "/" + qt.QDateTime.currentDateTime( ).toString("yyyyMMdd-hhmmss") outputDirectory = qt.QTemporaryDir( outputDirectoryBase) # Add unique substring to directory outputDirectory.setAutoRemove(False) outputDirectoryPath = outputDirectory.path() for instanceIndex, instance in enumerate(instances): progressDialog.setValue( int(100 * instanceIndex / numberOfInstances)) slicer.app.processEvents() cancelled = progressDialog.wasCanceled if cancelled: break filename = outputDirectoryPath + "/" + str( fileNumber) + ".dcm" instance.save_as(filename) fileNumber += 1 if cancelled: # cancel was requested in instance retrieve loop, # stop the entire import process break importDicom(outputDirectoryPath) seriesImported.append(currentSeriesInstanceUID) except Exception as e: import traceback errors.append( f"Error importing series {currentSeriesInstanceUID}: {str(e)} ({traceback.format_exc()})" ) except Exception as e: import traceback errors.append(f"{str(e)} ({traceback.format_exc()})") finally: progressDialog.close() clientLogger.setLevel(originalClientLogLevel) if errors: slicer.util.errorDisplay( f"Errors occurred during DICOMweb import of {len(errors)} series.", detailedText="\n\n".join(errors)) elif cancelled and (len(seriesImported) < len(seriesInstanceUIDs)): slicer.util.infoDisplay( f"DICOMweb import has been interrupted after completing {len(seriesImported)} out of {len(seriesInstanceUIDs)} series." ) return seriesImported
from dicomweb_client.api import DICOMwebClient from io import BytesIO import numpy as np from PIL import Image client = DICOMwebClient( url="https://cidia-pacs.ufrgs.dev", qido_url_prefix="pacs/dicom-web", wado_url_prefix="pacs/dicom-web", # wado_url_prefix="pacs/wado", ) print("client") print(client) print() # studies = client.search_for_studies() # print('studies') # print(studies) # print() # study = client.search_for_studies(search_filters={'PatientID': 'EXAME1'}) # print('study') # print(study) # print() # instance = client.retrieve_instance( # study_instance_uid='1.2.840.113704.7.1.0.1364618414717319.1587167780.0',
def make_client(url, port, user, password): auth = HTTPBasicAuth(user, password) session = create_session_from_auth(auth) full_url = utilities.make_url(url, 'dicom-web', port) client = DICOMwebClient(url = full_url, session = session) return client
def _PubsubCallback(self, message): # type: pubsub_v1.Message -> None """Processes a Pubsub message. This function will retrieve the instance (specified in Pubsub message) from the Cloud Healthcare API. Then it will invoke CMLE to get the prediction results. Finally (and optionally), it will store the inference results back to the Cloud Healthcare API as a DICOM Structured Report. The instance URL to the Structured Report containing the prediction is then published to a pub/sub. Args: message: Incoming pubsub message. """ image_instance_path = message.data.decode() _logger.debug('Received instance in pubsub feed: %s', image_instance_path) try: parsed_message = pubsub_format.ParseMessage( message, dicom_path.Type.INSTANCE) except exception.CustomExceptionError: _logger.info('Invalid input path: %s', image_instance_path) message.ack() return input_path = parsed_message.input_path authed_session = session_utils.create_session_from_gcp_credentials() dicomweb_url = posixpath.join(_HEALTHCARE_API_URL_PREFIX, input_path.dicomweb_path_str) input_client = DICOMwebClient(dicomweb_url, authed_session) if not self._IsMammoInstance(input_client, input_path): _logger.info( 'Instance is not of type MG modality, ignoring message: %s', image_instance_path) message.ack() return _logger.info('Processing instance: %s', image_instance_path) # Retrieve instance from DICOM API in JPEG format. image_jpeg_bytes = input_client.retrieve_instance_rendered( input_path.study_uid, input_path.series_uid, input_path.instance_uid, media_types=('image/jpeg', )) # Retrieve study level information study_json = input_client.search_for_studies( fields=['all'], search_filters={'StudyInstanceUID': input_path.study_uid})[0] # Get the predicted score and class from the inference model in Cloud ML or # AutoML. try: predicted_class, predicted_score = self._predictor.Predict( image_jpeg_bytes) except PermissionDenied as e: _logger.error('Permission error running prediction service: %s', e) message.nack() return except InvalidArgument as e: _logger.error( 'Invalid arguments when running prediction service: %s', e) message.nack() return # Print the prediction. text = 'Base path: %s\nPredicted class: %s\nPredicted score: %s' % ( image_instance_path, predicted_class, predicted_score) _logger.info(text) # If user requested destination DICOM store for inference, create a DICOM # structured report that stores the prediction. if self._dicom_store_path: # Create DICOMwebClient with output url. output_dicom_web_url = posixpath.join( _HEALTHCARE_API_URL_PREFIX, self._dicom_store_path.dicomweb_path_str) output_client = DICOMwebClient(output_dicom_web_url, authed_session) # Generate series uid and instance uid for the structured report. sr_instance_uid = pydicom.uid.generate_uid(prefix=None) sr_series_uid = pydicom.uid.generate_uid(prefix=None) sr_dataset = _BuildSR(study_json, text, sr_series_uid, sr_instance_uid) try: output_client.store_instances([sr_dataset]) except RuntimeError as e: _logger.error('Error storing DICOM in API: %s', e) message.nack() return # If user requested that new structured reports be published to a channel, # publish the instance path of the Structured Report structured_report_path = dicom_path.FromPath( self._dicom_store_path, study_uid=input_path.study_uid, series_uid=sr_series_uid, instance_uid=sr_instance_uid) self._PublishInferenceResultsReady(str(structured_report_path)) _logger.info('Published structured report with path: %s', structured_report_path) # Ack the message (successful or invalid message). message.ack() self._success_count += 1