protected void DeserializeGraphicLayer(GraphicLayerModuleIod module, T image) { GraphicLayerSequenceItem[] layerSequences = module.GraphicLayerSequence; if (layerSequences == null) { return; } SortedDictionary <int, GraphicLayerSequenceItem> orderedSequences = new SortedDictionary <int, GraphicLayerSequenceItem>(); foreach (GraphicLayerSequenceItem sequenceItem in layerSequences) { orderedSequences.Add(sequenceItem.GraphicLayerOrder, sequenceItem); } DicomGraphicsPlane graphic = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); foreach (GraphicLayerSequenceItem sequenceItem in orderedSequences.Values) { ILayer layer = graphic.Layers[sequenceItem.GraphicLayer]; layer.Description = sequenceItem.GraphicLayerDescription; // we don't support sequenceItem.GraphicLayerRecommendedDisplayCielabValue // we don't support sequenceItem.GraphicLayerRecommendedDisplayGrayscaleValue } }
/// <summary> /// Deserializes the specified bitmap display shutter module. /// </summary> /// <remarks> /// This method must be called after <see cref="DeserializeOverlayPlane">the overlay planes have been deserialized</see>. /// </remarks> /// <param name="bitmapDisplayShutterModule"></param> /// <param name="image"></param> protected void DeserializeBitmapDisplayShutter(BitmapDisplayShutterModuleIod bitmapDisplayShutterModule, T image) { if (!_overlayPlanesDeserialized) { throw new InvalidOperationException("Overlay planes must be deserialized first."); } if (bitmapDisplayShutterModule.ShutterShape == ShutterShape.Bitmap) { DicomGraphicsPlane dicomGraphicsPlane = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); int overlayIndex = bitmapDisplayShutterModule.ShutterOverlayGroupIndex; if (overlayIndex >= 0 && overlayIndex < 16) { IShutterGraphic shutter = null; if (dicomGraphicsPlane.PresentationOverlays.Contains(overlayIndex)) { shutter = dicomGraphicsPlane.PresentationOverlays[overlayIndex]; dicomGraphicsPlane.PresentationOverlays.ActivateAsShutter(overlayIndex); dicomGraphicsPlane.ImageOverlays.Deactivate(overlayIndex); } else if (dicomGraphicsPlane.ImageOverlays.Contains(overlayIndex)) { shutter = dicomGraphicsPlane.ImageOverlays[overlayIndex]; dicomGraphicsPlane.ImageOverlays.ActivateAsShutter(overlayIndex); } // Some day, we will properly deserialize CIELab colours - until then, handle only a specified presentation value if (shutter != null) { shutter.PresentationColor = Color.Empty; shutter.PresentationValue = bitmapDisplayShutterModule.ShutterPresentationValue ?? 0; } } } }
protected void DeserializeDisplayShutter(DisplayShutterModuleIod displayShutterModule, T image) { ShutterShape shape = displayShutterModule.ShutterShape; if (shape != ShutterShape.Bitmap && shape != ShutterShape.None) { IShutterGraphic shutter = DicomGraphicsFactory.CreateGeometricShuttersGraphic(displayShutterModule, image.Frame.Rows, image.Frame.Columns); // Some day, we will properly deserialize CIELab colours - until then, leave PresentationColor default black DicomGraphicsPlane dicomGraphicsPlane = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); dicomGraphicsPlane.Shutters.Add(shutter); dicomGraphicsPlane.Shutters.Activate(shutter); } }
/// <summary> /// Deserializes the specified overlay activation module. /// </summary> /// <remarks> /// This method must be called after <see cref="DeserializeOverlayPlane">the overlay planes have been deserialized</see>. /// </remarks> /// <param name="overlayActivationModule"></param> /// <param name="image"></param> protected void DeserializeOverlayActivation(OverlayActivationModuleIod overlayActivationModule, T image) { if (!_overlayPlanesDeserialized) { throw new InvalidOperationException("Overlay planes must be deserialized first."); } DicomGraphicsPlane dicomGraphicsPlane = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); for (int n = 0; n < 16; n++) { if (overlayActivationModule.HasOverlayActivationLayer(n)) { string targetLayer = overlayActivationModule[n].OverlayActivationLayer ?? string.Empty; if (dicomGraphicsPlane.PresentationOverlays.Contains(n)) { if (string.IsNullOrEmpty(targetLayer)) { dicomGraphicsPlane.PresentationOverlays.Deactivate(n); } else { dicomGraphicsPlane.PresentationOverlays.ActivateAsLayer(n, targetLayer); } dicomGraphicsPlane.ImageOverlays.Deactivate(n); } else if (dicomGraphicsPlane.ImageOverlays.Contains(n)) { if (string.IsNullOrEmpty(targetLayer)) { dicomGraphicsPlane.ImageOverlays.Deactivate(n); } else { dicomGraphicsPlane.ImageOverlays.ActivateAsLayer(n, targetLayer); } } } else { // if the module is missing entirely, then the presentation state is poorly encoded. // for patient safety reasons, we override the DICOM stipulation that only one of // these two should be shown and show both instead. dicomGraphicsPlane.PresentationOverlays.ActivateAsLayer(n, "OVERLAY"); dicomGraphicsPlane.ImageOverlays.ActivateAsLayer(n, "OVERLAY"); } } }
protected void SerializeGraphicLayer(GraphicLayerModuleIod graphicLayerModule, DicomPresentationImageCollection <T> images) { Dictionary <string, string> layerIndex = new Dictionary <string, string>(); List <GraphicLayerSequenceItem> layerSequences = new List <GraphicLayerSequenceItem>(); int order = 1; foreach (T image in images) { DicomGraphicsPlane psGraphic = DicomGraphicsPlane.GetDicomGraphicsPlane(image, false); if (psGraphic != null) { foreach (ILayer layerGraphic in (IEnumerable <ILayer>)psGraphic.Layers) { // do not serialize the inactive layer, and do not serialize layers more than once if (!string.IsNullOrEmpty(layerGraphic.Id) && !layerIndex.ContainsKey(layerGraphic.Id)) { GraphicLayerSequenceItem layerSequence = new GraphicLayerSequenceItem(); layerSequence.GraphicLayer = layerGraphic.Id.ToUpperInvariant(); layerSequence.GraphicLayerDescription = layerGraphic.Description; layerSequence.GraphicLayerOrder = order++; layerSequence.GraphicLayerRecommendedDisplayCielabValue = null; layerSequence.GraphicLayerRecommendedDisplayGrayscaleValue = null; layerSequences.Add(layerSequence); layerIndex.Add(layerGraphic.Id, null); } } } if (image.OverlayGraphics.Count > 0) { if (!layerIndex.ContainsKey(_annotationsLayerId)) { layerIndex.Add(_annotationsLayerId, null); GraphicLayerSequenceItem layerSequence = new GraphicLayerSequenceItem(); layerSequence.GraphicLayer = _annotationsLayerId; layerSequence.GraphicLayerOrder = order++; layerSequences.Add(layerSequence); break; } } } if (layerSequences.Count > 0) { graphicLayerModule.GraphicLayerSequence = layerSequences.ToArray(); } }
/// <summary> /// Gets the DICOM graphics plane of the specified DICOM presentation image. /// </summary> /// <param name="dicomPresentationImage">The target DICOM presentation image.</param> /// <param name="createIfNecessary">A value indicating if a DICOM graphics plane should be automatically created and associated with the presentation image.</param> /// <returns>The DICOM graphics plane associated with the specified presentation image, or null if one doesn't exist and was not created.</returns> public static DicomGraphicsPlane GetDicomGraphicsPlane(IDicomPresentationImage dicomPresentationImage, bool createIfNecessary) { if (dicomPresentationImage == null) { return(null); } GraphicCollection dicomGraphics = dicomPresentationImage.DicomGraphics; DicomGraphicsPlane dicomGraphicsPlane = dicomGraphics.FirstOrDefault(IsType <DicomGraphicsPlane>) as DicomGraphicsPlane; if (dicomGraphicsPlane == null && createIfNecessary) { dicomGraphics.Add(dicomGraphicsPlane = new DicomGraphicsPlane()); } return(dicomGraphicsPlane); }
protected void SerializeGraphicAnnotation(GraphicAnnotationModuleIod graphicAnnotationModule, DicomPresentationImageCollection <T> images) { List <GraphicAnnotationSequenceItem> annotations = new List <GraphicAnnotationSequenceItem>(); foreach (T image in images) { DicomGraphicsPlane psGraphic = DicomGraphicsPlane.GetDicomGraphicsPlane(image, false); if (psGraphic != null) { foreach (ILayer layerGraphic in (IEnumerable <ILayer>)psGraphic.Layers) { foreach (IGraphic graphic in layerGraphic.Graphics) { GraphicAnnotationSequenceItem annotation = new GraphicAnnotationSequenceItem(); if (GraphicAnnotationSerializer.SerializeGraphic(graphic, annotation) && AnyContent(annotation)) { SetAllSpecificCharacterSets(annotation, DataSet.SpecificCharacterSet); annotation.GraphicLayer = layerGraphic.Id.ToUpperInvariant(); annotation.ReferencedImageSequence = new[] { CreateImageSopInstanceReference(image.Frame) }; annotations.Add(annotation); } } } } foreach (IGraphic graphic in image.OverlayGraphics) { GraphicAnnotationSequenceItem annotation = new GraphicAnnotationSequenceItem(); if (GraphicAnnotationSerializer.SerializeGraphic(graphic, annotation) && AnyContent(annotation)) { SetAllSpecificCharacterSets(annotation, DataSet.SpecificCharacterSet); annotation.GraphicLayer = _annotationsLayerId; annotation.ReferencedImageSequence = new[] { CreateImageSopInstanceReference(image.Frame) }; annotations.Add(annotation); } } } if (annotations.Count > 0) { graphicAnnotationModule.GraphicAnnotationSequence = annotations.ToArray(); } }
protected void DeserializeGraphicAnnotation(GraphicAnnotationModuleIod module, RectangleF displayedArea, T image) { DicomGraphicsPlane graphic = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); var sqItems = module.GraphicAnnotationSequence; if (sqItems != null) { foreach (var annotation in sqItems.Select(sqItem => new { LayerId = sqItem.GraphicLayer ?? string.Empty, Graphic = DicomGraphicsFactory.CreateGraphicAnnotation(image.Frame, sqItem, displayedArea, DeserializeInteractiveAnnotations) }).Where(g => g.Graphic != null)) { graphic.Layers[annotation.LayerId].Graphics.Add(annotation.Graphic); } } }
protected void DeserializeOverlayPlane(OverlayPlaneModuleIod overlayPlaneModule, T image) { DicomGraphicsPlane dicomGraphicsPlane = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); foreach (OverlayPlaneGraphic overlay in DicomGraphicsFactory.CreateOverlayPlaneGraphics(image.Frame, overlayPlaneModule)) { // the results are a mix of overlays from the image itself and the presentation state if (overlay.Source == OverlayPlaneSource.Image) { dicomGraphicsPlane.ImageOverlays.Add(overlay); } else { dicomGraphicsPlane.PresentationOverlays.Add(overlay); } // the above lines will automatically add the overlays to the inactive layer } _overlayPlanesDeserialized = true; }
protected void DeserializeGraphicAnnotation(GraphicAnnotationModuleIod module, RectangleF displayedArea, T image) { DicomGraphicsPlane graphic = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); var sqItems = module.GraphicAnnotationSequence; if (sqItems != null) { var interactiveAnnotations = DeserializeOptions.HasFlag(DicomSoftcopyPresentationStateDeserializeOptions.InteractiveAnnotations); var ignoreImageRelationships = DeserializeIgnoreImageRelationship; foreach (var annotation in sqItems.Select(sqItem => new { LayerId = sqItem.GraphicLayer ?? string.Empty, Graphic = DicomGraphicsFactory.CreateGraphicAnnotation(image.Frame, sqItem, displayedArea, interactiveAnnotations, ignoreImageRelationships) }).Where(g => g.Graphic != null)) { graphic.Layers[annotation.LayerId].Graphics.Add(annotation.Graphic); } } }
private static void DeserializeHeader(IDicomPresentationImage image) { bool anyFailures = false; DicomGraphicsPlane dicomGraphicsPlane = DicomGraphicsPlane.GetDicomGraphicsPlane(image, true); if (dicomGraphicsPlane == null) { throw new DicomGraphicsDeserializationException("Unknown exception."); } // Check if the image header specifies a bitmap display shutter BitmapDisplayShutterModuleIod bitmapShutterIod = new BitmapDisplayShutterModuleIod(image.ImageSop.DataSource); int bitmapShutterIndex = -1; if (bitmapShutterIod.ShutterShape == ShutterShape.Bitmap) { bitmapShutterIndex = bitmapShutterIod.ShutterOverlayGroupIndex; } if (bitmapShutterIndex < 0 || bitmapShutterIndex > 15) { bitmapShutterIndex = -1; } try { GeometricShuttersGraphic geometricShuttersGraphic = DicomGraphicsFactory.CreateGeometricShuttersGraphic(image.Frame); dicomGraphicsPlane.Shutters.Add(geometricShuttersGraphic); } catch (Exception e) { anyFailures = true; Platform.Log(LogLevel.Warn, e, "An error occurred trying to create geometric shutter graphics from the image header."); } try { List <OverlayPlaneGraphic> overlayPlaneGraphics = DicomGraphicsFactory.CreateOverlayPlaneGraphics(image.Frame); foreach (OverlayPlaneGraphic overlay in overlayPlaneGraphics) { if (bitmapShutterIndex != -1 && overlay.Index == bitmapShutterIndex) { // Someday when we support CIELab colour, we should set presentation value/colour based on client display type if (bitmapShutterIod.ShutterPresentationValue != null) { overlay.GrayPresentationValue = (ushort)bitmapShutterIod.ShutterPresentationValue; } overlay.Color = null; // insert the bitmap shutter into the shutters graphic instead of with the other overlays dicomGraphicsPlane.Shutters.Add(overlay); } else if (overlay.Index >= 0 && overlay.Index < 16) { // otherwise just add the overlay to the default layer for overlays and activate immediately dicomGraphicsPlane.ImageOverlays.Add(overlay); dicomGraphicsPlane.ImageOverlays.ActivateAsLayer(overlay, "OVERLAY"); } else { // otherwise just add the overlay to the default layer for overlays and activate immediately dicomGraphicsPlane.UserOverlays.Add(overlay); dicomGraphicsPlane.UserOverlays.ActivateAsLayer(overlay, "OVERLAY"); } } } catch (Exception e) { anyFailures = true; Platform.Log(LogLevel.Warn, e, "An error occurred trying to create overlay graphics from the image header."); } dicomGraphicsPlane.Shutters.ActivateFirst(); if (anyFailures) { throw new DicomGraphicsDeserializationException("At least one failure occurred in deserializing graphics from the image header."); } }
protected void SerializeOverlayPlane(OverlayPlaneModuleIod overlayPlaneModule, out IOverlayMapping overlayMapping, DicomPresentationImageCollection <T> images) { // Doesn't support multiframe or whatever case it is when we get more than one image serialized to one state List <OverlayPlaneGraphic> visibleOverlays = new List <OverlayPlaneGraphic>(); foreach (T image in images) { DicomGraphicsPlane dicomGraphics = DicomGraphicsPlane.GetDicomGraphicsPlane(image, false); if (dicomGraphics != null) { // identify visible bitmap shutter if exists OverlayPlaneGraphic bitmapShutter = dicomGraphics.Shutters.ActiveShutter as OverlayPlaneGraphic; if (bitmapShutter != null) { visibleOverlays.Add(bitmapShutter); } // identify any visible overlays visibleOverlays.AddRange(((IEnumerable <ILayer>)dicomGraphics.Layers).Where(l => l.Visible).SelectMany(l => l.Graphics).OfType <OverlayPlaneGraphic>().Where(g => g.Visible)); } } OverlayMapping overlayMap = new OverlayMapping(); Queue <OverlayPlaneGraphic> overlaysToRemap = new Queue <OverlayPlaneGraphic>(); // user and presentation state overlays are high priority items to remap foreach (OverlayPlaneGraphic overlay in CollectionUtils.Select(visibleOverlays, delegate(OverlayPlaneGraphic t) { return(t.Source != OverlayPlaneSource.Image); })) { overlaysToRemap.Enqueue(overlay); } foreach (OverlayPlaneGraphic overlay in CollectionUtils.Select(visibleOverlays, delegate(OverlayPlaneGraphic t) { return(t.Source == OverlayPlaneSource.Image); })) { if (overlayMap[overlay.Index] == null) { overlayMap[overlay.Index] = overlay; } else { overlaysToRemap.Enqueue(overlay); // image overlays are lower priority items to remap, since they will be included in the header anyway } } // seed the overlays to remap into the remaining available overlay groups for (int n = 0; n < 16 && overlaysToRemap.Count > 0; n++) { if (overlayMap[n] == null) { overlayMap[n] = overlaysToRemap.Dequeue(); } } // serialize the overlays for (int n = 0; n < 16; n++) { OverlayPlaneGraphic overlay = overlayMap[n]; if (overlay != null) { if (overlay.Source != OverlayPlaneSource.Image || overlay.Index != n) { // only record this overlay in the presentation state if it is being remapped to another group or is not already in the image. OverlayPlane overlayIod = overlayPlaneModule[n]; overlayIod.OverlayData = overlay.CreateOverlayData(overlayIod.IsBigEndianOW).Raw; overlayIod.OverlayBitPosition = 0; overlayIod.OverlayBitsAllocated = 1; overlayIod.OverlayColumns = overlay.Columns; overlayIod.OverlayDescription = overlay.Description; overlayIod.OverlayLabel = overlay.Label; overlayIod.OverlayOrigin = Point.Round(overlay.Origin); overlayIod.OverlayRows = overlay.Rows; overlayIod.OverlaySubtype = overlay.Subtype; overlayIod.OverlayType = overlay.Type; overlayIod.RoiArea = null; overlayIod.RoiMean = null; overlayIod.RoiStandardDeviation = null; } else { overlayPlaneModule.Delete(n); } } } if (overlaysToRemap.Count > 0) { Platform.Log(LogLevel.Warn, "Attempt to serialize presentation state with more than 16 visible overlays - some information may be lost."); } overlayMapping = overlayMap; }
protected void SerializeDisplayShutter(DisplayShutterModuleIod displayShutterModule, DicomPresentationImageCollection <T> images) { // Doesn't support multiframe or whatever case it is when we get more than one image serialized to one state CircularShutter circular = null; RectangularShutter rectangular = null; PolygonalShutter polygonal = null; int unserializedCount = 0; foreach (T image in images) { DicomGraphicsPlane dicomGraphics = DicomGraphicsPlane.GetDicomGraphicsPlane(image, false); if (dicomGraphics != null) { // identify visible geometric shutter if exists GeometricShuttersGraphic geometricShutters = dicomGraphics.Shutters.ActiveShutter as GeometricShuttersGraphic; if (geometricShutters != null) { // we can only save the first of each foreach (GeometricShutter shutter in geometricShutters.CustomShutters) { if (shutter is CircularShutter && circular == null) { circular = (CircularShutter)shutter; } else if (shutter is RectangularShutter && rectangular == null) { rectangular = (RectangularShutter)shutter; } else if (shutter is PolygonalShutter && polygonal == null) { polygonal = (PolygonalShutter)shutter; } else { unserializedCount++; } } foreach (GeometricShutter shutter in geometricShutters.DicomShutters) { if (shutter is CircularShutter && circular == null) { circular = (CircularShutter)shutter; } else if (shutter is RectangularShutter && rectangular == null) { rectangular = (RectangularShutter)shutter; } else if (shutter is PolygonalShutter && polygonal == null) { polygonal = (PolygonalShutter)shutter; } else { unserializedCount++; } } } } } ShutterShape shape = ShutterShape.None; if (circular != null) { shape |= ShutterShape.Circular; displayShutterModule.CenterOfCircularShutter = circular.Center; displayShutterModule.RadiusOfCircularShutter = circular.Radius; } if (rectangular != null) { shape |= ShutterShape.Rectangular; Rectangle r = rectangular.Rectangle; displayShutterModule.ShutterLeftVerticalEdge = r.Left; displayShutterModule.ShutterRightVerticalEdge = r.Right; displayShutterModule.ShutterUpperHorizontalEdge = r.Top; displayShutterModule.ShutterLowerHorizontalEdge = r.Bottom; } if (polygonal != null) { shape |= ShutterShape.Polygonal; List <Point> vertices = new List <Point>(); vertices.AddRange(polygonal.Vertices); displayShutterModule.VerticesOfThePolygonalShutter = vertices.ToArray(); } if (shape != ShutterShape.None) { displayShutterModule.ShutterShape = shape; displayShutterModule.ShutterPresentationValue = 0; } else { foreach (uint tag in DisplayShutterMacroIod.DefinedTags) { displayShutterModule.DicomAttributeProvider[tag] = null; } } if (unserializedCount > 0) { Platform.Log(LogLevel.Warn, "Attempt to serialize presentation state with an unsupported combination of shutters - some information may be lost."); } }
public UserOverlaysCollection(DicomGraphicsPlane owner) { _owner = owner; _overlays = new List <OverlayPlaneGraphic>(); }
public OverlaysCollection(DicomGraphicsPlane owner) { _owner = owner; _overlays = new OverlayPlaneGraphic[16]; }