/// <summary> /// Constructs a new region of interest, specifying an <see cref="IPresentationImage"/> as the source of the pixel data. /// </summary> /// <param name="presentationImage">The image containing the source pixel data.</param> protected Roi(IPresentationImage presentationImage) { IImageGraphicProvider provider = presentationImage as IImageGraphicProvider; if (provider == null) return; _imageRows = provider.ImageGraphic.Rows; _imageColumns = provider.ImageGraphic.Columns; _presentationImage = presentationImage; _pixelData = provider.ImageGraphic.PixelData; if (presentationImage is IModalityLutProvider) _modalityLut = ((IModalityLutProvider) presentationImage).ModalityLut; if (presentationImage is IImageSopProvider) { Frame frame = ((IImageSopProvider) presentationImage).Frame; _normalizedPixelSpacing = frame.NormalizedPixelSpacing; _pixelAspectRatio = frame.PixelAspectRatio; _modality = frame.ParentImageSop.Modality; _modalityLutUnits = frame.RescaleUnits; _subnormalModalityLut = frame.IsSubnormalRescale; } else { _normalizedPixelSpacing = new PixelSpacing(0, 0); _pixelAspectRatio = new PixelAspectRatio(0, 0); _modalityLutUnits = RescaleUnits.None; _subnormalModalityLut = false; } }
private void InitializeNecessaryLuts(Luts luts) { if (luts >= Luts.Modality && LutComposer.ModalityLut == null) { IModalityLut modalityLut = this.LutFactory.GetModalityLutLinear(this.BitsStored, this.IsSigned, _rescaleSlope, _rescaleIntercept); this.LutComposer.ModalityLut = modalityLut; } if (luts >= Luts.Voi && LutComposer.VoiLut == null) { IVoiLut lut = null; if (_voiLutFactory != null) { lut = _voiLutFactory.CreateVoiLut(this); } if (lut == null) { lut = new IdentityVoiLinearLut(); } (this as IVoiLutInstaller).InstallVoiLut(lut); } }
public void ComposeUnsigned16() { const int bitsStored = 16; const bool isSigned = false; const double windowWidth = 350; const double windowLevel = 40; const double rescaleSlope = 1; const double rescaleIntercept = -1024; IModalityLut modalityLut = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLut.MinInputValue); Assert.AreEqual(65535, modalityLut.MaxInputValue); Assert.AreEqual(-1024, modalityLut.MinOutputValue, _tolerance); Assert.AreEqual(64511, modalityLut.MaxOutputValue, _tolerance); Assert.AreEqual(-1024, modalityLut[0], _tolerance); Assert.AreEqual(64511, modalityLut[65535], _tolerance); BasicVoiLutLinear voiLut = new BasicVoiLutLinear( modalityLut.MinOutputValue, modalityLut.MaxOutputValue); voiLut.WindowWidth = windowWidth; voiLut.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLut; lutComposer.VoiLut = voiLut; Assert.AreEqual(-1024, voiLut.MinInputValue, _tolerance); Assert.AreEqual(64511, voiLut.MaxInputValue, _tolerance); Assert.AreEqual(-1024, voiLut.MinOutputValue, _tolerance); Assert.AreEqual(64511, voiLut.MaxOutputValue, _tolerance); // Left Window Assert.AreEqual(-1024, voiLut[-135], _tolerance); // Right Window Assert.AreEqual(64511, voiLut[215], _tolerance); // Window center // 31837 is correct according to DICOM: See PS 3.3 C.11.2.1.2 for the calculation. // Although you might think it should be 31744 (65535/2 - 1024), it is not. Assert.AreEqual(31837.38968, voiLut[40], _tolerance); //For this, we want the output range to be the same as the VOI. var output = lutComposer.GetOutputLut((int)Math.Round(voiLut.MinOutputValue), (int)Math.Round(voiLut.MaxOutputValue)); Assert.AreEqual(-1024, output.Data[0]); Assert.AreEqual(64511, output.Data[65535]); Assert.AreEqual(31837, output.Data[1064]); }
/// <summary> /// Constructor. /// </summary> /// <param name="pixelData">The pixel data the algorithm will be run on.</param> /// <param name="modalityLut">The modality lut to use for calculating <see cref="WindowWidth"/> and <see cref="WindowCenter"/>, if applicable.</param> protected AlgorithmCalculatedVoiLutLinear(GrayscalePixelData pixelData, IModalityLut modalityLut) { Platform.CheckForNullReference(pixelData, "pixelData"); _pixelData = pixelData; _modalityLut = modalityLut; _windowWidth = double.NaN; _windowCenter = double.NaN; }
/// <summary> /// Constructor. /// </summary> /// <param name="pixelData">The pixel data the algorithm will be run on.</param> /// <param name="modalityLut">The modality lut to use for calculating <see cref="WindowWidth"/> and <see cref="WindowCenter"/>, if applicable.</param> protected AlgorithmCalculatedVoiLutLinear(GrayscalePixelData pixelData, IModalityLut modalityLut) { Platform.CheckForNullReference(pixelData, "pixelData"); _pixelData = pixelData; _modalityLut = modalityLut; _windowWidth = double.NaN; _windowCenter = double.NaN; }
public void ComposeUnsigned8() { const int bitsStored = 8; const bool isSigned = false; const double windowWidth = 128; const double windowLevel = 74; const double rescaleSlope = 0.5; const double rescaleIntercept = 10; IModalityLut modalityLut = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLut.MinInputValue); Assert.AreEqual(255, modalityLut.MaxInputValue); Assert.AreEqual(10, modalityLut.MinOutputValue, _tolerance); Assert.AreEqual(137.5, modalityLut.MaxOutputValue, _tolerance); Assert.AreEqual(10, modalityLut[0], _tolerance); Assert.AreEqual(137.5, modalityLut[255], _tolerance); BasicVoiLutLinear voiLut = new BasicVoiLutLinear(); voiLut.WindowWidth = windowWidth; voiLut.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLut; lutComposer.VoiLut = voiLut; Assert.AreEqual(10, voiLut.MinInputValue, _tolerance); Assert.AreEqual(137.5, voiLut.MaxInputValue, _tolerance); Assert.AreEqual(10, voiLut.MinOutputValue); Assert.AreEqual(137.5, voiLut.MaxOutputValue); Assert.AreEqual(10, voiLut[10], _tolerance); Assert.AreEqual(137.5, voiLut[138], _tolerance); Assert.AreEqual(73.24803, voiLut[73], _tolerance); Assert.AreEqual(0, lutComposer.MinInputValue); Assert.AreEqual(255, lutComposer.MaxInputValue); //For this, we want the output range to be the same as the VOI. var output = lutComposer.GetOutputLut((int)Math.Round(voiLut.MinOutputValue), (int)Math.Round(voiLut.MaxOutputValue)); Assert.AreEqual(10, output.MinOutputValue); Assert.AreEqual(138, output.MaxOutputValue); Assert.AreEqual(10, output[0], _tolerance); Assert.AreEqual(138, output[255], _tolerance); Assert.AreEqual(74, output[127], _tolerance); }
public void ComposeUnsigned16() { int bitsStored = 16; bool isSigned = false; double windowWidth = 350; double windowLevel = 40; double rescaleSlope = 1; double rescaleIntercept = -1024; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLUT.MinInputValue); Assert.AreEqual(65535, modalityLUT.MaxInputValue); Assert.AreEqual(-1024, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(64511, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(-1024, modalityLUT[0], _tolerance); Assert.AreEqual(64511, modalityLUT[65535], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear( modalityLUT.MinOutputValue, modalityLUT.MaxOutputValue); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(-1024, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(64511, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(-1024, voiLUT.MinOutputValue); Assert.AreEqual(64511, voiLUT.MaxOutputValue); // Left Window Assert.AreEqual(-1024, voiLUT[-135]); // Right Window Assert.AreEqual(64511, voiLUT[215]); // Window center // 31837 is correct according to DICOM: See PS 3.3 C.11.2.1.2 for the calculation. // Although you might think it should be 31744 (65535/2 - 1024), it is not. Assert.AreEqual(31837, voiLUT[40]); Assert.AreEqual(-1024, lutComposer.Data[0]); Assert.AreEqual(64511, lutComposer.Data[65535]); Assert.AreEqual(31837, lutComposer.Data[1064]); }
public void ComposeSigned12() { int bitsStored = 12; bool isSigned = true; double windowWidth = 16384; double windowLevel = 4096; double rescaleSlope = 1.0; double rescaleIntercept = 0; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(-2048, modalityLUT.MinInputValue); Assert.AreEqual(2047, modalityLUT.MaxInputValue); Assert.AreEqual(-2048, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(2047, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(-2048, modalityLUT[-2048], _tolerance); Assert.AreEqual(2047, modalityLUT[2047], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear(); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(-2048, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(2047, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(-2048, voiLUT.MinOutputValue); Assert.AreEqual(2047, voiLUT.MaxOutputValue); Assert.AreEqual(-1536, voiLUT[-2047]); Assert.AreEqual(-1024, voiLUT[0]); Assert.AreEqual(-513, voiLUT[2047]); //This test is a little different from the others, it tests the output using a grayscale color map. var colorMap = _lutFactory.GetGrayscaleColorMap(); colorMap.MaxInputValue = lutComposer.MaxOutputValue; colorMap.MinInputValue = lutComposer.MinOutputValue; Assert.AreEqual(31, 0x000000ff & colorMap[lutComposer.Data[0]]); Assert.AreEqual(63, 0x000000ff & colorMap[lutComposer.Data[2048]]); Assert.AreEqual(95, 0x000000ff & colorMap[lutComposer.Data[4095]]); }
public void ComposeUnsigned8() { int bitsStored = 8; bool isSigned = false; double windowWidth = 128; double windowLevel = 74; double rescaleSlope = 0.5; double rescaleIntercept = 10; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLUT.MinInputValue); Assert.AreEqual(255, modalityLUT.MaxInputValue); Assert.AreEqual(10, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(137.5, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(10, modalityLUT[0], _tolerance); Assert.AreEqual(137.5, modalityLUT[255], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear(); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(10, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(137.5, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(10, voiLUT.MinOutputValue); Assert.AreEqual(138, voiLUT.MaxOutputValue); Assert.AreEqual(10, voiLUT[10]); Assert.AreEqual(138, voiLUT[138]); Assert.AreEqual(73, voiLUT[73]); Assert.AreEqual(0, lutComposer.MinInputValue); Assert.AreEqual(255, lutComposer.MaxInputValue); Assert.AreEqual(10, lutComposer.MinOutputValue); Assert.AreEqual(138, lutComposer.MaxOutputValue); Assert.AreEqual(10, lutComposer[0]); Assert.AreEqual(138, lutComposer[255]); Assert.AreEqual(74, lutComposer[127]); }
public void ComposeSigned8() { // Use case: Window width is 1 const int bitsStored = 8; const bool isSigned = true; const double windowWidth = 1; const double windowLevel = 0; const double rescaleSlope = 0.5; const double rescaleIntercept = 10; IModalityLut modalityLut = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(-128, modalityLut.MinInputValue); Assert.AreEqual(127, modalityLut.MaxInputValue); Assert.AreEqual(-54, modalityLut.MinOutputValue, _tolerance); Assert.AreEqual(73.5, modalityLut.MaxOutputValue, _tolerance); Assert.AreEqual(-54, modalityLut[-128], _tolerance); Assert.AreEqual(73.5, modalityLut[127], _tolerance); BasicVoiLutLinear voiLut = new BasicVoiLutLinear(); voiLut.WindowWidth = windowWidth; voiLut.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLut; lutComposer.VoiLut = voiLut; Assert.AreEqual(-54, voiLut.MinInputValue, _tolerance); Assert.AreEqual(73.5, voiLut.MaxInputValue, _tolerance); Assert.AreEqual(-54, voiLut.MinOutputValue, _tolerance); Assert.AreEqual(73.5, voiLut.MaxOutputValue, _tolerance); Assert.AreEqual(-54, voiLut[-1], _tolerance); Assert.AreEqual(73.5, voiLut[0], _tolerance); //For this, we want the output range to be the same as the VOI. var output = lutComposer.GetOutputLut((int)Math.Round(voiLut.MinOutputValue), (int)Math.Round(voiLut.MaxOutputValue)); Assert.AreEqual(-54, output.Data[0]); Assert.AreEqual(-54, output.Data[106]); Assert.AreEqual(-54, output.Data[107]); // stored pixel -21 which, if you don't round off the modality LUT, is actually -0.5 and therefore has a VOI value of -54 Assert.AreEqual(74, output.Data[108]); }
public void ComposeUnsigned12() { const int bitsStored = 12; const bool isSigned = false; const double windowWidth = 2800; const double windowLevel = 1600; const double rescaleSlope = 0.683760684; const double rescaleIntercept = 200; IModalityLut modalityLut = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLut.MinInputValue); Assert.AreEqual(4095, modalityLut.MaxInputValue); Assert.AreEqual(200, modalityLut.MinOutputValue, _tolerance); Assert.AreEqual(3000, modalityLut.MaxOutputValue, _tolerance); Assert.AreEqual(200, modalityLut[0], _tolerance); Assert.AreEqual(3000, modalityLut[4095], _tolerance); BasicVoiLutLinear voiLut = new BasicVoiLutLinear(); voiLut.WindowWidth = windowWidth; voiLut.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLut; lutComposer.VoiLut = voiLut; Assert.AreEqual(200, voiLut.MinInputValue, _tolerance); Assert.AreEqual(3000, voiLut.MaxInputValue, _tolerance); Assert.AreEqual(200, voiLut.MinOutputValue, _tolerance); Assert.AreEqual(3000, voiLut.MaxOutputValue, _tolerance); Assert.AreEqual(200, voiLut[200], _tolerance); Assert.AreEqual(3000, voiLut[3000], _tolerance); Assert.AreEqual(1600.50018, voiLut[1600], _tolerance); //For this, we want the output range to be the same as the VOI. var output = lutComposer.GetOutputLut((int)Math.Round(voiLut.MinOutputValue), (int)Math.Round(voiLut.MaxOutputValue)); Assert.AreEqual(200, output.Data[0]); Assert.AreEqual(3000, output.Data[4095]); Assert.AreEqual(1601, output.Data[2048]); }
/// <summary> /// Constructor. /// </summary> /// <param name="minPixelValue">The minimum raw pixel value in the pixel data.</param> /// <param name="maxPixelValue">The maximum raw pixel value in the pixel data.</param> /// <param name="modalityLut">The modality LUT to use for calculating <see cref="AlgorithmCalculatedVoiLutLinear.WindowWidth"/> /// and <see cref="AlgorithmCalculatedVoiLutLinear.WindowCenter"/>, if applicable.</param> public MinMaxPixelLinearLut(int minPixelValue, int maxPixelValue, IModalityLut modalityLut) { double windowStart = minPixelValue; double windowEnd = maxPixelValue; if (modalityLut != null) { windowStart = modalityLut[windowStart]; windowEnd = modalityLut[windowEnd]; } // round the window to one decimal place so it's not ridiculous // value is calculated anyway and thus has no significance outside of display var windowWidth = Math.Max(windowEnd - windowStart + 1, 1); _windowWidth = Math.Round(windowWidth, 1); _windowCenter = Math.Round(windowStart + windowWidth/2, 1); }
public void ComposeSigned8() { // Use case: Window width is 1 int bitsStored = 8; bool isSigned = true; double windowWidth = 1; double windowLevel = 0; double rescaleSlope = 0.5; double rescaleIntercept = 10; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(-128, modalityLUT.MinInputValue); Assert.AreEqual(127, modalityLUT.MaxInputValue); Assert.AreEqual(-54, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(73.5, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(-54, modalityLUT[-128], _tolerance); Assert.AreEqual(73.5, modalityLUT[127], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear(); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(-54, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(73.5, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(-54, voiLUT.MinOutputValue); Assert.AreEqual(74, voiLUT.MaxOutputValue); Assert.AreEqual(-54, voiLUT[-1]); Assert.AreEqual(74, voiLUT[0]); Assert.AreEqual(-54, lutComposer.Data[0]); Assert.AreEqual(-54, lutComposer.Data[106]); Assert.AreEqual(-54, lutComposer.Data[107]); // stored pixel -21 which, if you don't round off the modality LUT, is actually -0.5 and therefore has a VOI value of -54 Assert.AreEqual(74, lutComposer.Data[108]); }
/// <summary> /// Constructor. /// </summary> /// <param name="minPixelValue">The minimum raw pixel value in the pixel data.</param> /// <param name="maxPixelValue">The maximum raw pixel value in the pixel data.</param> /// <param name="modalityLut">The modality LUT to use for calculating <see cref="AlgorithmCalculatedVoiLutLinear.WindowWidth"/> /// and <see cref="AlgorithmCalculatedVoiLutLinear.WindowCenter"/>, if applicable.</param> public MinMaxPixelLinearLut(int minPixelValue, int maxPixelValue, IModalityLut modalityLut) { double windowStart = minPixelValue; double windowEnd = maxPixelValue; if (modalityLut != null) { windowStart = modalityLut[windowStart]; windowEnd = modalityLut[windowEnd]; } // round the window to one decimal place so it's not ridiculous // value is calculated anyway and thus has no significance outside of display var windowWidth = Math.Max(windowEnd - windowStart + 1, 1); _windowWidth = Math.Round(windowWidth, 1); _windowCenter = Math.Round(windowStart + windowWidth / 2, 1); }
public void ComposeSigned16() { int bitsStored = 16; bool isSigned = true; double windowWidth = 350; double windowLevel = 40; double rescaleSlope = 1; double rescaleIntercept = -1024; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(-32768, modalityLUT.MinInputValue); Assert.AreEqual(32767, modalityLUT.MaxInputValue); Assert.AreEqual(-33792, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(31743, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(-33792, modalityLUT[-32768], _tolerance); Assert.AreEqual(31743, modalityLUT[32767], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear(); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(-33792, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(31743, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(-33792, voiLUT.MinOutputValue); Assert.AreEqual(31743, voiLUT.MaxOutputValue); // Left Window Assert.AreEqual(-33792, voiLUT[-135]); // Right Window Assert.AreEqual(31743, voiLUT[215]); // Window center Assert.AreEqual(-931, voiLUT[40]); }
public void ComposeUnsigned12() { int bitsStored = 12; bool isSigned = false; double windowWidth = 2800; double windowLevel = 1600; double rescaleSlope = 0.683760684; double rescaleIntercept = 200; IModalityLut modalityLUT = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(0, modalityLUT.MinInputValue); Assert.AreEqual(4095, modalityLUT.MaxInputValue); Assert.AreEqual(200, modalityLUT.MinOutputValue, _tolerance); Assert.AreEqual(3000, modalityLUT.MaxOutputValue, _tolerance); Assert.AreEqual(200, modalityLUT[0], _tolerance); Assert.AreEqual(3000, modalityLUT[4095], _tolerance); BasicVoiLutLinear voiLUT = new BasicVoiLutLinear(); voiLUT.WindowWidth = windowWidth; voiLUT.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLUT; lutComposer.VoiLut = voiLUT; Assert.AreEqual(200, voiLUT.MinInputValue, _tolerance); Assert.AreEqual(3000, voiLUT.MaxInputValue, _tolerance); Assert.AreEqual(200, voiLUT.MinOutputValue); Assert.AreEqual(3000, voiLUT.MaxOutputValue); Assert.AreEqual(200, voiLUT[200]); Assert.AreEqual(3000, voiLUT[3000]); Assert.AreEqual(1601, voiLUT[1600]); Assert.AreEqual(200, lutComposer.Data[0]); Assert.AreEqual(3000, lutComposer.Data[4095]); Assert.AreEqual(1601, lutComposer.Data[2048]); }
private static double CalculateMean ( RectangleF roiBoundingBox, GrayscalePixelData pixelData, IModalityLut modalityLut, IsPointInRoiDelegate isPointInRoi ) { double sum = 0; int pixelCount = 0; var boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); pixelData.ForEachPixel( boundingBox.Left, boundingBox.Top, boundingBox.Right, boundingBox.Bottom, delegate(int i, int x, int y, int pixelIndex) { if (isPointInRoi(x, y)) { ++pixelCount; // Make sure we run the raw pixel through the modality LUT // when doing the calculation. Note that the modality LUT // can be something other than a rescale intercept, so we can't // just run the mean through the LUT. int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; sum += realValue; } }); if (pixelCount == 0) { return(0); } return(sum / pixelCount); }
private static double CalculateStandardDeviation ( double mean, RectangleF roiBoundingBox, GrayscalePixelData pixelData, IModalityLut modalityLut, IsPointInRoiDelegate isPointInRoi ) { double sum = 0; int pixelCount = 0; var boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); pixelData.ForEachPixel( boundingBox.Left, boundingBox.Top, boundingBox.Right, boundingBox.Bottom, delegate(int i, int x, int y, int pixelIndex) { if (isPointInRoi(x, y)) { ++pixelCount; int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; double deviation = realValue - mean; sum += deviation * deviation; } }); if (pixelCount == 0) { return(0); } return(Math.Sqrt(sum / pixelCount)); }
public void ComposeSigned12() { const int bitsStored = 12; const bool isSigned = true; const double windowWidth = 16384; const double windowLevel = 4096; const double rescaleSlope = 1.0; const double rescaleIntercept = 0; IModalityLut modalityLut = _lutFactory.GetModalityLutLinear( bitsStored, isSigned, rescaleSlope, rescaleIntercept); Assert.AreEqual(-2048, modalityLut.MinInputValue); Assert.AreEqual(2047, modalityLut.MaxInputValue); Assert.AreEqual(-2048, modalityLut.MinOutputValue, _tolerance); Assert.AreEqual(2047, modalityLut.MaxOutputValue, _tolerance); Assert.AreEqual(-2048, modalityLut[-2048], _tolerance); Assert.AreEqual(2047, modalityLut[2047], _tolerance); BasicVoiLutLinear voiLut = new BasicVoiLutLinear(); voiLut.WindowWidth = windowWidth; voiLut.WindowCenter = windowLevel; LutComposer lutComposer = new LutComposer(bitsStored, isSigned); lutComposer.ModalityLut = modalityLut; lutComposer.VoiLut = voiLut; Assert.AreEqual(-2048, voiLut.MinInputValue, _tolerance); Assert.AreEqual(2047, voiLut.MaxInputValue, _tolerance); Assert.AreEqual(-2048, voiLut.MinOutputValue); Assert.AreEqual(2047, voiLut.MaxOutputValue); Assert.AreEqual(-1535.84380, voiLut[-2047], _tolerance); Assert.AreEqual(-1024.18751, voiLut[0], _tolerance); Assert.AreEqual(-512.53122, voiLut[2047], _tolerance); //For this, we want the output range to be the same as the VOI. var output = lutComposer.GetOutputLut((int)Math.Round(voiLut.MinOutputValue), (int)Math.Round(voiLut.MaxOutputValue)); Assert.AreEqual(-1536, output[-2047]); Assert.AreEqual(-1024, output[0]); Assert.AreEqual(-513, output[2047]); Assert.AreEqual(voiLut.MinOutputValue, output.MinInputValue); Assert.AreEqual(voiLut.MaxOutputValue, output.MaxInputValue); Assert.AreEqual(voiLut.MinOutputValue, output.MinOutputValue); Assert.AreEqual(voiLut.MaxOutputValue, output.MaxOutputValue); //This test is a little different from the others, it tests the output using a grayscale color map. var colorMap = _lutFactory.GetGrayscaleColorMap(); colorMap.MaxInputValue = output.MaxOutputValue; colorMap.MinInputValue = output.MinOutputValue; Assert.AreEqual(32, 0x000000ff & colorMap[output.Data[0]]); Assert.AreEqual(64, 0x000000ff & colorMap[output.Data[2048]]); Assert.AreEqual(96, 0x000000ff & colorMap[output.Data[4095]]); }
private static void CopyFrameData(byte[] frameData, int frameBytesPerPixel, bool frameIsSigned, IModalityLut frameModalityLut, ushort[] volumeData, int volumeStart, double normalizedSlope, double normalizedIntercept, out int minFramePixel, out int maxFramePixel) { var pixelCount = frameData.Length / frameBytesPerPixel; unsafe { var min = int.MaxValue; var max = int.MinValue; fixed(byte *pFrameData = frameData) fixed(ushort *pVolumeData = volumeData) { if (frameBytesPerPixel == 2) { var pFrameData16 = (short *)pFrameData; for (var i = 0; i < pixelCount; ++i) { /// TODO (CR Nov 2011): Although perhaps less pretty, it's a bit more efficient /// to break this out into 2 loops. var frameValue = frameModalityLut[frameIsSigned ? (int)pFrameData16[i] : (ushort)pFrameData16[i]]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); /// TODO (CR Nov 2011): Writes are volatile, so slightly more efficient to only do the assignment when necessary min = Math.Min(min, volumePixel); max = Math.Max(max, volumePixel); pVolumeData[volumeStart + i] = volumePixel; } } else if (frameBytesPerPixel == 1) { for (var i = 0; i < pixelCount; ++i) { /// TODO (CR Nov 2011): Although perhaps less pretty, it's a bit more efficient /// to break this out into 2 loops. var frameValue = frameModalityLut[frameIsSigned ? (int)(sbyte)pFrameData[i] : pFrameData[i]]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); /// TODO (CR Nov 2011): Writes are volatile, so slightly more efficient to only do the assignment when necessary min = Math.Min(min, volumePixel); max = Math.Max(max, volumePixel); pVolumeData[volumeStart + i] = volumePixel; } } } minFramePixel = min; maxFramePixel = max; } }
/// <summary> /// Constructor. /// </summary> /// <remarks> /// The input <see cref="IVoiLut"/> object can be null. /// </remarks> /// <param name="pixelData">The pixel data the algorithm will be run on.</param> /// <param name="modalityLut">The modality lut to use for calculating <see cref="AlgorithmCalculatedVoiLutLinear.WindowWidth"/> /// and <see cref="AlgorithmCalculatedVoiLutLinear.WindowCenter"/>, if applicable.</param> public MinMaxPixelCalculatedLinearLut(GrayscalePixelData pixelData, IModalityLut modalityLut) : base(pixelData, modalityLut) { }
private static double CalculateMean ( RectangleF roiBoundingBox, GrayscalePixelData pixelData, IModalityLut modalityLut, IsPointInRoiDelegate isPointInRoi ) { double sum = 0; int pixelCount = 0; var boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); pixelData.ForEachPixel( boundingBox.Left, boundingBox.Top, boundingBox.Right, boundingBox.Bottom, delegate(int i, int x, int y, int pixelIndex) { if (isPointInRoi(x, y)) { ++pixelCount; // Make sure we run the raw pixel through the modality LUT // when doing the calculation. Note that the modality LUT // can be something other than a rescale intercept, so we can't // just run the mean through the LUT. int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; sum += realValue; } }); if (pixelCount == 0) return 0; return sum/pixelCount; }
private static unsafe void CopyFrameData(byte[] frameData, int frameBytesPerPixel, bool frameIsSigned, IModalityLut frameModalityLut, ushort[] volumeData, int volumeStart, double normalizedSlope, double normalizedIntercept, out int minFramePixel, out int maxFramePixel) { var pixelCount = frameData.Length/frameBytesPerPixel; var min = int.MaxValue; var max = int.MinValue; fixed (byte* pFrameData = frameData) fixed (ushort* pVolumeData = volumeData) { var pVolumeFrame = pVolumeData + volumeStart; if (frameBytesPerPixel == 2) { if (frameIsSigned) { var pFrameDataS16 = (short*) pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataS16++]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) min = volumePixel; if (volumePixel > max) max = volumePixel; *pVolumeFrame++ = volumePixel; } } else { var pFrameDataU16 = (ushort*) pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataU16++]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) min = volumePixel; if (volumePixel > max) max = volumePixel; *pVolumeFrame++ = volumePixel; } } } else if (frameBytesPerPixel == 1) { if (frameIsSigned) { var pFrameDataS8 = (sbyte*) pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataS8++]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) min = volumePixel; if (volumePixel > max) max = volumePixel; *pVolumeFrame++ = volumePixel; } } else { var pFrameDataU8 = pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataU8++]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) min = volumePixel; if (volumePixel > max) max = volumePixel; *pVolumeFrame++ = volumePixel; } } } else { throw new ArgumentOutOfRangeException("frameBytesPerPixel"); } } minFramePixel = min; maxFramePixel = max; }
/// <summary> /// Constructor. /// </summary> /// <remarks> /// The input <see cref="IVoiLut"/> object can be null. /// </remarks> /// <param name="pixelData">The pixel data the algorithm will be run on.</param> /// <param name="modalityLut">The modality lut to use for calculating <see cref="AlgorithmCalculatedVoiLutLinear.WindowWidth"/> /// and <see cref="AlgorithmCalculatedVoiLutLinear.WindowCenter"/>, if applicable.</param> public MinMaxPixelCalculatedLinearLut(GrayscalePixelData pixelData, IModalityLut modalityLut) : base(pixelData, modalityLut) { }
private static double CalculateStandardDeviation ( double mean, RectangleF roiBoundingBox, GrayscalePixelData pixelData, IModalityLut modalityLut, IsPointInRoiDelegate isPointInRoi ) { double sum = 0; int pixelCount = 0; var boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); pixelData.ForEachPixel( boundingBox.Left, boundingBox.Top, boundingBox.Right, boundingBox.Bottom, delegate(int i, int x, int y, int pixelIndex) { if (isPointInRoi(x, y)) { ++pixelCount; int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; double deviation = realValue - mean; sum += deviation*deviation; } }); if (pixelCount == 0) return 0; return Math.Sqrt(sum/pixelCount); }
internal static double CalculateMeanForStack(List <ImageCalculationInfo> imageCalculationInfoStack) { double sum = 0; int pixelCount = 0; for (int imageCount = 0; imageCount < imageCalculationInfoStack.Count; imageCount++) { PixelData pixelData = imageCalculationInfoStack[imageCount].PixelData; SegFrameImageGraphic segFrameImageGraphic = imageCalculationInfoStack[imageCount].SegFrameImageGraphic; RectangleF roiBoundingBox = imageCalculationInfoStack[imageCount].RoiBoundingBox; IModalityLut modalityLut = imageCalculationInfoStack[imageCount].ModalityLut; Rectangle boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); int left = boundingBox.Left; if (left < 0) { left = 0; } if (left >= segFrameImageGraphic.Columns) { left = segFrameImageGraphic.Columns - 1; } int right = boundingBox.Right; if (right < 0) { right = 0; } if (right >= segFrameImageGraphic.Columns) { right = segFrameImageGraphic.Columns - 1; } int top = boundingBox.Top; if (top < 0) { top = 0; } if (top >= segFrameImageGraphic.Rows) { top = segFrameImageGraphic.Rows - 1; } int bottom = boundingBox.Bottom; if (bottom < 0) { bottom = 0; } if (bottom >= segFrameImageGraphic.Rows) { bottom = segFrameImageGraphic.Rows - 1; } pixelData.ForEachPixel( left, top, right, bottom, delegate(int i, int x, int y, int pixelIndex) { //if (x >= 0 && x < segFrameImageGraphic.Columns && y >= 0 && y < segFrameImageGraphic.Rows) if (segFrameImageGraphic[x, y]) { ++pixelCount; // Make sure we run the raw pixel through the modality LUT // when doing the calculation. Note that the modality LUT // can be something other than a rescale intercept, so we can't // just run the mean through the LUT. int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; sum += realValue; } }); } if (pixelCount == 0) { return(0); } return(sum / pixelCount); }
private static void CopyFrameData(byte[] frameData, int frameBytesPerPixel, bool frameIsSigned, IModalityLut frameModalityLut, ushort[] volumeData, int volumeStart, double normalizedSlope, double normalizedIntercept, out int minFramePixel, out int maxFramePixel) { var pixelCount = frameData.Length/frameBytesPerPixel; unsafe { var min = int.MaxValue; var max = int.MinValue; fixed (byte* pFrameData = frameData) fixed (ushort* pVolumeData = volumeData) { if (frameBytesPerPixel == 2) { var pFrameData16 = (short*) pFrameData; for (var i = 0; i < pixelCount; ++i) { /// TODO (CR Nov 2011): Although perhaps less pretty, it's a bit more efficient /// to break this out into 2 loops. var frameValue = frameModalityLut[frameIsSigned ? (int) pFrameData16[i] : (ushort) pFrameData16[i]]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); /// TODO (CR Nov 2011): Writes are volatile, so slightly more efficient to only do the assignment when necessary min = Math.Min(min, volumePixel); max = Math.Max(max, volumePixel); pVolumeData[volumeStart + i] = volumePixel; } } else if (frameBytesPerPixel == 1) { for (var i = 0; i < pixelCount; ++i) { /// TODO (CR Nov 2011): Although perhaps less pretty, it's a bit more efficient /// to break this out into 2 loops. var frameValue = frameModalityLut[frameIsSigned ? (int)(sbyte)pFrameData[i] : pFrameData[i]]; var volumeValue = (frameValue - normalizedIntercept)/normalizedSlope; var volumePixel = (ushort) Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); /// TODO (CR Nov 2011): Writes are volatile, so slightly more efficient to only do the assignment when necessary min = Math.Min(min, volumePixel); max = Math.Max(max, volumePixel); pVolumeData[volumeStart + i] = volumePixel; } } } minFramePixel = min; maxFramePixel = max; } }
internal static double CalculateStandardDeviationForStack(double mean, List <ImageCalculationInfo> imageCalculationInfoStack) { double sum = 0; int pixelCount = 0; for (int imageCount = 0; imageCount < imageCalculationInfoStack.Count; imageCount++) { PixelData pixelData = imageCalculationInfoStack[imageCount].PixelData; SegFrameImageGraphic segFrameImageGraphic = imageCalculationInfoStack[imageCount].SegFrameImageGraphic; RectangleF roiBoundingBox = imageCalculationInfoStack[imageCount].RoiBoundingBox; IModalityLut modalityLut = imageCalculationInfoStack[imageCount].ModalityLut; Rectangle boundingBox = RectangleUtilities.RoundInflate(RectangleUtilities.ConvertToPositiveRectangle(roiBoundingBox)); int left = boundingBox.Left; if (left < 0) { left = 0; } if (left >= segFrameImageGraphic.Columns) { left = segFrameImageGraphic.Columns - 1; } int right = boundingBox.Right; if (right < 0) { right = 0; } if (right >= segFrameImageGraphic.Columns) { right = segFrameImageGraphic.Columns - 1; } int top = boundingBox.Top; if (top < 0) { top = 0; } if (top >= segFrameImageGraphic.Rows) { top = segFrameImageGraphic.Rows - 1; } int bottom = boundingBox.Bottom; if (bottom < 0) { bottom = 0; } if (bottom >= segFrameImageGraphic.Rows) { bottom = segFrameImageGraphic.Rows - 1; } pixelData.ForEachPixel( left, top, right, bottom, delegate(int i, int x, int y, int pixelIndex) { if (segFrameImageGraphic[x, y]) { ++pixelCount; int storedValue = pixelData.GetPixel(pixelIndex); double realValue = modalityLut != null ? modalityLut[storedValue] : storedValue; double deviation = realValue - mean; sum += deviation * deviation; } }); } if (pixelCount == 0) { return(0); } return(Math.Sqrt(sum / pixelCount)); }
private static unsafe void CopyFrameData(byte[] frameData, int frameBytesPerPixel, bool frameIsSigned, IModalityLut frameModalityLut, ushort[] volumeData, int volumeStart, double normalizedSlope, double normalizedIntercept, out int minFramePixel, out int maxFramePixel) { var pixelCount = frameData.Length / frameBytesPerPixel; var min = int.MaxValue; var max = int.MinValue; fixed(byte *pFrameData = frameData) fixed(ushort *pVolumeData = volumeData) { var pVolumeFrame = pVolumeData + volumeStart; if (frameBytesPerPixel == 2) { if (frameIsSigned) { var pFrameDataS16 = (short *)pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataS16++]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) { min = volumePixel; } if (volumePixel > max) { max = volumePixel; } *pVolumeFrame++ = volumePixel; } } else { var pFrameDataU16 = (ushort *)pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataU16++]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) { min = volumePixel; } if (volumePixel > max) { max = volumePixel; } *pVolumeFrame++ = volumePixel; } } } else if (frameBytesPerPixel == 1) { if (frameIsSigned) { var pFrameDataS8 = (sbyte *)pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataS8++]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) { min = volumePixel; } if (volumePixel > max) { max = volumePixel; } *pVolumeFrame++ = volumePixel; } } else { var pFrameDataU8 = pFrameData; for (var i = 0; i < pixelCount; ++i) { var frameValue = frameModalityLut[*pFrameDataU8++]; var volumeValue = (frameValue - normalizedIntercept) / normalizedSlope; var volumePixel = (ushort)Math.Max(ushort.MinValue, Math.Min(ushort.MaxValue, Math.Round(volumeValue))); if (volumePixel < min) { min = volumePixel; } if (volumePixel > max) { max = volumePixel; } *pVolumeFrame++ = volumePixel; } } } else { throw new ArgumentOutOfRangeException("frameBytesPerPixel"); } } minFramePixel = min; maxFramePixel = max; }