public void TestGetWindowsWithExplanations() { var windows = new[] { new VoiWindow(1, 2), new VoiWindow(100, 200), new VoiWindow(100.1, 200.2), new VoiWindow(123.1, 456.2), new VoiWindow(123.567890123, -23.567890123) }; var dataset = new DicomAttributeCollection(); dataset[DicomTags.WindowCenter].SetStringValue(@"2\200\200.2\456.2\-23.567890123"); dataset[DicomTags.WindowWidth].SetStringValue(@"1\100\100.1\123.1\123.567890123"); dataset[DicomTags.WindowCenterWidthExplanation].SetStringValue(@"bob\alice\eve\james"); var actualWindows = VoiWindow.GetWindows(dataset).ToArray(); Assert.AreEqual(windows, actualWindows); Assert.AreEqual("bob", actualWindows[0].Explanation); Assert.AreEqual("alice", actualWindows[1].Explanation); Assert.AreEqual("eve", actualWindows[2].Explanation); Assert.AreEqual("james", actualWindows[3].Explanation); Assert.AreEqual("", actualWindows[4].Explanation); }
/// <summary> /// Creates the <see cref="VolumeHeaderData"/> for the builder's source frames. /// </summary> /// <returns></returns> public VolumeHeaderData BuildVolumeHeader() { if (_volumeHeaderData != null) { return(_volumeHeaderData); } PrepareFrames(_frames); // this also sorts the frames into order by slice location // compute modality LUT parameters normalized for all frames double normalizedSlope, normalizedIntercept; var normalizedUnits = _frames[0].Frame.RescaleUnits; ComputeNormalizedModalityLut(_frames, out normalizedSlope, out normalizedIntercept); // determine an appropriate pixel padding value var pixelPaddingValue = ComputePixelPaddingValue(_frames, normalizedSlope, normalizedIntercept); // get the laterality of the anatomy being constructed var laterality = _frames[0].Frame.Laterality; // Construct a model SOP data source based on the first frame's DICOM header var header = new VolumeHeaderData(_frames.Select(f => (IDicomAttributeProvider)f.Frame).ToList(), VolumeSize, VoxelSpacing, VolumePositionPatient, VolumeOrientationPatient, 16, 16, false, pixelPaddingValue, normalizedSlope, normalizedIntercept, normalizedUnits, laterality); // determine how the normalized modality LUT affects VOI windows and update the header VoiWindow.SetWindows(ComputeAggregateNormalizedVoiWindows(_frames, normalizedSlope, normalizedIntercept), header); return(_volumeHeaderData = header); }
/// <summary> /// Creates and populates a <see cref="Volume"/> from the builder's source frames. /// </summary> public Volume Build() { PrepareFrames(_frames); // this also sorts the frames into order by slice location // Construct a model SOP data source based on the first frame's DICOM header var sopDataSourcePrototype = VolumeSopDataSourcePrototype.Create(_frames.Select(f => (IDicomAttributeProvider)f.Sop.DataSource).ToList(), 16, 16, false); // compute normalized modality LUT double normalizedSlope, normalizedIntercept; ComputeNormalizedModalityLut(_frames, out normalizedSlope, out normalizedIntercept); sopDataSourcePrototype[DicomTags.RescaleSlope].SetFloat64(0, normalizedSlope); sopDataSourcePrototype[DicomTags.RescaleIntercept].SetFloat64(0, normalizedIntercept); sopDataSourcePrototype[DicomTags.RescaleType] = _frames[0].Sop.DataSource[DicomTags.RescaleType].Copy(); sopDataSourcePrototype[DicomTags.Units] = _frames[0].Sop.DataSource[DicomTags.Units].Copy(); // PET series use this attribute to designate rescale units // compute normalized VOI windows VoiWindow.SetWindows(ComputeNormalizedVoiWindows(_frames, normalizedSlope, normalizedIntercept), sopDataSourcePrototype); // compute the volume padding value var pixelPaddingValue = ComputePixelPaddingValue(_frames, normalizedSlope, normalizedIntercept); int minVolumeValue, maxVolumeValue; var volumeArray = BuildVolumeArray(pixelPaddingValue, normalizedSlope, normalizedIntercept, out minVolumeValue, out maxVolumeValue); var volume = new Volume(null, volumeArray, VolumeSize, VoxelSpacing, ImagePositionPatient, ImageOrientationPatient, sopDataSourcePrototype, pixelPaddingValue, _frames[0].Frame.SeriesInstanceUid, minVolumeValue, maxVolumeValue); return(volume); }
public void TestGetWindowsMissingWidths() { var dataset = new DicomAttributeCollection(); dataset[DicomTags.WindowCenter].SetStringValue(@"2\200\200.2\456.2\-23.567890123"); dataset[DicomTags.WindowWidth].SetEmptyValue(); var windows = VoiWindow.GetWindows(dataset).ToArray(); Assert.AreEqual(new VoiWindow[0], windows); }
public void TestSetWindowsEmpty() { var windows = new VoiWindow[0]; var dataset = new DicomAttributeCollection(); VoiWindow.SetWindows(windows, dataset); Assert.IsTrue(dataset[DicomTags.WindowCenter].IsEmpty); Assert.IsTrue(dataset[DicomTags.WindowWidth].IsEmpty); }
public FusionOverlayData(IEnumerable <Frame> overlaySource) { var frames = new List <IFrameReference>(); foreach (Frame frame in overlaySource) { frames.Add(frame.CreateTransientReference()); } _frames = frames.AsReadOnly(); if (frames.Count > 0) { _voiWindows = new List <VoiWindow>(VoiWindow.GetWindows(frames[0].Sop.DataSource)).AsReadOnly(); } }
public void TestExplanations() { var window0 = new VoiWindow(123.1, 456.2); Assert.AreEqual(string.Empty, window0.Explanation); var window1 = new VoiWindow(123.1, 456.2, null); Assert.AreEqual(string.Empty, window1.Explanation); Assert.AreEqual(window1, window0); var window2 = new VoiWindow(123.1, 456.2, "explanation"); Assert.AreEqual("explanation", window2.Explanation); Assert.AreEqual(window1, window2); var window3 = new VoiWindow(4132, 324, "explanation"); Assert.AreNotEqual(window2, window3); }
private static IEnumerable <VoiWindow> ComputeNormalizedVoiWindows(IImageSopProvider frame, double normalizedSlope, double normalizedIntercept) { var normalizedWindows = new List <VoiWindow>(VoiWindow.GetWindows(frame.Frame)); if (frame.ImageSop.Modality == @"PT" && frame.Frame.IsSubnormalRescale) { // for PET images with subnormal rescale, the VOI window will always be applied directly to the original stored pixel values // since MPR will not have access to original stored pixel values, we compute the VOI window through original modality LUT and inverted normalized modality LUT var normalizedVoiSlope = frame.Frame.RescaleSlope / normalizedSlope; var normalizedVoiIntercept = (frame.Frame.RescaleIntercept - normalizedIntercept) / normalizedSlope; for (var i = 0; i < normalizedWindows.Count; ++i) { var window = normalizedWindows[i]; // round the computed windows - the extra precision is not useful for display anyway normalizedWindows[i] = new VoiWindow(Math.Ceiling(window.Width * normalizedVoiSlope), Math.Round(window.Center * normalizedVoiSlope + normalizedVoiIntercept), window.Explanation); } } return(normalizedWindows); }
public void TestBasics() { var window1 = new VoiWindow(123.1, 456.2); Assert.AreEqual(123.1, window1.Width); Assert.AreEqual(456.2, window1.Center); Assert.AreEqual("123.10/456.20", window1.ToString()); Assert.IsFalse(window1.Equals(new object())); var window2 = new VoiWindow(1.231, 456.2); Assert.AreNotEqual(window1, window2); var window3 = new VoiWindow(123.1, 4.562); Assert.AreNotEqual(window1, window3); var window4 = new VoiWindow(123.1, 456.2); Assert.AreEqual(window1, window4); }
public void TestGetWindowsMismatchedPairs() { var windows = new[] { new VoiWindow(1, 2), new VoiWindow(100, 200), new VoiWindow(100.1, 200.2), new VoiWindow(123.1, 456.2) }; var dataset = new DicomAttributeCollection(); dataset[DicomTags.WindowCenter].SetStringValue(@"2\200\200.2\456.2\-23.567890123"); dataset[DicomTags.WindowWidth].SetStringValue(@"1\100\100.1\123.1"); var actualWindows = VoiWindow.GetWindows(dataset).ToArray(); Assert.AreEqual(windows, actualWindows); }
public FusionOverlayData(IEnumerable <Frame> overlaySource) { var frames = new List <IFrameReference>(); foreach (Frame frame in overlaySource) { frames.Add(frame.CreateTransientReference()); } _frames = frames.AsReadOnly(); if (frames.Count > 0) { // TODO: should this VOI window be based on volume header's normalized VOI windows? _voiWindows = new List <VoiWindow>(VoiWindow.GetWindows(frames[0].Frame)).AsReadOnly(); SourceSeriesInstanceUid = frames[0].Frame.SeriesInstanceUid; FrameOfReferenceUid = frames[0].Frame.FrameOfReferenceUid; Modality = frames[0].Sop.Modality; } }
public void TestSetWindows() { var windows = new[] { new VoiWindow(1, 2), new VoiWindow(100, 200), new VoiWindow(100.1, 200.2), new VoiWindow(123.1, 456.2), new VoiWindow(123.567890123, -23.567890123) }; var dataset = new DicomAttributeCollection(); VoiWindow.SetWindows(windows, dataset); Assert.AreEqual(5, dataset[DicomTags.WindowCenter].Count); Assert.AreEqual(dataset[DicomTags.WindowCenter].ToString(), @"2\200\200.2\456.2\-23.567890123"); Assert.AreEqual(5, dataset[DicomTags.WindowWidth].Count); Assert.AreEqual(dataset[DicomTags.WindowWidth].ToString(), @"1\100\100.1\123.1\123.567890123"); }
public void TestSetWindowsWithExplanations() { var windows = new[] { new VoiWindow(1, 2, "bob"), new VoiWindow(100, 200, "alice"), new VoiWindow(100.1, 200.2, "eve"), new VoiWindow(123.1, 456.2, "james"), new VoiWindow(123.567890123, -23.567890123) }; var dataset = new DicomAttributeCollection(); VoiWindow.SetWindows(windows, dataset); Assert.AreEqual(5, dataset[DicomTags.WindowCenter].Count); Assert.AreEqual(dataset[DicomTags.WindowCenter].ToString(), @"2\200\200.2\456.2\-23.567890123"); Assert.AreEqual(5, dataset[DicomTags.WindowWidth].Count); Assert.AreEqual(dataset[DicomTags.WindowWidth].ToString(), @"1\100\100.1\123.1\123.567890123"); Assert.AreEqual(5, dataset[DicomTags.WindowCenterWidthExplanation].Count); Assert.AreEqual(dataset[DicomTags.WindowCenterWidthExplanation].ToString(), @"bob\alice\eve\james\"); }
private static IEnumerable<VoiWindow> ComputeNormalizedVoiWindows(IList<IFrameReference> frames, double normalizedSlope, double normalizedIntercept) { var normalizedWindows = new List<VoiWindow>(VoiWindow.GetWindows(frames[0].Sop.DataSource)); if (frames[0].ImageSop.Modality == @"PT" && frames[0].Frame.IsSubnormalRescale) { // for PET images with subnormal rescale, the VOI window will always be applied directly to the original stored pixel values // since MPR will not have access to original stored pixel values, we compute the VOI window through original modality LUT and inverted normalized modality LUT var normalizedVoiSlope = frames[0].Frame.RescaleSlope/normalizedSlope; var normalizedVoiIntercept = (frames[0].Frame.RescaleIntercept - normalizedIntercept)/normalizedSlope; for (var i = 0; i < normalizedWindows.Count; ++i) { var window = normalizedWindows[i]; // round the computed windows - the extra precision is not useful for display anyway normalizedWindows[i] = new VoiWindow(Math.Ceiling(window.Width*normalizedVoiSlope), Math.Round(window.Center*normalizedVoiSlope + normalizedVoiIntercept), window.Explanation); } } return normalizedWindows; }