protected override byte[] CreateNormalizedPixelData() { string photometricInterpretation; byte[] pixelData = _framePixelData.GetUncompressedPixelData(out photometricInterpretation); string photometricInterpretationCode = photometricInterpretation ?? Parent[DicomTags.PhotometricInterpretation].ToString(); PhotometricInterpretation pi = PhotometricInterpretation.FromCodeString(photometricInterpretationCode); if (pi.IsColor) { pixelData = ToArgb(this.Parent, pixelData, pi); } else { var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); foreach (var overlayPlane in overlayPlaneModuleIod) { if (!overlayPlane.HasOverlayData && _overlayData[overlayPlane.Index] == null) { // if the overlay is embedded in pixel data and we haven't cached it yet, extract it now before we normalize the frame pixel data var overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, Parent[DicomTags.BitsAllocated].GetInt32(0, 0), false, pixelData); _overlayData[overlayPlane.Index] = overlayData; } } NormalizeGrayscalePixels(this.Parent, pixelData); } return(pixelData); }
public void ChangeSyntax(TransferSyntax syntax) { try { if (!_dicomFile.TransferSyntax.Encapsulated) { // Check if Overlay is embedded in pixels OverlayPlaneModuleIod overlayIod = new OverlayPlaneModuleIod(_dicomFile.DataSet); for (int i = 0; i < 16; i++) { if (overlayIod.HasOverlayPlane(i)) { OverlayPlane overlay = overlayIod[i]; if (overlay.OverlayData == null) { DicomUncompressedPixelData pd = new DicomUncompressedPixelData(_dicomFile); overlay.ConvertEmbeddedOverlay(pd); } } } } else if (syntax.Encapsulated) { // Must decompress first. _dicomFile.ChangeTransferSyntax(TransferSyntax.ExplicitVrLittleEndian); } _dicomFile.ChangeTransferSyntax(syntax); } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected exception compressing/decompressing DICOM file"); } }
public void TestIsValidMultiFrameOverlay() { const int size = 3; var dataset = new DicomAttributeCollection(); SetOverlay(dataset, 0, new bool[size*size], OverlayType.R, new Point(0, 0), size, size, null, false, false); SetOverlay(dataset, 1, new bool[size*size], OverlayType.R, new Point(0, 0), size, size, 1, false, false); SetOverlay(dataset, 2, new bool[size*size*5], OverlayType.R, new Point(0, 0), size, size, 5, false, false); SetOverlay(dataset, 3, new bool[size*size], OverlayType.R, new Point(0, 0), size, size, 1, 3, false, false); SetOverlay(dataset, 4, new bool[size*size*5], OverlayType.R, new Point(0, 0), size, size, 5, 2, false, false); var module = new OverlayPlaneModuleIod(dataset); Assert.IsTrue(module[0].IsValidMultiFrameOverlay(1), "Single Frame Overlay / 1 Frame in Image"); Assert.IsTrue(module[0].IsValidMultiFrameOverlay(2), "Single Frame Overlay / 2 Frames in Image"); Assert.IsTrue(module[1].IsValidMultiFrameOverlay(1), "1 Frame in Overlay (origin null==1) / 1 Frame in Image"); Assert.IsTrue(module[1].IsValidMultiFrameOverlay(2), "1 Frame in Overlay (origin null==1) / 2 Frames in Image"); Assert.IsFalse(module[2].IsValidMultiFrameOverlay(4), "5 Frames in Overlay (origin null==1) / 4 Frames in Image"); Assert.IsTrue(module[2].IsValidMultiFrameOverlay(5), "5 Frames in Overlay (origin null==1) / 5 Frames in Image"); Assert.IsTrue(module[2].IsValidMultiFrameOverlay(6), "5 Frames in Overlay (origin null==1) / 6 Frames in Image"); Assert.IsFalse(module[3].IsValidMultiFrameOverlay(2), "1 Frames in Overlay (origin 3) / 2 Frames in Image"); Assert.IsTrue(module[3].IsValidMultiFrameOverlay(3), "1 Frames in Overlay (origin 3) / 3 Frames in Image"); Assert.IsTrue(module[3].IsValidMultiFrameOverlay(4), "1 Frames in Overlay (origin 3) / 4 Frames in Image"); Assert.IsFalse(module[4].IsValidMultiFrameOverlay(5), "5 Frames in Overlay (origin 2) / 5 Frames in Image"); Assert.IsTrue(module[4].IsValidMultiFrameOverlay(6), "5 Frames in Overlay (origin 2) / 6 Frames in Image"); Assert.IsTrue(module[4].IsValidMultiFrameOverlay(7), "5 Frames in Overlay (origin 2) / 7 Frames in Image"); }
/// <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); }
/// <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); }
private void ExtractOverlayFrames(byte[] rawPixelData, int bitsAllocated) { // if any overlays have embedded pixel data, extract them now or forever hold your peace var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); foreach (var overlayPlane in overlayPlaneModuleIod) { if (!overlayPlane.HasOverlayData && _overlayCache[overlayPlane.Index] == null) { // if the overlay is embedded in pixel data and we haven't cached it yet, extract it now before we normalize the frame pixel data var overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, bitsAllocated, false, rawPixelData); _overlayCache[overlayPlane.Index] = overlayData; } } }
public void SetupMRWithOverlay(DicomAttributeCollection theSet) { SetupMR(theSet); OverlayPlaneModuleIod overlayIod = new OverlayPlaneModuleIod(theSet); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(theSet); OverlayPlane overlay = overlayIod[0]; // Embedded overlays are retired in dicom, just doing it for testing purposes theSet[DicomTags.OverlayBitPosition].SetInt32(0, pd.HighBit + 1); overlay.OverlayBitsAllocated = 1; overlay.OverlayColumns = pd.ImageWidth; overlay.OverlayRows = pd.ImageHeight; overlay.OverlayOrigin = new Point(0, 0); overlay.OverlayType = OverlayType.R; }
public void RleOverlayTest() { DicomFile file = new DicomFile("RleCodecOverlayTest.dcm"); SetupMRWithOverlay(file.DataSet); SetupMetaInfo(file); // Save a copy file.Save(); // Load the file into new DicomFile object DicomFile newFile = new DicomFile(file.Filename); newFile.Load(); OverlayPlaneModuleIod overlayIod = new OverlayPlaneModuleIod(newFile.DataSet); OverlayPlane overlay = overlayIod[0]; // SHould be no OverlayData tag Assert.IsNull(overlay.OverlayData, "Overlay should be in pixel data"); // Overlay should be extracted out of pixel data here newFile.ChangeTransferSyntax(TransferSyntax.RleLossless); Assert.IsNotNull(overlay.OverlayData, "Overlay Data is not null"); newFile.Save(); // Load a new copy newFile = new DicomFile(file.Filename); newFile.Load(); newFile.ChangeTransferSyntax(TransferSyntax.ExplicitVrLittleEndian); newFile.Filename = "Output" + file.Filename; newFile.Save(); List <DicomAttributeComparisonResult> results = new List <DicomAttributeComparisonResult>(); bool compare = file.DataSet.Equals(newFile.DataSet, ref results); // Shouldn't be the same, OverlayData tag should have been added Assert.IsFalse(compare, results.Count > 0 ? CollectionUtils.FirstElement(results).Details : string.Empty); }
protected override byte[] CreateNormalizedPixelData() { byte[] pixelData = _framePixelData.GetUncompressedPixelData(); string photometricInterpretationCode = this.Parent[DicomTags.PhotometricInterpretation].ToString(); PhotometricInterpretation pi = PhotometricInterpretation.FromCodeString(photometricInterpretationCode); TransferSyntax ts = TransferSyntax.GetTransferSyntax(this.Parent.TransferSyntaxUid); if (pi.IsColor) { if (ts == TransferSyntax.Jpeg2000ImageCompression || ts == TransferSyntax.Jpeg2000ImageCompressionLosslessOnly || ts == TransferSyntax.JpegExtendedProcess24 || ts == TransferSyntax.JpegBaselineProcess1) { pi = PhotometricInterpretation.Rgb; } pixelData = ToArgb(this.Parent, pixelData, pi); } else { OverlayPlaneModuleIod opmi = new OverlayPlaneModuleIod(this.Parent); foreach (OverlayPlane overlayPlane in opmi) { if (IsOverlayEmbedded(overlayPlane) && _overlayData[overlayPlane.Index] == null) { byte[] overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, this.Parent[DicomTags.BitsAllocated].GetInt32(0, 0), false, pixelData); _overlayData[overlayPlane.Index] = overlayData; } else if (!overlayPlane.HasOverlayData) { Platform.Log(LogLevel.Warn, "The image {0} appears to be missing OverlayData for group 0x{1:X4}.", this.Parent.SopInstanceUid, overlayPlane.Group); } } NormalizeGrayscalePixels(this.Parent, pixelData); } return(pixelData); }
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 override byte[] CreateNormalizedPixelData() { byte[] pixelData = _framePixelData.GetUncompressedPixelData(); string photometricInterpretationCode = this.Parent[DicomTags.PhotometricInterpretation].ToString(); PhotometricInterpretation pi = PhotometricInterpretation.FromCodeString(photometricInterpretationCode); TransferSyntax ts = TransferSyntax.GetTransferSyntax(this.Parent.TransferSyntaxUid); if (pi.IsColor) { if (ts == TransferSyntax.Jpeg2000ImageCompression || ts == TransferSyntax.Jpeg2000ImageCompressionLosslessOnly || ts == TransferSyntax.JpegExtendedProcess24 || ts == TransferSyntax.JpegBaselineProcess1) { pi = PhotometricInterpretation.Rgb; } pixelData = ToArgb(this.Parent, pixelData, pi); } else { var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); foreach (var overlayPlane in overlayPlaneModuleIod) { if (!overlayPlane.HasOverlayData && _overlayData[overlayPlane.Index] == null) { // if the overlay is embedded in pixel data and we haven't cached it yet, extract it now before we normalize the frame pixel data var overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, Parent[DicomTags.BitsAllocated].GetInt32(0, 0), false, pixelData); _overlayData[overlayPlane.Index] = overlayData; } } NormalizeGrayscalePixels(this.Parent, pixelData); } return(pixelData); }
/// <summary> /// Initializes a new instance of the <see cref="ScImageIod"/> class. /// </summary> /// <param name="dicomAttributeProvider">The DICOM attribute provider.</param> public ScImageIod(IDicomAttributeProvider dicomAttributeProvider) { _dicomAttributeProvider = dicomAttributeProvider; _patientModule = new PatientModuleIod(_dicomAttributeProvider); _clinicalTrialSubjectModule = new ClinicalTrialSubjectModuleIod(_dicomAttributeProvider); _generalStudyModule = new GeneralStudyModuleIod(_dicomAttributeProvider); _patientStudyModule = new PatientStudyModuleIod(_dicomAttributeProvider); _clinicalTrialStudyModule = new ClinicalTrialStudyModuleIod(_dicomAttributeProvider); _generalSeriesModule = new GeneralSeriesModuleIod(_dicomAttributeProvider); _clinicalTrialSeriesModule = new ClinicalTrialSeriesModuleIod(_dicomAttributeProvider); _generalEquipmentModule = new GeneralEquipmentModuleIod(_dicomAttributeProvider); _scEquipmentModule = new ScEquipmentModuleIod(_dicomAttributeProvider); _generalImageModule = new GeneralImageModuleIod(_dicomAttributeProvider); _imagePixelModule = new ImagePixelMacroIod(_dicomAttributeProvider); _deviceModule = new DeviceModuleIod(_dicomAttributeProvider); _scImageModule = new ScImageModuleIod(_dicomAttributeProvider); _overlayPlaneModule = new OverlayPlaneModuleIod(_dicomAttributeProvider); _modalityLutModule = new ModalityLutModuleIod(_dicomAttributeProvider); _voiLutModule = new VoiLutModuleIod(_dicomAttributeProvider); _iccProfileModule = new IccProfileModuleIod(_dicomAttributeProvider); _sopCommonModule = new SopCommonModuleIod(_dicomAttributeProvider); }
protected override byte[] CreateNormalizedOverlayData(int overlayGroupNumber, int overlayFrameNumber) { int frameIndex = overlayFrameNumber - 1; int overlayIndex = overlayGroupNumber - 1; byte[] overlayData = null; OverlayPlaneModuleIod opmi = new OverlayPlaneModuleIod(this.Parent); if (opmi.HasOverlayPlane(overlayIndex)) { OverlayPlane overlayPlane = opmi[overlayIndex]; if (_overlayData[overlayIndex] == null) { if (IsOverlayEmbedded(overlayPlane)) { this.GetNormalizedPixelData(); } else { int bitOffset; overlayPlane.TryComputeOverlayDataBitOffset(frameIndex, out bitOffset); OverlayData od = new OverlayData(bitOffset, overlayPlane.OverlayRows, overlayPlane.OverlayColumns, overlayPlane.IsBigEndianOW, overlayPlane.OverlayData); _overlayData[overlayIndex] = od.Unpack(); } } overlayData = _overlayData[overlayIndex]; } return(overlayData); }
public void TestComputeOverlayDataBitOffset_SingleFrameEmbedded() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetImage(dataset, new byte[rows*columns*2], rows, columns, 1, 16, 12, 14, false); SetOverlay(dataset, overlayIndex, new bool[rows*columns], OverlayType.G, new Point(1, 1), 15, bigEndian); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualBitOffset; // bit offset doesn't make any sense for embedded data Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(-1, out actualBitOffset), "Should not be able to compute bit offset for frame number -1"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(0, out actualBitOffset), "Should not be able to compute bit offset for frame number 0"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(1, out actualBitOffset), "Should not be able to compute bit offset for frame number 1"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(2, out actualBitOffset), "Should not be able to compute bit offset for frame number 2"); }
/// <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; }
public void TestComputeOverlayDataBitOffset_MultiframeOverlayDataWithOrigin() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int frames = 7; // just because you're getting overlay frame #2 for image frame #4 doesn't change the offset where overlay frame #2 can be found!! const int imageFrameOrigin = 3; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetOverlay(dataset, overlayIndex, new bool[rows*columns*frames], OverlayType.G, new Point(1, 1), rows, columns, frames, imageFrameOrigin, bigEndian, false); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualBitOffset; Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(-1, out actualBitOffset), "Should not be able to compute bit offset for frame number -1"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(0, out actualBitOffset), "Should not be able to compute bit offset for frame number 0"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(8, out actualBitOffset), "Should not be able to compute bit offset for frame number 8"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(1, out actualBitOffset), "Should be able to compute bit offset for frame number 1"); Assert.AreEqual(0*rows*columns, actualBitOffset, "Wrong offset computed for frame number 1"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(2, out actualBitOffset), "Should be able to compute bit offset for frame number 2"); Assert.AreEqual(1*rows*columns, actualBitOffset, "Wrong offset computed for frame number 2"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(3, out actualBitOffset), "Should be able to compute bit offset for frame number 3"); Assert.AreEqual(2*rows*columns, actualBitOffset, "Wrong offset computed for frame number 3"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(4, out actualBitOffset), "Should be able to compute bit offset for frame number 4"); Assert.AreEqual(3*rows*columns, actualBitOffset, "Wrong offset computed for frame number 4"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(5, out actualBitOffset), "Should be able to compute bit offset for frame number 5"); Assert.AreEqual(4*rows*columns, actualBitOffset, "Wrong offset computed for frame number 5"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(6, out actualBitOffset), "Should be able to compute bit offset for frame number 6"); Assert.AreEqual(5*rows*columns, actualBitOffset, "Wrong offset computed for frame number 6"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(7, out actualBitOffset), "Should be able to compute bit offset for frame number 7"); Assert.AreEqual(6*rows*columns, actualBitOffset, "Wrong offset computed for frame number 7"); }
public void TestComputeOverlayDataBitOffset_SingleFrameOverlayData() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetOverlay(dataset, overlayIndex, new bool[rows*columns], OverlayType.G, new Point(1, 1), rows, columns, null, null, bigEndian, false); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualBitOffset; Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(-1, out actualBitOffset), "Should not be able to compute bit offset for frame number -1"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(0, out actualBitOffset), "Should not be able to compute bit offset for frame number 0"); Assert.IsFalse(overlayPlane.TryComputeOverlayDataBitOffset(2, out actualBitOffset), "Should not be able to compute bit offset for frame number 2"); Assert.IsTrue(overlayPlane.TryComputeOverlayDataBitOffset(1, out actualBitOffset), "Should be able to compute bit offset for frame number 1"); Assert.AreEqual(0, actualBitOffset, "Wrong offset computed for frame number 1"); }
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); }
public void RleOverlayTest() { DicomFile file = new DicomFile("RleCodecOverlayTest.dcm"); SetupMRWithOverlay(file.DataSet); SetupMetaInfo(file); // Save a copy file.Save(); // Load the file into new DicomFile object DicomFile newFile = new DicomFile(file.Filename); newFile.Load(); OverlayPlaneModuleIod overlayIod = new OverlayPlaneModuleIod(newFile.DataSet); OverlayPlane overlay = overlayIod[0]; // SHould be no OverlayData tag Assert.IsNull(overlay.OverlayData, "Overlay should be in pixel data"); // Overlay should be extracted out of pixel data here newFile.ChangeTransferSyntax(TransferSyntax.RleLossless); Assert.IsNotNull(overlay.OverlayData,"Overlay Data is not null"); newFile.Save(); // Load a new copy newFile = new DicomFile(file.Filename); newFile.Load(); newFile.ChangeTransferSyntax(TransferSyntax.ExplicitVrLittleEndian); newFile.Filename = "Output" + file.Filename; newFile.Save(); List<DicomAttributeComparisonResult> results = new List<DicomAttributeComparisonResult>(); bool compare = file.DataSet.Equals(newFile.DataSet, ref results); // Shouldn't be the same, OverlayData tag should have been added Assert.IsFalse(compare, results.Count > 0 ? CollectionUtils.FirstElement(results).Details : string.Empty); }
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 override byte[] CreateNormalizedPixelData() { byte[] pixelData = _framePixelData.GetUncompressedPixelData(); string photometricInterpretationCode = this.Parent[DicomTags.PhotometricInterpretation].ToString(); PhotometricInterpretation pi = PhotometricInterpretation.FromCodeString(photometricInterpretationCode); TransferSyntax ts = TransferSyntax.GetTransferSyntax(this.Parent.TransferSyntaxUid); if (pi.IsColor) { if (ts == TransferSyntax.Jpeg2000ImageCompression || ts == TransferSyntax.Jpeg2000ImageCompressionLosslessOnly || ts == TransferSyntax.JpegExtendedProcess24 || ts == TransferSyntax.JpegBaselineProcess1) pi = PhotometricInterpretation.Rgb; pixelData = ToArgb(this.Parent, pixelData, pi); } else { var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); foreach (var overlayPlane in overlayPlaneModuleIod) { if (!overlayPlane.HasOverlayData && _overlayData[overlayPlane.Index] == null) { // if the overlay is embedded in pixel data and we haven't cached it yet, extract it now before we normalize the frame pixel data var overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, Parent[DicomTags.BitsAllocated].GetInt32(0, 0), false, pixelData); _overlayData[overlayPlane.Index] = overlayData; } } NormalizeGrayscalePixels(this.Parent, pixelData); } return pixelData; }
/// <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 void TestGetRelevantOverlayFrame_MultiframeEmbedded() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int frames = 7; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetImage(dataset, new byte[rows*columns*2*frames], rows, columns, frames, 16, 12, 11, false); SetOverlay(dataset, overlayIndex, new bool[rows*columns*frames], OverlayType.G, new Point(1, 1), 12, bigEndian); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualOverlayFrame; Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(-1, frames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #-1"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(0, frames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #0"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(8, frames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #8"); // all valid image frame inputs should map 1-to-1 with the same numbered overlay frame Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(1, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #1"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #1"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(2, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #2"); Assert.AreEqual(2, actualOverlayFrame, "Wrong overlay frame matched to image frame #2"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(3, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #3"); Assert.AreEqual(3, actualOverlayFrame, "Wrong overlay frame matched to image frame #3"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(4, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #4"); Assert.AreEqual(4, actualOverlayFrame, "Wrong overlay frame matched to image frame #4"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(5, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #5"); Assert.AreEqual(5, actualOverlayFrame, "Wrong overlay frame matched to image frame #5"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(6, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #6"); Assert.AreEqual(6, actualOverlayFrame, "Wrong overlay frame matched to image frame #6"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(7, frames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #7"); Assert.AreEqual(7, actualOverlayFrame, "Wrong overlay frame matched to image frame #7"); }
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; }
public void TestGetRelevantOverlayFrame_SingleFrameEmbedded() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetImage(dataset, new byte[rows*columns*2], rows, columns, 1, 16, 12, 11, false); SetOverlay(dataset, overlayIndex, new bool[rows*columns], OverlayType.G, new Point(1, 1), 12, bigEndian); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualOverlayFrame; Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(-1, 1, out actualOverlayFrame), "Should not any matching overlay frame for image frame #-1"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(0, 1, out actualOverlayFrame), "Should not any matching overlay frame for image frame #0"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(8, 1, out actualOverlayFrame), "Should not any matching overlay frame for image frame #8"); // in the single frame case, there's only one pairing Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(1, 1, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #1"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #1"); }
protected override byte[] CreateNormalizedPixelData() { string photometricInterpretation; byte[] pixelData = _framePixelData.GetUncompressedPixelData(out photometricInterpretation); string photometricInterpretationCode = photometricInterpretation ?? Parent[DicomTags.PhotometricInterpretation].ToString(); PhotometricInterpretation pi = PhotometricInterpretation.FromCodeString(photometricInterpretationCode); if (pi.IsColor) { pixelData = ToArgb(this.Parent, pixelData, pi); } else { var overlayPlaneModuleIod = new OverlayPlaneModuleIod(Parent); foreach (var overlayPlane in overlayPlaneModuleIod) { if (!overlayPlane.HasOverlayData && _overlayData[overlayPlane.Index] == null) { // if the overlay is embedded in pixel data and we haven't cached it yet, extract it now before we normalize the frame pixel data var overlayData = OverlayData.UnpackFromPixelData(overlayPlane.OverlayBitPosition, Parent[DicomTags.BitsAllocated].GetInt32(0, 0), false, pixelData); _overlayData[overlayPlane.Index] = overlayData; } } NormalizeGrayscalePixels(this.Parent, pixelData); } return pixelData; }
public void TestGetRelevantOverlayFrame_SingleFrameOverlayData() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int rows = 97; const int columns = 101; const int imageFrames = 7; const int overlayIndex = 0; var dataset = new DicomAttributeCollection(); SetOverlay(dataset, overlayIndex, new bool[rows*columns], OverlayType.G, new Point(1, 1), rows, columns, null, null, bigEndian, false); var module = new OverlayPlaneModuleIod(dataset); var overlayPlane = module[overlayIndex]; int actualOverlayFrame; Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(-1, imageFrames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #-1"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(0, imageFrames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #0"); Assert.IsFalse(overlayPlane.TryGetRelevantOverlayFrame(8, imageFrames, out actualOverlayFrame), "Should not any matching overlay frame for image frame #8"); // in the single frame case, all valid image frame inputs should map to overlay frame #1 Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(1, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #1"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #1"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(2, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #2"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #2"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(3, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #3"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #3"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(4, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #4"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #4"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(5, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #5"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #5"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(6, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #6"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #6"); Assert.IsTrue(overlayPlane.TryGetRelevantOverlayFrame(7, imageFrames, out actualOverlayFrame), "Should be able to match an overlay frame to image frame #7"); Assert.AreEqual(1, actualOverlayFrame, "Wrong overlay frame matched to image frame #7"); }
public void TestOverlayPlaneModuleIod_SingleFrame() { const bool bigEndian = false; // these parameters should be kept prime numbers so that we can exercise the overlay handling for rows/frames that cross byte boundaries const int imageRows = 97; const int imageColumns = 101; const int overlay1Rows = 103; const int overlay1Columns = 89; const int overlay2Rows = 67; const int overlay2Columns = 71; var dataset = new DicomAttributeCollection(); SetImage(dataset, new byte[imageRows*imageColumns*2], imageRows, imageColumns, 1, 16, 13, 12, false); SetOverlay(dataset, 0, new bool[overlay1Rows*overlay1Columns], OverlayType.G, new Point(1, 1), overlay1Rows, overlay1Columns, bigEndian, false); SetOverlay(dataset, 1, new bool[imageRows*imageColumns], OverlayType.G, new Point(2, 3), 15, bigEndian); SetOverlay(dataset, 2, new bool[overlay2Rows*overlay2Columns], OverlayType.R, new Point(4, 5), overlay2Rows, overlay2Columns, bigEndian, true); SetOverlay(dataset, 13, new bool[imageRows*imageColumns], OverlayType.R, new Point(6, 7), 14, bigEndian); var module = new OverlayPlaneModuleIod(dataset); // test overlay group 6000 { const int overlayIndex = 0; var overlayPlane = module[overlayIndex]; // assert overlay plane identification Assert.AreEqual(0x6000, overlayPlane.Group, "Wrong overlay group for plane #{0}", overlayIndex); Assert.AreEqual(0, overlayPlane.Index, "Wrong overlay index for plane #{0}", overlayIndex); Assert.AreEqual(0x000000, overlayPlane.TagOffset, "Wrong tag offset for plane #{0}", overlayIndex); // assert overlay plane encoding detection Assert.AreEqual(true, overlayPlane.HasOverlayData, "Incorrect OverlayData detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsBigEndianOW, "Incorrect OW/OB detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsMultiFrame, "Incorrect multiframe detection for plane #{0}", overlayIndex); Assert.AreEqual(103*89, overlayPlane.GetOverlayFrameLength(), "Incorrect frame size computation for plane #{0}", overlayIndex); // assert overlay plane basic attribute values Assert.AreEqual(103, overlayPlane.OverlayRows, "Wrong overlay rows for plane #{0}", overlayIndex); Assert.AreEqual(89, overlayPlane.OverlayColumns, "Wrong overlay columns for plane #{0}", overlayIndex); Assert.AreEqual(0, overlayPlane.OverlayBitPosition, "Wrong overlay bit position for plane #{0}", overlayIndex); Assert.AreEqual(1, overlayPlane.OverlayBitsAllocated, "Wrong overlay bits allocated for plane #{0}", overlayIndex); Assert.AreEqual(OverlayType.G, overlayPlane.OverlayType, "Wrong overlay type for plane #{0}", overlayIndex); Assert.AreEqual(new Point(1, 1), overlayPlane.OverlayOrigin, "Wrong overlay origin for plane #{0}", overlayIndex); // assert overlay plane multiframe attribute values Assert.AreEqual(null, overlayPlane.ImageFrameOrigin, "Wrong image frame origin for plane #{0}", overlayIndex); Assert.AreEqual(null, overlayPlane.NumberOfFramesInOverlay, "Wrong number of frames in overlay for plane #{0}", overlayIndex); } // test overlay group 6002 { const int overlayIndex = 1; var overlayPlane = module[overlayIndex]; // assert overlay plane identification Assert.AreEqual(0x6002, overlayPlane.Group, "Wrong overlay group for plane #{0}", overlayIndex); Assert.AreEqual(1, overlayPlane.Index, "Wrong overlay index for plane #{0}", overlayIndex); Assert.AreEqual(0x020000, overlayPlane.TagOffset, "Wrong tag offset for plane #{0}", overlayIndex); // assert overlay plane encoding detection Assert.AreEqual(false, overlayPlane.HasOverlayData, "Incorrect OverlayData detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsBigEndianOW, "Incorrect OW/OB detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsMultiFrame, "Incorrect multiframe detection for plane #{0}", overlayIndex); Assert.AreEqual(97*101, overlayPlane.GetOverlayFrameLength(), "Incorrect frame size computation for plane #{0}", overlayIndex); // assert overlay plane basic attribute values Assert.AreEqual(97, overlayPlane.OverlayRows, "Wrong overlay rows for plane #{0}", overlayIndex); Assert.AreEqual(101, overlayPlane.OverlayColumns, "Wrong overlay columns for plane #{0}", overlayIndex); Assert.AreEqual(15, overlayPlane.OverlayBitPosition, "Wrong overlay bit position for plane #{0}", overlayIndex); Assert.AreEqual(16, overlayPlane.OverlayBitsAllocated, "Wrong overlay bits allocated for plane #{0}", overlayIndex); Assert.AreEqual(OverlayType.G, overlayPlane.OverlayType, "Wrong overlay type for plane #{0}", overlayIndex); Assert.AreEqual(new Point(2, 3), overlayPlane.OverlayOrigin, "Wrong overlay origin for plane #{0}", overlayIndex); // assert overlay plane multiframe attribute values Assert.AreEqual(null, overlayPlane.ImageFrameOrigin, "Wrong image frame origin for plane #{0}", overlayIndex); Assert.AreEqual(null, overlayPlane.NumberOfFramesInOverlay, "Wrong number of frames in overlay for plane #{0}", overlayIndex); } // test overlay group 6004 { const int overlayIndex = 2; var overlayPlane = module[overlayIndex]; // assert overlay plane identification Assert.AreEqual(0x6004, overlayPlane.Group, "Wrong overlay group for plane #{0}", overlayIndex); Assert.AreEqual(2, overlayPlane.Index, "Wrong overlay index for plane #{0}", overlayIndex); Assert.AreEqual(0x040000, overlayPlane.TagOffset, "Wrong tag offset for plane #{0}", overlayIndex); // assert overlay plane encoding detection Assert.AreEqual(true, overlayPlane.HasOverlayData, "Incorrect OverlayData detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsBigEndianOW, "Incorrect OW/OB detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsMultiFrame, "Incorrect multiframe detection for plane #{0}", overlayIndex); Assert.AreEqual(67*71, overlayPlane.GetOverlayFrameLength(), "Incorrect frame size computation for plane #{0}", overlayIndex); // assert overlay plane basic attribute values Assert.AreEqual(67, overlayPlane.OverlayRows, "Wrong overlay rows for plane #{0}", overlayIndex); Assert.AreEqual(71, overlayPlane.OverlayColumns, "Wrong overlay columns for plane #{0}", overlayIndex); Assert.AreEqual(0, overlayPlane.OverlayBitPosition, "Wrong overlay bit position for plane #{0}", overlayIndex); Assert.AreEqual(1, overlayPlane.OverlayBitsAllocated, "Wrong overlay bits allocated for plane #{0}", overlayIndex); Assert.AreEqual(OverlayType.R, overlayPlane.OverlayType, "Wrong overlay type for plane #{0}", overlayIndex); Assert.AreEqual(new Point(4, 5), overlayPlane.OverlayOrigin, "Wrong overlay origin for plane #{0}", overlayIndex); // assert overlay plane multiframe attribute values Assert.AreEqual(null, overlayPlane.ImageFrameOrigin, "Wrong image frame origin for plane #{0}", overlayIndex); Assert.AreEqual(null, overlayPlane.NumberOfFramesInOverlay, "Wrong number of frames in overlay for plane #{0}", overlayIndex); } // test overlay group 601A { const int overlayIndex = 13; var overlayPlane = module[overlayIndex]; // assert overlay plane identification Assert.AreEqual(0x601A, overlayPlane.Group, "Wrong overlay group for plane #{0}", overlayIndex); Assert.AreEqual(13, overlayPlane.Index, "Wrong overlay index for plane #{0}", overlayIndex); Assert.AreEqual(0x1A0000, overlayPlane.TagOffset, "Wrong tag offset for plane #{0}", overlayIndex); // assert overlay plane encoding detection Assert.AreEqual(false, overlayPlane.HasOverlayData, "Incorrect OverlayData detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsBigEndianOW, "Incorrect OW/OB detection for plane #{0}", overlayIndex); Assert.AreEqual(false, overlayPlane.IsMultiFrame, "Incorrect multiframe detection for plane #{0}", overlayIndex); Assert.AreEqual(97*101, overlayPlane.GetOverlayFrameLength(), "Incorrect frame size computation for plane #{0}", overlayIndex); // assert overlay plane basic attribute values Assert.AreEqual(97, overlayPlane.OverlayRows, "Wrong overlay rows for plane #{0}", overlayIndex); Assert.AreEqual(101, overlayPlane.OverlayColumns, "Wrong overlay columns for plane #{0}", overlayIndex); Assert.AreEqual(14, overlayPlane.OverlayBitPosition, "Wrong overlay bit position for plane #{0}", overlayIndex); Assert.AreEqual(16, overlayPlane.OverlayBitsAllocated, "Wrong overlay bits allocated for plane #{0}", overlayIndex); Assert.AreEqual(OverlayType.R, overlayPlane.OverlayType, "Wrong overlay type for plane #{0}", overlayIndex); Assert.AreEqual(new Point(6, 7), overlayPlane.OverlayOrigin, "Wrong overlay origin for plane #{0}", overlayIndex); // assert overlay plane multiframe attribute values Assert.AreEqual(null, overlayPlane.ImageFrameOrigin, "Wrong image frame origin for plane #{0}", overlayIndex); Assert.AreEqual(null, overlayPlane.NumberOfFramesInOverlay, "Wrong number of frames in overlay for plane #{0}", overlayIndex); } }
public void ChangeTransferSyntax(TransferSyntax newTransferSyntax, IDicomCodec inputCodec, DicomCodecParameters inputParameters) { IDicomCodec codec = inputCodec; DicomCodecParameters parameters = inputParameters; if (newTransferSyntax.Encapsulated && TransferSyntax.Encapsulated) throw new DicomCodecException("Source and destination transfer syntaxes encapsulated"); if (newTransferSyntax.Encapsulated) { if (codec == null) { codec = DicomCodecRegistry.GetCodec(newTransferSyntax); if (codec == null) { Platform.Log(LogLevel.Error, "Unable to get registered codec for {0}", newTransferSyntax); throw new DicomCodecException("No registered codec for: " + newTransferSyntax.Name); } } if (parameters == null) parameters = DicomCodecRegistry.GetCodecParameters(newTransferSyntax, DataSet); DicomAttribute pixelData; if (DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData)) { if (pixelData.IsNull) throw new DicomCodecException("Sop pixel data has no valid value and cannot be compressed."); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(DataSet); DicomCompressedPixelData fragments = new DicomCompressedPixelData(pd); // Check if Overlay is embedded in pixels OverlayPlaneModuleIod overlayIod = new OverlayPlaneModuleIod(DataSet); for (int i = 0; i < 16; i++) { if (overlayIod.HasOverlayPlane(i)) { OverlayPlane overlay = overlayIod[i]; if (overlay.OverlayData == null) { Platform.Log(LogLevel.Debug, "SOP Instance has embedded overlay in pixel data, extracting"); overlay.ConvertEmbeddedOverlay(pd); } } } // Set before compression, the codecs need it. fragments.TransferSyntax = newTransferSyntax; codec.Encode(pd, fragments, parameters); fragments.UpdateMessage(this); //TODO: should we validate the number of frames in the compressed data? if (!DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData) || pixelData.IsNull) throw new DicomCodecException("Sop has no pixel data after compression."); } else { //A bit cheap, but check for basic image attributes - if any exist // and are non-empty, there should probably be pixel data too. DicomAttribute attribute; if (DataSet.TryGetAttribute(DicomTags.Rows, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Rows is non-empty), but has no pixel data."); if (DataSet.TryGetAttribute(DicomTags.Columns, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Columns is non-empty), but has no pixel data."); TransferSyntax = newTransferSyntax; } } else { if (codec == null) { codec = DicomCodecRegistry.GetCodec(TransferSyntax); if (codec == null) { Platform.Log(LogLevel.Error, "Unable to get registered codec for {0}", TransferSyntax); throw new DicomCodecException("No registered codec for: " + TransferSyntax.Name); } if (parameters == null) parameters = DicomCodecRegistry.GetCodecParameters(TransferSyntax, DataSet); } DicomAttribute pixelData; if (DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData)) { if (pixelData.IsNull) throw new DicomCodecException("Sop pixel data has no valid value and cannot be decompressed."); DicomCompressedPixelData fragments = new DicomCompressedPixelData(DataSet); DicomUncompressedPixelData pd = new DicomUncompressedPixelData(fragments); codec.Decode(fragments, pd, parameters); pd.TransferSyntax = TransferSyntax.ExplicitVrLittleEndian; pd.UpdateMessage(this); //TODO: should we validate the number of frames in the decompressed data? if (!DataSet.TryGetAttribute(DicomTags.PixelData, out pixelData) || pixelData.IsNull) throw new DicomCodecException("Sop has no pixel data after decompression."); } else { //NOTE: doing this for consistency, really. DicomAttribute attribute; if (DataSet.TryGetAttribute(DicomTags.Rows, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Rows is non-empty), but has no pixel data."); if (DataSet.TryGetAttribute(DicomTags.Columns, out attribute) && !attribute.IsNull) throw new DicomCodecException("Suspect Sop appears to be an image (Columns is non-empty), but has no pixel data."); TransferSyntax = TransferSyntax.ExplicitVrLittleEndian; } } }