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();
            }
        }
Пример #6
0
        /// <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);
                }
            }
        }
Пример #11
0
        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];
 }