protected override void PerformSerialization(IList <IPresentationImage> images) { DicomPresentationImageCollection <T> imageCollection = new DicomPresentationImageCollection <T>(images.OfType <T>()); if (imageCollection.Count == 0) { return; } PerformTypeSpecificSerialization(imageCollection); }
protected override sealed void PerformDeserialization(IList <IPresentationImage> images) { foreach (PresentationStateRelationshipModuleIod psRelationship in this.RelationshipSets) { SeriesReferenceDictionary dictionary = new SeriesReferenceDictionary(psRelationship.ReferencedSeriesSequence); DicomPresentationImageCollection <T> imageCollection = new DicomPresentationImageCollection <T>(images.OfType <T>().Where(img => dictionary.ReferencesFrame(img.ImageSop.SeriesInstanceUid, img.ImageSop.SopInstanceUid, img.Frame.FrameNumber))); this.PerformTypeSpecificDeserialization(imageCollection); } }
protected override void PerformTypeSpecificDeserialization(DicomPresentationImageCollection <DicomColorPresentationImage> images) { ColorSoftcopyPresentationStateIod iod = new ColorSoftcopyPresentationStateIod(base.DataSet); foreach (DicomColorPresentationImage image in images) { RectangleF displayedArea; this.DeserializeSpatialTransform(iod.SpatialTransform, image); this.DeserializeDisplayedArea(iod.DisplayedArea, out displayedArea, image); this.DeserializeGraphicLayer(iod.GraphicLayer, image); this.DeserializeGraphicAnnotation(iod.GraphicAnnotation, displayedArea, image); this.DeserializeOverlayPlane(iod.OverlayPlane, image); this.DeserializeOverlayActivation(iod.OverlayActivation, image); this.DeserializeBitmapDisplayShutter(iod.BitmapDisplayShutter, image); this.DeserializeDisplayShutter(iod.DisplayShutter, image); } }
protected override void PerformTypeSpecificSerialization(DicomPresentationImageCollection <DicomColorPresentationImage> images) { IOverlayMapping overlayMapping; ColorSoftcopyPresentationStateIod iod = new ColorSoftcopyPresentationStateIod(base.DataSet); this.SerializePresentationStateRelationship(iod.PresentationStateRelationship, images); this.SerializePresentationStateShutter(iod.PresentationStateShutter); this.SerializeDisplayShutter(iod.DisplayShutter, images); this.SerializeOverlayPlane(iod.OverlayPlane, out overlayMapping, images); this.SerializeOverlayActivation(iod.OverlayActivation, overlayMapping, images); this.SerializeBitmapDisplayShutter(iod.BitmapDisplayShutter, overlayMapping, images); this.SerializeDisplayedArea(iod.DisplayedArea, images); this.SerializeGraphicAnnotation(iod.GraphicAnnotation, images); this.SerializeSpatialTransform(iod.SpatialTransform, images); this.SerializeGraphicLayer(iod.GraphicLayer, images); this.SerializeIccProfile(iod.IccProfile); }
protected override sealed void PerformDeserialization(IList <IPresentationImage> images) { DicomPresentationImageCollection <T> imageCollection; if (!DeserializeIgnoreImageRelationship) { imageCollection = new DicomPresentationImageCollection <T>( RelationshipSets.Select(s => new SeriesReferenceDictionary(s.ReferencedSeriesSequence)) .Aggregate(Enumerable.Empty <T>(), (set, rel) => set.Union(images.OfType <T>() .Where(img => rel.ReferencesFrame(img.ImageSop.SeriesInstanceUid, img.ImageSop.SopInstanceUid, img.Frame.FrameNumber))))); } else { imageCollection = new DicomPresentationImageCollection <T>(images.OfType <T>()); } PerformTypeSpecificDeserialization(imageCollection); }
protected void SerializeSoftcopyVoiLut(SoftcopyVoiLutModuleIod module, DicomPresentationImageCollection <T> images) { List <SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem> voiLutSequenceItems = new List <SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem>(); foreach (T image in images) { if (!image.VoiLutManager.Enabled) { continue; } SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem sequenceItem = new SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem(); sequenceItem.InitializeAttributes(); sequenceItem.ReferencedImageSequence = new ImageSopInstanceReferenceMacro[] { CreateImageSopInstanceReference(image.Frame) }; IVoiLut lut = image.VoiLutManager.VoiLut; if (lut is IDataLut) { IDataLut voiLut = (IDataLut)lut; sequenceItem.VoiLutSequence = new VoiLutSequenceItem[] { SerializeDataLut(voiLut) }; } else if (lut is IVoiLutLinear) { IVoiLutLinear voiLut = (IVoiLutLinear)lut; sequenceItem.WindowWidth = new double[] { voiLut.WindowWidth }; sequenceItem.WindowCenter = new double[] { voiLut.WindowCenter }; sequenceItem.WindowCenterWidthExplanation = new string[] { SR.LabelPresentationVoiLinearLut }; sequenceItem.VoiLutFunction = VoiLutFunction.Linear; // we don't support sigmoid } else { // should never happen - all VOI LUT object should implement either interface continue; } voiLutSequenceItems.Add(sequenceItem); } if (voiLutSequenceItems.Count > 0) { module.SoftcopyVoiLutSequence = voiLutSequenceItems.ToArray(); } }
protected override void PerformTypeSpecificSerialization(DicomPresentationImageCollection <DicomGrayscalePresentationImage> images) { IOverlayMapping overlayMapping; GrayscaleSoftcopyPresentationStateIod iod = new GrayscaleSoftcopyPresentationStateIod(base.DataSet); this.SerializePresentationStateRelationship(iod.PresentationStateRelationship, images); this.SerializePresentationStateShutter(iod.PresentationStateShutter); this.SerializePresentationStateMask(iod.PresentationStateMask, images); this.SerializeMask(iod.Mask, images); this.SerializeDisplayShutter(iod.DisplayShutter, images); this.SerializeOverlayPlane(iod.OverlayPlane, out overlayMapping, images); this.SerializeOverlayActivation(iod.OverlayActivation, overlayMapping, images); this.SerializeBitmapDisplayShutter(iod.BitmapDisplayShutter, overlayMapping, images); this.SerializeDisplayedArea(iod.DisplayedArea, images); this.SerializeGraphicAnnotation(iod.GraphicAnnotation, images); this.SerializeSpatialTransform(iod.SpatialTransform, images); this.SerializeGraphicLayer(iod.GraphicLayer, images); this.SerializeModalityLut(iod.ModalityLut, images); this.SerializeSoftcopyVoiLut(iod.SoftcopyVoiLut, images); this.SerializeSoftcopyPresentationLut(iod.SoftcopyPresentationLut, images); }
protected void SerializeDisplayedArea(DisplayedAreaModuleIod displayedAreaModule, DicomPresentationImageCollection <T> images) { displayedAreaModule.InitializeAttributes(); List <DisplayedAreaModuleIod.DisplayedAreaSelectionSequenceItem> displayedAreas = new List <DisplayedAreaModuleIod.DisplayedAreaSelectionSequenceItem>(); foreach (T image in images) { DisplayedAreaModuleIod.DisplayedAreaSelectionSequenceItem displayedArea = new DisplayedAreaModuleIod.DisplayedAreaSelectionSequenceItem(); displayedArea.InitializeAttributes(); displayedArea.ReferencedImageSequence = new[] { CreateImageSopInstanceReference(image.Frame) }; ImageGraphic imageGraphic = ((IImageGraphicProvider)image).ImageGraphic; Size imageSize = new Size(imageGraphic.Columns, imageGraphic.Rows); // compute the visible area of the image as a rectangle oriented positively in screen space RectangleF visibleImageArea = imageGraphic.SpatialTransform.ConvertToSource(image.ClientRectangle); visibleImageArea = RectangleUtilities.ConvertToPositiveRectangle(visibleImageArea); visibleImageArea = RectangleUtilities.RoundInflate(visibleImageArea); visibleImageArea = RectangleUtilities.Intersect(visibleImageArea, new Rectangle(new Point(0, 0), imageSize)); // compute the pixel addresses of the visible area by intersecting area with actual pixel addresses available Rectangle visiblePixels = ConvertToPixelAddressRectangle(Rectangle.Truncate(visibleImageArea)); displayedArea.DisplayedAreaTopLeftHandCorner = visiblePixels.Location; displayedArea.DisplayedAreaBottomRightHandCorner = visiblePixels.Location + visiblePixels.Size; ISpatialTransform spatialTransform = image.SpatialTransform; switch (_displayAreaSerializationOption) { case DisplayAreaSerializationOption.SerializeAsMagnification: displayedArea.PresentationSizeMode = DisplayedAreaModuleIod.PresentationSizeMode.Magnify; displayedArea.PresentationPixelMagnificationRatio = spatialTransform.Scale; break; case DisplayAreaSerializationOption.SerializeAsTrueSize: displayedArea.PresentationSizeMode = DisplayedAreaModuleIod.PresentationSizeMode.TrueSize; displayedArea.PresentationPixelSpacing = image.Frame.NormalizedPixelSpacing; break; case DisplayAreaSerializationOption.SerializeAsDisplayedArea: default: displayedArea.PresentationSizeMode = DisplayedAreaModuleIod.PresentationSizeMode.ScaleToFit; break; } displayedArea.PresentationPixelAspectRatio = PixelAspectRatio.FromString(image.Frame.NormalizedPixelSpacing.GetPixelAspectRatioString()); displayedAreas.Add(displayedArea); } displayedAreaModule.DisplayedAreaSelectionSequence = displayedAreas.ToArray(); }
protected void SerializeOverlayActivation(OverlayActivationModuleIod overlayActivationModule, 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 for (int n = 0; n < 16; n++) { OverlayPlaneGraphic overlay = overlayMapping[n]; if (overlay != null) { if (overlay.ParentGraphic is ILayer) { overlayActivationModule[n].OverlayActivationLayer = ((ILayer)overlay.ParentGraphic).Id; } else { overlayActivationModule.Delete(n); } } } }
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 SerializeBitmapDisplayShutter(BitmapDisplayShutterModuleIod bitmapDisplayShutterModule, 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 for (int n = 0; n < 16; n++) { OverlayPlaneGraphic overlay = overlayMapping[n]; if (overlay != null) { if (overlay.ParentGraphic is IDicomGraphicsPlaneShutters) { bitmapDisplayShutterModule.ShutterShape = ShutterShape.Bitmap; bitmapDisplayShutterModule.ShutterOverlayGroupIndex = n; bitmapDisplayShutterModule.ShutterPresentationValue = overlay.GrayPresentationValue; bitmapDisplayShutterModule.ShutterPresentationColorCielabValue = null; break; // there can only be one } } } }
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."); } }
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 SerializePresentationStateMask(PresentationStateMaskModuleIod module, DicomPresentationImageCollection <T> images) { // NOTE: Not supported module.InitializeAttributes(); }
protected void SerializePresentationStateRelationship(PresentationStateRelationshipModuleIod presentationStateRelationshipModule, DicomPresentationImageCollection <T> images) { presentationStateRelationshipModule.InitializeAttributes(); List <IReferencedSeriesSequence> seriesReferences = new List <IReferencedSeriesSequence>(); foreach (string seriesUid in images.EnumerateSeries()) { IReferencedSeriesSequence seriesReference = presentationStateRelationshipModule.CreateReferencedSeriesSequence(); seriesReference.SeriesInstanceUid = seriesUid; List <ImageSopInstanceReferenceMacro> imageReferences = new List <ImageSopInstanceReferenceMacro>(); foreach (T image in images.EnumerateImages(seriesUid)) { imageReferences.Add(CreateImageSopInstanceReference(image.Frame)); } seriesReference.ReferencedImageSequence = imageReferences.ToArray(); seriesReferences.Add(seriesReference); } presentationStateRelationshipModule.ReferencedSeriesSequence = seriesReferences.ToArray(); }
protected void SerializeModalityLut(ModalityLutModuleIod module, DicomPresentationImageCollection <T> images) { }
protected void SerializeMask(MaskModuleIod module, DicomPresentationImageCollection <T> images) { // NOTE: Not supported }
protected abstract void PerformTypeSpecificDeserialization(DicomPresentationImageCollection <T> images);
protected void SerializeSpatialTransform(SpatialTransformModuleIod spatialTransformModule, DicomPresentationImageCollection <T> images) { foreach (T image in images) { // spatial transform defines rotation in cartesian space - dicom module defines rotation as clockwise in image space // spatial transform defines both horizontal and vertical flip - dicom module defines horizontal flip only (vertical flip is 180 rotation plus horizontal flip) ISpatialTransform spatialTransform = image.SpatialTransform; int rotationBy90 = (((spatialTransform.RotationXY % 360) + 360) % 360) / 90; int flipState = (spatialTransform.FlipX ? 2 : 0) + (spatialTransform.FlipY ? 1 : 0); spatialTransformModule.ImageRotation = _spatialTransformRotationTranslation[rotationBy90 + 4 * flipState]; spatialTransformModule.ImageHorizontalFlip = spatialTransform.FlipY ^ spatialTransform.FlipX ? ImageHorizontalFlip.Y : ImageHorizontalFlip.N; break; } }
/// <summary> /// Serializes the Softcopy Presentation LUT IOD module (DICOM PS 3.3, C.11.6) /// </summary> /// <param name="module">The IOD module.</param> /// <param name="images">The images to be serialized.</param> private void SerializeSoftcopyPresentationLut(SoftcopyPresentationLutModuleIod module, DicomPresentationImageCollection <DicomGrayscalePresentationImage> images) { var inverted = false; if (images.Count > 0) { inverted = images.FirstImage.VoiLutManager.Invert; // if more than one image is being serialized in the same presentation state, and they have different inversion states, then just don't invert any of them foreach (var image in images) { if (inverted != image.VoiLutManager.Invert) { inverted = false; break; } } } module.InitializeAttributes(); module.PresentationLutShape = !inverted ? PresentationLutShape.Identity : PresentationLutShape.Inverse; }
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(); } }