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));
            }
Example #3
0
            /// <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);
            }
Example #4
0
 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);
            }