/// <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); }
/// <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; }