Exemple #1
0
        /// <summary>
        /// Processes the model configuration.
        /// </summary>
        /// <param name="uploadQueueItem">The upload queue item.</param>
        /// <param name="dicomFiles">The dicom files.</param>
        /// <param name="queueTransaction">The queue transaction.</param>
        /// <param name="clientConfiguration">The client configuration.</param>
        /// <returns>The waitable task.</returns>
        private async Task ProcessModelConfig(
            IEnumerable <DicomFile> dicomFiles,
            UploadQueueItem uploadQueueItem,
            IQueueTransaction queueTransaction,
            ClientAETConfig clientConfiguration)
        {
            var modelMatchResult = ApplyAETModelConfigProvider.ApplyAETModelConfig(clientConfiguration.Config.ModelsConfig, dicomFiles);

            if (modelMatchResult.Matched)
            {
                var model     = modelMatchResult.Result;
                var queueItem = await StartSegmentationAsync(model.ChannelData, uploadQueueItem, model.ModelId, model.TagReplacements.ToArray(), clientConfiguration).ConfigureAwait(false);

                EnqueueMessage(queueItem, _downloadQueuePath, queueTransaction);
            }
            else
            {
                var failedDicomTags = modelMatchResult.GetDicomConstraintsDicomTags();

                // Log all the tags that did not match
                LogError(LogEntry.Create(AssociationStatus.UploadErrorTagsDoNotMatch,
                                         uploadQueueItem: uploadQueueItem,
                                         failedDicomTags: string.Join(",", failedDicomTags.Select(x => x.DictionaryEntry.Name))),
                         new ProcessorServiceException("Failed to find a model for the received Dicom data."));
            }
        }
Exemple #2
0
        /// <summary>
        /// Uploads the files.
        /// </summary>
        /// <param name="dicomFiles">The dicom files.</param>
        /// <param name="uploadQueueItem">The upload queue item.</param>
        /// <param name="queueTransaction">The queue transaction.</param>
        /// <returns>The async task.</returns>
        private async Task ProcessUploadQueueItem(UploadQueueItem uploadQueueItem, IQueueTransaction queueTransaction)
        {
            var clientConfiguration = ApplyAETModelConfigProvider.GetAETConfigs(
                _aetConfigModels,
                uploadQueueItem.CalledApplicationEntityTitle,
                uploadQueueItem.CallingApplicationEntityTitle);

            LogTrace(LogEntry.Create(AssociationStatus.UploadProcessQueueItem));

            switch (clientConfiguration.Config.AETConfigType)
            {
            // ML Model or ML Model with Dry Run Result
            case AETConfigType.Model:
            case AETConfigType.ModelWithResultDryRun:
                // Load all DICOM files in the received folder.
                var dicomFiles = ReadDicomFiles(uploadQueueItem.AssociationFolderPath, uploadQueueItem);
                await ProcessModelConfig(dicomFiles, uploadQueueItem, queueTransaction, clientConfiguration).ConfigureAwait(false);

                break;

            // ML Model dry run
            case AETConfigType.ModelDryRun:
                // Anonymize and save the files locally for the dry run using the segmentation anonymisation protocol
                await AnonymiseAndSaveDicomFilesAsync(
                    anonymisationProtocolId : _innerEyeSegmentationClient.SegmentationAnonymisationProtocolId,
                    anonymisationProtocol : _innerEyeSegmentationClient.SegmentationAnonymisationProtocol,
                    uploadQueueItem : uploadQueueItem,
                    aETConfigType : clientConfiguration.Config.AETConfigType).ConfigureAwait(false);

                break;
            }
        }
Exemple #3
0
        protected async Task <(string SegmentationId, string ModelId, IEnumerable <byte[]> Data)> StartFakeSegmentationAsync(string filesPath)
        {
            var dicomFiles = new DirectoryInfo(filesPath).GetFiles().Select(x => DicomFile.Open(x.FullName)).ToArray();

            using (var segmentationClient = GetMockInnerEyeSegmentationClient())
            {
                var testAETConfigModel = GetTestAETConfigModel();

                var matchedModel = ApplyAETModelConfigProvider.ApplyAETModelConfig(testAETConfigModel.AETConfig.Config.ModelsConfig, dicomFiles);
                var modelId      = matchedModel.Result.ModelId;

                var(segmentationId, postedImages) = await segmentationClient.StartSegmentationAsync(
                    matchedModel.Result.ModelId,
                    matchedModel.Result.ChannelData).ConfigureAwait(false);

                var referenceDicomFiles = postedImages.CreateNewDicomFileWithoutPixelData(segmentationClient.SegmentationAnonymisationProtocol.Select(x => x.DicomTagIndex.DicomTag));
                return(segmentationId, modelId, referenceDicomFiles);
            }
        }
Exemple #4
0
        public async Task IntegrationTestEndToEnd()
        {
            var sourceDirectory = CreateTemporaryDirectory();
            var resultDirectory = CreateTemporaryDirectory();

            var random = new Random();

            // Get file names for all in directory
            var sourceDicomFileNames = new DirectoryInfo(@"Images\HN").GetFiles().ToArray();
            // Load all DICOM files
            var sourceDicomFiles = sourceDicomFileNames.Select(f => DicomFile.Open(f.FullName, FileReadOption.ReadAll)).ToArray();

            // Add/Update random tags for the source DICOM files.
            DicomAnonymisationTests.AddRandomTags(random, sourceDicomFiles);

            // Save them all to the sourceDirectory.
            var sourcePairs = sourceDicomFileNames.Zip(sourceDicomFiles, (f, d) => Tuple.Create(f, d)).ToArray();

            foreach (var sourcePair in sourcePairs)
            {
                var sourceImageFilePath = Path.Combine(sourceDirectory.FullName, sourcePair.Item1.Name);

                sourcePair.Item2.Save(sourceImageFilePath);
            }

            // Keep the first as a reference for deanonymization later.
            var originalSlice = sourceDicomFiles.First();

            var testAETConfigModel = GetTestAETConfigModel();

            var receivePort = 160;

            using (var dicomDataReceiver = new ListenerDataReceiver(new ListenerDicomSaver(resultDirectory.FullName)))
                using (var deleteService = CreateDeleteService())
                    using (var pushService = CreatePushService())
                        using (var downloadService = CreateDownloadService())
                            using (var uploadService = CreateUploadService())
                                using (var receiveService = CreateReceiveService(receivePort))
                                {
                                    // Start a DICOM receiver for the final DICOM-RT file
                                    var eventCount = new ConcurrentDictionary <DicomReceiveProgressCode, int>();
                                    var folderPath = string.Empty;

                                    dicomDataReceiver.DataReceived += (sender, e) =>
                                    {
                                        folderPath = e.FolderPath;
                                        eventCount.AddOrUpdate(e.ProgressCode, 1, (k, v) => v + 1);
                                    };

                                    StartDicomDataReceiver(dicomDataReceiver, testAETConfigModel.AETConfig.Destination.Port);

                                    // Start the services.
                                    deleteService.Start();
                                    pushService.Start();
                                    downloadService.Start();
                                    uploadService.Start();
                                    receiveService.Start();

                                    // Try a DICOM C-ECHO
                                    var dicomDataSender = new DicomDataSender();

                                    var echoResult = await dicomDataSender.DicomEchoAsync(
                                        testAETConfigModel.CallingAET,
                                        testAETConfigModel.CalledAET,
                                        receivePort,
                                        "127.0.0.1").ConfigureAwait(false);

                                    Assert.IsTrue(echoResult == DicomOperationResult.Success);

                                    // Send the image stack
                                    DcmtkHelpers.SendFolderUsingDCMTK(
                                        sourceDirectory.FullName,
                                        receivePort,
                                        ScuProfile.LEExplicitCT,
                                        TestContext,
                                        applicationEntityTitle: testAETConfigModel.CallingAET,
                                        calledAETitle: testAETConfigModel.CalledAET);

                                    // Wait for DICOM-RT file to be received.
                                    Func <DicomReceiveProgressCode, int, bool> TestEventCount = (progressCode, count) =>
                                                                                                eventCount.ContainsKey(progressCode) && eventCount[progressCode] == count;

                                    SpinWait.SpinUntil(() => TestEventCount(DicomReceiveProgressCode.AssociationEstablished, 1));
                                    SpinWait.SpinUntil(() => TestEventCount(DicomReceiveProgressCode.FileReceived, 1));
                                    SpinWait.SpinUntil(() => TestEventCount(DicomReceiveProgressCode.AssociationReleased, 1));
                                    SpinWait.SpinUntil(() => TestEventCount(DicomReceiveProgressCode.ConnectionClosed, 1));

                                    Assert.IsTrue(eventCount[DicomReceiveProgressCode.AssociationEstablished] == 1);
                                    Assert.IsTrue(eventCount[DicomReceiveProgressCode.FileReceived] == 1);
                                    Assert.IsTrue(eventCount[DicomReceiveProgressCode.AssociationReleased] == 1);
                                    Assert.IsTrue(eventCount[DicomReceiveProgressCode.ConnectionClosed] == 1);

                                    var receivedFiles = new DirectoryInfo(folderPath).GetFiles();
                                    Assert.AreEqual(1, receivedFiles.Length);

                                    var receivedFilePath = receivedFiles.First().FullName;

                                    var dicomFile = await DicomFile.OpenAsync(receivedFilePath, FileReadOption.ReadAll).ConfigureAwait(false);

                                    Assert.IsNotNull(dicomFile);

                                    var matchedModel = ApplyAETModelConfigProvider.ApplyAETModelConfig(testAETConfigModel.AETConfig.Config.ModelsConfig, sourceDicomFiles);

                                    var segmentationClient = TestGatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient().Invoke();

                                    DicomAnonymisationTests.AssertDeanonymizedFile(
                                        originalSlice,
                                        dicomFile,
                                        segmentationClient.TopLevelReplacements,
                                        matchedModel.Result.TagReplacements,
                                        false);

                                    AssertIsDicomRtFile(DateTime.UtcNow, dicomFile, matchedModel.Result.ModelId);
                                }
        }
Exemple #5
0
        /// <summary>
        /// Called when [update tick] is called. This will wait for all work to execute then will pause for desired interval delay.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>
        /// The async task.
        /// </returns>
        protected override async Task OnUpdateTickAsync(CancellationToken cancellationToken)
        {
            using (var transaction = CreateQueueTransaction())
            {
                BeginMessageQueueTransaction(transaction);

                PushQueueItem queueItem = null;

                try
                {
                    queueItem = await DequeueNextMessageAsync(transaction, cancellationToken).ConfigureAwait(false);

                    // If we have dequed this item more than once, lets check if the destination
                    // Dicom endpoint has been updated on the configuration service (or if the destination is null).
                    if (queueItem.DequeueCount > 1 || queueItem.DestinationApplicationEntity == null)
                    {
                        // Refresh the application entity config.
                        var applicationEntityConfig = ApplyAETModelConfigProvider.GetAETConfigs(
                            _aetConfigModels,
                            queueItem.CalledApplicationEntityTitle,
                            queueItem.CallingApplicationEntityTitle);

                        if (applicationEntityConfig.Destination == null)
                        {
                            var exception = new ArgumentNullException("applicationEntityConfig.Destination",
                                                                      "The result destination is null. The destination has not been configured.");

                            LogError(LogEntry.Create(AssociationStatus.PushErrorDestinationEmpty, pushQueueItem: queueItem),
                                     exception);

                            throw exception;
                        }

                        queueItem.DestinationApplicationEntity = new GatewayApplicationEntity(
                            title: applicationEntityConfig.Destination.Title,
                            port: applicationEntityConfig.Destination.Port,
                            ipAddress: applicationEntityConfig.Destination.Ip);
                    }

                    if (queueItem.FilePaths.Any())
                    {
                        var dicomFiles = ReadDicomFiles(queueItem.FilePaths, queueItem);

                        await PushDicomFilesAsync(
                            pushQueueItem : queueItem,
                            ownApplicationEntityTitle : queueItem.CalledApplicationEntityTitle,
                            destination : queueItem.DestinationApplicationEntity,
                            cancellationToken : cancellationToken,
                            dicomFiles : dicomFiles.ToArray()).ConfigureAwait(false);
                    }

                    // Enqueue delete the files.
                    CleanUp(queueItem, transaction);

                    transaction.Commit();
                }
                catch (MessageQueueReadException)
                {
                    // We timed out trying to de-queue (no items on the queue).
                    // This exception doesn't need to be logged.
                    transaction.Abort();
                }
                catch (OperationCanceledException)
                {
                    // Throw operation canceled exceptions up to the worker thread. It will handle
                    // logging correctly.
                    transaction.Abort();
                    throw;
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    LogError(LogEntry.Create(AssociationStatus.PushError, pushQueueItem: queueItem),
                             e);

                    HandleExceptionForTransaction(
                        queueItem: queueItem,
                        queueTransaction: transaction,
                        oldQueueItemAction: () => CleanUp(queueItem, transaction));
                }
            }
        }