internal static async Task FindAsync <U>( DicomCFindRequest request, DicomSearchServiceSettings serviceSettings, SemaphoreSlim requestSemaphore, CancellationToken ct) { // always add the encoding request.Dataset.AddOrUpdate(new DicomTag(0x8, 0x5), "ISO_IR 100"); // add the dicom tags with empty values that should be included in the result of the QR Server request.Dataset.Fill <U>(); var client = serviceSettings.DicomSettings.CreateClient(); await client.AddRequestAsync(request); if (requestSemaphore != null) { await requestSemaphore.WaitAsync(ct); } try { if (!ct.IsCancellationRequested) { await client.SendAsync(ct); } } finally { if (requestSemaphore != null) { requestSemaphore.Release(); } } }
private DicomSeriesImageService(Action <Image> progress, DicomSearchServiceSettings settings, CancellationToken ct) { _getImagesDesc = new TransformBlock <Series, Request>(async ser => { try { var desc = await GetImagesDescAsync(ser, settings, ct); return(new Request { Series = ser, ImagesDesc = desc }); } catch (Exception ex) { _logger.Error(ex, "Failed to get images desc for from series {SeriesInstanceUid}", ser.SeriesInstanceUid); return(new Request { Series = ser, ImagesDesc = new List <ImageDesc>() }); } }, new ExecutionDataflowBlockOptions { CancellationToken = ct, MaxDegreeOfParallelism = settings.SeriesImageSettings.MaxParallelImageQueries }); _getImage = new ActionBlock <Request[]>(async requests => { try { await GetImageAsync(requests, settings, ct, progress); } catch (Exception ex) { _logger.Error(ex, "Failed to get image"); } }, new ExecutionDataflowBlockOptions { CancellationToken = ct, MaxDegreeOfParallelism = settings.SeriesImageSettings.MaxParallelMoveRequests }); _batch = new BatchBlock <Request>(10); _getImagesDesc.LinkTo(_batch, new DataflowLinkOptions { PropagateCompletion = true }); _batch.LinkTo(_getImage, new DataflowLinkOptions { PropagateCompletion = true }); _batchTimer = new Timer(delegate { _batch.TriggerBatch(); }); _batchTimer.Change(1000, 1000); }
public static async Task GetSeriesImageAsync(GetSeriesImageRequest request, DicomSearchServiceSettings settings, CancellationToken ct) { var service = new DicomSeriesImageService(request.RaiseImageGot, settings, ct); await service.Go(request.Series, ct); }
private async Task GetImageAsync(Request[] requests, DicomSearchServiceSettings settings, CancellationToken ct, Action <Image> progress) { var requestsByDicom = new Dictionary <DicomCMoveRequest, Request>(); // filled below DicomCMoveRequest.ResponseDelegate handler = (dicomReq, dicomResp) => { if (ct.IsCancellationRequested || dicomResp.Status.State != DicomState.Success) { return; } var request = requestsByDicom[dicomReq]; var midImageDesc = request.ImagesDesc.OrderBy(id => id.InstanceNumber).ElementAt(request.ImagesDesc.Count() / 2); var image = LoadImage(midImageDesc); if (image == null) { return; } if (request.Series.Orientation == FDCSeriesOrientation.eFDC_NO_ORIENTATION && image.Orientation != FDCSeriesOrientation.eFDC_NO_ORIENTATION) { request.Series.Orientation = image.Orientation; } progress(image); }; foreach (var request in requests) { var count = request.ImagesDesc.Count(); if (count <= 0) { continue; } var midImageDesc = request.ImagesDesc.OrderBy(id => id.InstanceNumber).ElementAt(count / 2); var localImage = LoadImage(midImageDesc); if (localImage != null) { _logger.Debug("no need to get image for series {SeriesInstanceUid}, it's on the disk", midImageDesc.SeriesInstanceUid); if (request.Series.Orientation == FDCSeriesOrientation.eFDC_NO_ORIENTATION && localImage.Orientation != FDCSeriesOrientation.eFDC_NO_ORIENTATION) { request.Series.Orientation = localImage.Orientation; } progress(localImage); continue; } var dicomRequest = midImageDesc.CreateCMoveRequest(settings.DicomSettings); dicomRequest.OnResponseReceived += handler; requestsByDicom[dicomRequest] = request; } if (requestsByDicom.Count == 0) { return; } _logger.Debug("Getting mid images"); var client = settings.DicomSettings.CreateClient(); await client.AddRequestsAsync(requestsByDicom.Keys); using (var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct)) { timeoutCts.CancelAfter(settings.SeriesImageSettings.GetImageTimeoutMs * requestsByDicom.Count); await client.SendAsync(timeoutCts.Token); } }
private async Task <IEnumerable <ImageDesc> > GetImagesDescAsync(Series series, DicomSearchServiceSettings settings, CancellationToken ct) { var uid = series.SeriesInstanceUid; var max = settings.SeriesImageSettings.SeriesImageTakeImages; var result = new List <ImageDesc>(); if (ct.IsCancellationRequested) { return(result); } var request = DicomCFindRequest.CreateImageQuery(series.StudyInstanceUid, series.SeriesInstanceUid); CancellationTokenSource tooManySeriesCts = null; var cancellationLock = new object(); request.OnResponseReceived += (req, resp) => { if (ct.IsCancellationRequested || resp.Dataset == null) { return; } if (result.Count >= settings.SeriesImageSettings.SeriesImageTakeImages) { lock (cancellationLock) { if (!tooManySeriesCts.IsCancellationRequested) { tooManySeriesCts.Cancel(); } } if (tooManySeriesCts.IsCancellationRequested) { _logger.Debug("Cancelled Image query for series {Uid} after {Max}", uid, max); } return; } var imageDesc = resp.Dataset.CreateObject <ImageDesc>(); if (imageDesc == null) { _logger.Error("ImageDesc creation failed"); return; } lock (cancellationLock) { result.Add(imageDesc); } _logger.Debug("Got imageDesc for series {Uid} on image {ImageUid}. Results: {Count}", uid, imageDesc.SopInstanceUid, result.Count); }; using (tooManySeriesCts = new CancellationTokenSource()) { using (CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ct, tooManySeriesCts.Token)) { _logger.Debug("Getting images desc for series {SeriesInstanceUid}", series.SeriesInstanceUid); await DicomSearchService.FindAsync <ImageDesc>(request, settings, null, linkedCts.Token); return(result); } } }
public DicomSearchService(DicomSearchServiceSettings settings) : base(settings.BaseSettings) { _settings = settings; }