public void TestPipelineUnsigned16() { var composer = new LutComposer(16, false); composer.ModalityLut = new ModalityLutLinear(16, false, 1, 0); var voiLUT = new BasicVoiLutLinear(65536, 32768); composer.VoiLut = voiLUT; Assert.AreEqual(0, voiLUT[0], _tolerance); Assert.AreEqual(32768, voiLUT[32768], _tolerance); Assert.AreEqual(65535, voiLUT[65535], _tolerance); Assert.AreEqual(0, voiLUT[-1], _tolerance); Assert.AreEqual(65535, voiLUT[65536], _tolerance); var output = composer.GetOutputLut(0, byte.MaxValue); Assert.AreEqual(0, output[0]); Assert.AreEqual(128, output[32768]); Assert.AreEqual(255, output[65535]); //Make sure the output of the grayscale color map works with all the different "display" output ranges. var colorMap = LutFactory.Create().GetGrayscaleColorMap(); colorMap.MinInputValue = output.MinOutputValue; colorMap.MaxInputValue = output.MaxOutputValue; Assert.AreEqual(0, 0x000000FF & colorMap[output[0]]); Assert.AreEqual(128, 0x000000FF & colorMap[output[32768]]); Assert.AreEqual(255, 0x000000FF & colorMap[output[65535]]); //10-bit display output = composer.GetOutputLut(0, 1023); Assert.AreEqual(0, output[0]); Assert.AreEqual(512, output[32768]); Assert.AreEqual(1023, output[65535]); colorMap.MinInputValue = output.MinOutputValue; colorMap.MaxInputValue = output.MaxOutputValue; Assert.AreEqual(0, 0x000000FF & colorMap[output[0]]); Assert.AreEqual(128, 0x000000FF & colorMap[output[32768]]); Assert.AreEqual(255, 0x000000FF & colorMap[output[65535]]); //Theoretical 12-bit display with signed output output = composer.GetOutputLut(-2048, 2047); Assert.AreEqual(-2048, output[0]); Assert.AreEqual(0, output[32768]); Assert.AreEqual(2047, output[65535]); colorMap.MinInputValue = output.MinOutputValue; colorMap.MaxInputValue = output.MaxOutputValue; Assert.AreEqual(0, 0x000000FF & colorMap[output[0]]); Assert.AreEqual(128, 0x000000FF & colorMap[output[32768]]); Assert.AreEqual(255, 0x000000FF & colorMap[output[65535]]); }
public IColorMap CreateColorMap() { IColorMap baseColorMap; if (_colorMapName == HotIronColorMapFactory.ColorMapName) { baseColorMap = new HotIronColorMapFactory().Create(); } else { using (LutFactory lutFactory = LutFactory.Create()) { baseColorMap = lutFactory.GetColorMap(_colorMapName); } } return(new AlphaColorMap(baseColorMap, _alpha, _thresholding)); }
/// <summary> /// Builds the volume array. Takes care of Gantry Tilt correction (pads rows at top/bottom accordingly) /// </summary> private ushort[] BuildVolumeArray(ushort pixelPadValue, double normalizedSlope, double normalizedIntercept, out int minVolumeValue, out int maxVolumeValue) { var volumeSize = VolumeSize; var volumeData = MemoryManager.Allocate <ushort>(volumeSize.Volume, TimeSpan.FromSeconds(10)); var refFramePos = _frames[0].Frame.ImagePlaneHelper.ImagePositionPatientVector; var paddingRows = PaddingRows; var skewAngleY = SkewAngleY; var volumePaddedFrameSize = volumeSize.Width * volumeSize.Height; var progressCallback = new FrameCopyProgressTracker(_frames.Count, _callback); var frameRanges = Enumerable.Range(0, _frames.Count) .AsParallel2() .Select(n => { var position = n * volumePaddedFrameSize; var sourceFrame = _frames[n].Frame; int paddingTopRows = 0, paddingBottomRows = 0; if (paddingRows > 0) { // determine the number of rows to be padded at top and bottom var framePadRowsMm = Math.Sin(skewAngleY) * (refFramePos - sourceFrame.ImagePlaneHelper.ImagePositionPatientVector).Magnitude; var framePadRows = Math.Min(paddingRows, (int)(Math.Abs(framePadRowsMm / VoxelSpacing.Y) + 0.5f)); // when the skew angle is negative, the above calculation gives the rows to pad at the top of the frame paddingTopRows = skewAngleY < 0 ? framePadRows : paddingRows - framePadRows; paddingBottomRows = paddingRows - paddingTopRows; } int frameMinPixelValue, frameMaxPixelValue; using (var lutFactory = LutFactory.Create()) // lut factory isn't thread safe, so we create one when needed in the worker thread FillVolumeFrame(volumeData, position, volumeSize.Width, sourceFrame, pixelPadValue, normalizedSlope, normalizedIntercept, paddingTopRows, paddingBottomRows, lutFactory, out frameMinPixelValue, out frameMaxPixelValue); progressCallback.IncrementAndNotify(); return(new { Min = frameMinPixelValue, Max = frameMaxPixelValue }); }).ToList(); minVolumeValue = frameRanges.Select(r => r.Min).Min(); maxVolumeValue = frameRanges.Select(r => r.Max).Max(); return(volumeData); }
public void Init() { Platform.SetExtensionFactory(new NullExtensionFactory()); MemoryManager.Enabled = false; _lutFactory = LutFactory.Create(); }
// Builds the volume array. Takes care of Gantry Tilt correction (pads rows at top/bottom accordingly) private ushort[] BuildVolumeArray(ushort pixelPadValue, double normalizedSlope, double normalizedIntercept, out int minVolumeValue, out int maxVolumeValue) { var volumeData = MemoryManager.Allocate <ushort>(VolumeSize.Volume, TimeSpan.FromSeconds(10)); var min = int.MaxValue; var max = int.MinValue; float lastFramePos = (float)_frames[_frames.Count - 1].Frame.ImagePositionPatient.Z; int position = 0; using (var lutFactory = LutFactory.Create()) { for (var n = 0; n < _frames.Count; n++) { var sourceFrame = _frames[n].Frame; var frameDimensions = VolumeSize; var paddingRows = PaddingRows; var gantryTilt = GantryTilt; // PadTop takes care of padding rows for gantry tilt correction int countRowsPaddedAtTop = 0; if (paddingRows > 0) { // figure out how many rows need to be padded at the top float deltaMm = lastFramePos - (float)sourceFrame.ImagePositionPatient.Z; double padTopMm = Math.Tan(gantryTilt) * deltaMm; countRowsPaddedAtTop = (int)(padTopMm / this.VoxelSpacing.Y + 0.5f); //TODO (cr Oct 2009): verify that IPP of the first image is correct for the volume. // account for the tilt in negative radians: we start padding from the bottom first in this case if (gantryTilt < 0) { countRowsPaddedAtTop += paddingRows; } int stop = position + countRowsPaddedAtTop * frameDimensions.Width; for (int i = position; i < stop; i++) { volumeData[i] = pixelPadValue; } position = stop; } // Copy frame data var frameData = sourceFrame.GetNormalizedPixelData(); var frameBitsStored = sourceFrame.BitsStored; var frameBytesPerPixel = sourceFrame.BitsAllocated / 8; var frameIsSigned = sourceFrame.PixelRepresentation != 0; var frameModalityLut = lutFactory.GetModalityLutLinear(frameBitsStored, frameIsSigned, sourceFrame.RescaleSlope, sourceFrame.RescaleIntercept); int frameMin, frameMax; CopyFrameData(frameData, frameBytesPerPixel, frameIsSigned, frameModalityLut, volumeData, position, normalizedSlope, normalizedIntercept, out frameMin, out frameMax); position += frameData.Length / sizeof(ushort); min = Math.Min(min, frameMin); max = Math.Max(max, frameMax); // Finish out any padding left over from PadTop if (paddingRows > 0) // Pad bottom { int stop = position + ((paddingRows - countRowsPaddedAtTop) * frameDimensions.Width); for (int i = position; i < stop; i++) { volumeData[i] = pixelPadValue; } position = stop; } // update progress _callback(n, _frames.Count); } } minVolumeValue = min; maxVolumeValue = max; return(volumeData); }