コード例 #1
0
ファイル: DICOMProcesses.py プロジェクト: shijiawls/Slicer
    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.")
コード例 #2
0
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
コード例 #3
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #4
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #5
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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')
コード例 #6
0
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
コード例 #7
0
ファイル: download.py プロジェクト: kaiser-team/dicom-utils
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
コード例 #8
0
ファイル: cli.py プロジェクト: BabakSamari/dicomweb-client
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)
コード例 #9
0
ファイル: cli.py プロジェクト: timmyreilly/dicomweb-client
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)
コード例 #10
0
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]
コード例 #11
0
ファイル: test_api.py プロジェクト: razorx89/dicomweb-client
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]
コード例 #12
0
ファイル: send_via_dcmweb.py プロジェクト: pschader/kaapana
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
コード例 #13
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #14
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #15
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #16
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #17
0
ファイル: dcmweb.py プロジェクト: pschader/kaapana
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")
コード例 #18
0
ファイル: cli.py プロジェクト: venkateshks/dicomweb-client
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)
コード例 #19
0
ファイル: DICOMUtils.py プロジェクト: luckyfish888/Slicer
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
コード例 #20
0
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
コード例 #21
0
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
コード例 #22
0
ファイル: test_api.py プロジェクト: razorx89/dicomweb-client
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
コード例 #23
0
ファイル: test_api.py プロジェクト: razorx89/dicomweb-client
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
コード例 #24
0
def client(httpserver):
    '''Instance of `dicomweb_client.api.DICOMwebClient`.'''
    return DICOMwebClient(httpserver.url)
コード例 #25
0
def test_proxies(httpserver):
    protocol = 'http'
    address = 'foo.com'
    proxies = {protocol: address}
    client = DICOMwebClient(httpserver.url, proxies=proxies)
    assert client._session.proxies[protocol] == address
コード例 #26
0
ファイル: DICOMUtils.py プロジェクト: yehan0223/Slicer
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
コード例 #27
0
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
コード例 #28
0
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
コード例 #30
0
    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