Exemple #1
0
    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.")
Exemple #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
Exemple #3
0
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)
Exemple #4
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
Exemple #5
0
    def send(self):
        self.progressCallback("Starting send to %s using self.protocol" %
                              self.destinationUrl.toString())

        if self.protocol == "DICOMweb":
            # DICOMweb
            # Ensure that correct version of dicomweb-client Python package is installed
            needRestart = False
            needInstall = False
            minimumDicomwebClientVersion = "0.51"
            try:
                import dicomweb_client
                from packaging import version
                if version.parse(dicomweb_client.__version__) < version.parse(
                        minimumDicomwebClientVersion):
                    if not slicer.util.confirmOkCancelDisplay(
                            f"DICOMweb sending requires installation of dicomweb-client (version {minimumDicomwebClientVersion} or later).\nClick OK to upgrade dicomweb-client and restart the application."
                    ):
                        self.showBrowserOnEnter = False
                        return
                    needRestart = True
                    needInstall = True
            except ModuleNotFoundError:
                needInstall = True

            if needInstall:
                # pythonweb-client 0.50 was broken (https://github.com/MGHComputationalPathology/dicomweb-client/issues/41)
                progressDialog = slicer.util.createProgressDialog(
                    labelText=
                    'Upgrading dicomweb-client. This may take a minute...',
                    maximum=0)
                slicer.app.processEvents()
                slicer.util.pip_install(
                    f'dicomweb-client>={minimumDicomwebClientVersion}')
                import dicomweb_client
                progressDialog.close()
            if needRestart:
                slicer.util.restart()

            # Establish connection
            import dicomweb_client.log
            dicomweb_client.log.configure_logging(2)
            from dicomweb_client.api import DICOMwebClient
            effectiveServerUrl = self.destinationUrl.toString()
            session = None
            headers = {}
            # Setting up of the DICOMweb client from various server parameters can be done
            # in plugins in the future, but for now just hardcode special initialization
            # steps for a few server types.
            if "kheops" in effectiveServerUrl:
                # Kheops DICOMweb API endpoint from browser view URL
                url = qt.QUrl(effectiveServerUrl)
                if url.path().startswith('/view/'):
                    # This is a Kheops viewer URL.
                    # Retrieve the token from the viewer URL and use the Kheops API URL to connect to the server.
                    token = url.path().replace('/view/', '')
                    effectiveServerUrl = "https://demo.kheops.online/api"
                    from requests.auth import HTTPBasicAuth
                    from dicomweb_client.session_utils import create_session_from_auth
                    auth = HTTPBasicAuth('token', token)
                    session = create_session_from_auth(auth)

            client = DICOMwebClient(url=effectiveServerUrl,
                                    session=session,
                                    headers=headers)

            for file in self.files:
                if not self.progressCallback(
                        f"Sending {file} to {self.destinationUrl.toString()} using {self.protocol}"
                ):
                    raise UserWarning(
                        "Sending was cancelled, upload is incomplete.")
                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(
                        f"Sent {file} to {self.destinationUrl.host()}:{self.destinationUrl.port()}"
                ):
                    raise UserWarning(
                        "Sending was cancelled, upload is incomplete.")