public static List<OverlayPlaneGraphic> CreateOverlayPlaneGraphics(Frame frame, OverlayPlaneModuleIod overlaysFromPresentationState) { ISopDataSource dataSource = frame.ParentImageSop.DataSource; OverlayPlaneModuleIod overlaysIod = new OverlayPlaneModuleIod(dataSource); List<OverlayPlaneGraphic> overlayPlaneGraphics = new List<OverlayPlaneGraphic>(); bool failedOverlays = false; foreach (var overlayPlane in overlaysIod) { // DICOM 2009 PS 3.3 Section C.9.3.1.1 specifies the rule: NumberOfFramesInOverlay+ImageFrameOrigin-1 must be <= NumberOfFrames if (!overlayPlane.IsValidMultiFrameOverlay(frame.ParentImageSop.NumberOfFrames)) { failedOverlays = true; Platform.Log(LogLevel.Warn, new DicomOverlayDeserializationException(overlayPlane.Group, OverlayPlaneSource.Image), "Encoding error encountered while reading overlay from image headers."); continue; } try { byte[] overlayData = dataSource.GetFrameData(frame.FrameNumber).GetNormalizedOverlayData(overlayPlane.Index + 1); overlayPlaneGraphics.Add(new OverlayPlaneGraphic(overlayPlane, overlayData, OverlayPlaneSource.Image)); // if overlay data is null, the data source failed to retrieve the overlay data for some reason, so we also treat it as an encoding error // this is different from if the overlay data is zero-length, which indicates that the retrieval succeeded, but that the overlay data for the frame is empty if (overlayData == null) throw new NullReferenceException(); } catch (Exception ex) { failedOverlays = true; Platform.Log(LogLevel.Warn, new DicomOverlayDeserializationException(overlayPlane.Group, OverlayPlaneSource.Image, ex), "Failed to load overlay from the image header."); } } if (overlaysFromPresentationState != null) { foreach (var overlayPlane in overlaysFromPresentationState) { // if overlay data is missing, treat as an encoding error if (!overlayPlane.HasOverlayData) { failedOverlays = true; Platform.Log(LogLevel.Warn, new DicomOverlayDeserializationException(overlayPlane.Group, OverlayPlaneSource.PresentationState), "Encoding error encountered while reading overlay from softcopy presentation state."); continue; } try { byte[] overlayData; // try to compute the offset in the OverlayData bit stream where we can find the overlay frame that applies to this image frame int overlayFrame, bitOffset; if (overlayPlane.TryGetRelevantOverlayFrame(frame.FrameNumber, frame.ParentImageSop.NumberOfFrames, out overlayFrame) && overlayPlane.TryComputeOverlayDataBitOffset(overlayFrame, out bitOffset)) { // offset found - unpack only that overlay frame var od = new OverlayData(bitOffset, overlayPlane.OverlayRows, overlayPlane.OverlayColumns, overlayPlane.IsBigEndianOW, overlayPlane.OverlayData); overlayData = od.Unpack(); } else { // no relevant overlay frame found - i.e. the overlay for this image frame is blank overlayData = new byte[0]; } overlayPlaneGraphics.Add(new OverlayPlaneGraphic(overlayPlane, overlayData, OverlayPlaneSource.PresentationState)); } catch (Exception ex) { failedOverlays = true; Platform.Log(LogLevel.Warn, new DicomOverlayDeserializationException(overlayPlane.Group, OverlayPlaneSource.PresentationState, ex), "Failed to load overlay from softcopy presentation state."); } } } if (failedOverlays) { // add an error graphic if any overlays are not being displayed due to deserialization errors. overlayPlaneGraphics.Add(new ErrorOverlayPlaneGraphic(SR.MessageErrorDisplayingOverlays)); } return overlayPlaneGraphics; }
/// <summary> /// Called by <see cref="StandardSopFrameData.GetNormalizedOverlayData"/> to create a new byte buffer containing normalized /// overlay pixel data for a particular overlay plane. /// </summary> /// <remarks> /// See <see cref="StandardSopFrameData.GetNormalizedOverlayData"/> for details on the expected format of the byte buffer. /// </remarks> /// <param name="overlayNumber">The 1-based overlay plane number.</param> /// <returns>A new byte buffer containing the normalized overlay pixel data.</returns> protected override byte[] CreateNormalizedOverlayData(int overlayNumber) { var overlayIndex = overlayNumber - 1; byte[] overlayData = null; // check whether or not the overlay plane exists before attempting to ascertain // whether or not the overlay is embedded in the pixel data var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); if (overlayPlaneModuleIod.HasOverlayPlane(overlayIndex)) { if (_overlayData[overlayIndex] == null) { var overlayPlane = overlayPlaneModuleIod[overlayIndex]; if (!overlayPlane.HasOverlayData) { // if the overlay is embedded, trigger retrieval of pixel data which will populate the cache for us GetNormalizedPixelData(); } else { // try to compute the offset in the OverlayData bit stream where we can find the overlay frame that applies to this image frame int overlayFrame; int bitOffset; if (overlayPlane.TryGetRelevantOverlayFrame(FrameNumber, Parent.NumberOfFrames, out overlayFrame) && overlayPlane.TryComputeOverlayDataBitOffset(overlayFrame, out bitOffset)) { // offset found - unpack only that overlay frame var od = new OverlayData(bitOffset, overlayPlane.OverlayRows, overlayPlane.OverlayColumns, overlayPlane.IsBigEndianOW, overlayPlane.OverlayData); _overlayData[overlayIndex] = od.Unpack(); } else { // no relevant overlay frame found - i.e. the overlay for this image frame is blank _overlayData[overlayIndex] = new byte[0]; } } } overlayData = _overlayData[overlayIndex]; } return overlayData; }
/// <summary> /// Called by <see cref="StandardSopFrameData.GetNormalizedOverlayData"/> to create a new byte buffer containing normalized /// overlay pixel data for a particular overlay plane. /// </summary> /// <remarks> /// See <see cref="StandardSopFrameData.GetNormalizedOverlayData"/> for details on the expected format of the byte buffer. /// </remarks> /// <param name="overlayNumber">The 1-based overlay plane number.</param> /// <returns>A new byte buffer containing the normalized overlay pixel data.</returns> protected override byte[] CreateNormalizedOverlayData(int overlayNumber) { //TODO (CR December 2010): make this a helper method somewhere, since it's now identical to the one in StreamingSopFrameData? var overlayIndex = overlayNumber - 1; byte[] overlayData = null; var clock = new CodeClock(); clock.Start(); // check whether or not the overlay plane exists before attempting to ascertain // whether or not the overlay is embedded in the pixel data var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); if (overlayPlaneModuleIod.HasOverlayPlane(overlayIndex)) { if (_overlayCache[overlayIndex] == null) { var overlayPlane = overlayPlaneModuleIod[overlayIndex]; if (!overlayPlane.HasOverlayData) { // if the overlay is embedded, trigger retrieval of pixel data which will populate the cache for us GetNormalizedPixelData(); } else { // try to compute the offset in the OverlayData bit stream where we can find the overlay frame that applies to this image frame int overlayFrame; int bitOffset; if (overlayPlane.TryGetRelevantOverlayFrame(FrameNumber, Parent.NumberOfFrames, out overlayFrame) && overlayPlane.TryComputeOverlayDataBitOffset(overlayFrame, out bitOffset)) { // offset found - unpack only that overlay frame var od = new OverlayData(bitOffset, overlayPlane.OverlayRows, overlayPlane.OverlayColumns, overlayPlane.IsBigEndianOW, overlayPlane.OverlayData); _overlayCache[overlayIndex] = od.Unpack(); } else { // no relevant overlay frame found - i.e. the overlay for this image frame is blank _overlayCache[overlayIndex] = new byte[0]; } } } overlayData = _overlayCache[overlayIndex]; } clock.Stop(); PerformanceReportBroker.PublishReport("DicomMessageSopDataSource", "CreateNormalizedOverlayData", clock.Seconds); return overlayData; }
public static void CreateSeriesGraphicsForSeg(IPresentationImage presentationImage, Seg seg, SegmentationDocument segmentationDocument, IDicomMessageSopDataSource dicomMessageSopDataSourceSop) { Platform.CheckForNullReference(presentationImage, "presentationImage"); Platform.CheckForNullReference(seg, "seg"); Platform.CheckForNullReference(segmentationDocument, "segmentationDocument"); SegmentImageData segImageData = seg.SegmentImageData; if (segImageData == null) { Platform.Log(LogLevel.Error, "Cannot create segmentation graphics when no segmentation imaging data is provided"); return; } var imageSopProvider = presentationImage as IImageSopProvider; if (imageSopProvider == null) { Platform.Log(LogLevel.Error, "Failed to populate SegFrameGraphics collection. Image is not an ImageSopProvider"); return; } DicomPixelData segmentationPixelData = DicomPixelData.CreateFrom(dicomMessageSopDataSourceSop.SourceMessage); var rawPixelData = (byte[]) dicomMessageSopDataSourceSop.SourceMessage.DataSet.GetAttribute(DicomTags.PixelData).Values; var pixelDataGetter = new Func<int, byte[]>(frameIndex => { if (segImageData.BitsStored == 1) { // Do unpacking int frameLength = segImageData.Rows* segImageData.Columns; var overlayData = new OverlayData(frameIndex*frameLength, segImageData.Rows, segImageData.Columns, false, rawPixelData); return overlayData.Unpack(); } if (segImageData.BitsStored == 8) { return segmentationPixelData.GetFrame(frameIndex); } throw new InvalidDataException( "Segmentation objects need to have BitsStored as either 1 or 8"); }); // NOTE: SegmentFrameData was already sorted foreach (SegmentFrameData segmentFrameData in segImageData.SegmentFrameData) { IPresentationImage segPresentationImage = null; // Get the presentation image if we have an image reference string referencedSopInstanceUid = segmentFrameData.ReferencedSopInstanceUid; int referencedImageFrameNumber = segmentFrameData.ReferencedFrameNumber ?? 1; if (!string.IsNullOrEmpty(referencedSopInstanceUid)) { segPresentationImage = presentationImage.ParentDisplaySet.PresentationImages.OfType<IImageSopProvider>() .FirstOrDefault(curImageSopProvider => curImageSopProvider != null && curImageSopProvider.ImageSop.SopInstanceUid == referencedSopInstanceUid && curImageSopProvider.Frame.FrameNumber == referencedImageFrameNumber) as IPresentationImage; } // Location defaults to 0, 0 unless determined otherwise from image position and image orientation var segLocation = new PointF(); // Get the presentation image from the image position and orientation if (segmentFrameData.ImagePositionPatient != null && segmentFrameData.ImagePositionPatient.Count() > 2 && segmentFrameData.ImageOrientationPatient != null && segmentFrameData.ImageOrientationPatient.Count() > 5) { var imagePositionPatient = new ImagePositionPatient( segmentFrameData.ImagePositionPatient[0], segmentFrameData.ImagePositionPatient[1], segmentFrameData.ImagePositionPatient[2]); var imageOrientationPatient = new ImageOrientationPatient( segmentFrameData.ImageOrientationPatient[0], segmentFrameData.ImageOrientationPatient[1], segmentFrameData.ImageOrientationPatient[2], segmentFrameData.ImageOrientationPatient[3], segmentFrameData.ImageOrientationPatient[4], segmentFrameData.ImageOrientationPatient[5]); IDisplaySet displaySet = presentationImage.ParentDisplaySet; if (segPresentationImage == null) { segPresentationImage = PresentationImageFromPositionOrientation( imagePositionPatient, imageOrientationPatient, displaySet, segImageData.FrameOfReferenceUid); } var imageSop = segPresentationImage as IImageSopProvider; if (imageSop != null) { Vector3D segImageLocation = imageSop.Frame.ImagePlaneHelper.ConvertToImagePlane(new Vector3D( (float) imagePositionPatient.X, (float) imagePositionPatient.Y, (float) imagePositionPatient.Z)); PointF? segPixelLocation = imageSop.Frame.ImagePlaneHelper.ConvertToImage( new PointF(segImageLocation.X, segImageLocation.Y)); if (segPixelLocation.HasValue) segLocation = segPixelLocation.Value; } } if (segPresentationImage != null) { SegFrameImageGraphic newGraphic = AddSegFrameImageGraphicToPresentationImage( segPresentationImage, segImageData.Rows, segImageData.Columns, segLocation.X, segLocation.Y, seg.Color, referencedImageFrameNumber, seg.Label, seg.Description, pixelDataGetter.Invoke(segmentFrameData.FrameNumber - 1), new SegmentationDocumentReference(segmentationDocument, seg.SegmentationNumber)); if (newGraphic != null && segPresentationImage == segPresentationImage.ParentDisplaySet.ImageBox.TopLeftPresentationImage) { newGraphic.Draw(); } } else { Platform.Log(LogLevel.Error, "Failed to find Presentation Image to display a segment on"); } } }