/// <summary> /// Gets the pixel data representing a thick slice (a.k.a. slab) of the volume. /// </summary> private static byte[] GetSlabPixelData(IVolumeReference volumeReference, Matrix resliceAxes, Vector3D stackOrientation, int rows, int columns, int subsamples, float rowSpacing, float columnSpacing, float sliceThickness, VolumeInterpolationMode interpolation, VolumeProjectionMode projection) { if (subsamples == 0) { return(GetSlicePixelData(volumeReference, resliceAxes, rows, columns, rowSpacing, columnSpacing, interpolation)); } var subsampleSpacing = sliceThickness / (subsamples - 1); using (var reslicer = new vtkImageReslice()) using (var resliceAxesMatrix = new vtkMatrix4x4()) using (var executive = reslicer.GetExecutive()) using (var volume = volumeReference.Volume.CreateVtkVolumeHandle()) { // update the reslice axes matrix with the values from the slicing orientation resliceAxesMatrix.SetElements(resliceAxes); // determine offset for start of slab (we centre the slab on the requested slice position, as DICOM defines "image position (patient)" to be centre of the thick slice) var slabOffset = volumeReference.RotateToVolumeOrientation(-sliceThickness / 2f * stackOrientation) + new Vector3D(resliceAxes[0, 3], resliceAxes[1, 3], resliceAxes[2, 3]); resliceAxesMatrix.SetElement(0, 3, slabOffset.X); resliceAxesMatrix.SetElement(1, 3, slabOffset.Y); resliceAxesMatrix.SetElement(2, 3, slabOffset.Z); // register for errors on the reslicer reslicer.RegisterVtkErrorEvents(); // set input to the volume reslicer.SetInput(volume.vtkImageData); reslicer.SetInformationInput(volume.vtkImageData); // instruct reslicer to output a 3D slab volume reslicer.SetOutputDimensionality(3); // use the volume's padding value for all pixels that are outside the volume reslicer.SetBackgroundLevel(volumeReference.PaddingValue); // ensure the slicer outputs at our desired spacing reslicer.SetOutputSpacing(columnSpacing, rowSpacing, subsampleSpacing); // set the reslice axes reslicer.SetResliceAxes(resliceAxesMatrix); // clamp the output based on the slice extent reslicer.SetOutputExtent(0, columns - 1, 0, rows - 1, 0, subsamples - 1); // set the output origin to the slice through-point (output image will be centered on this location) // VTK output origin is derived from the center image being 0,0 reslicer.SetOutputOrigin(-columns * columnSpacing / 2, -rows * rowSpacing / 2, 0); // select the requested interpolation mode switch (interpolation) { case VolumeInterpolationMode.NearestNeighbor: reslicer.SetInterpolationModeToNearestNeighbor(); break; case VolumeInterpolationMode.Linear: reslicer.SetInterpolationModeToLinear(); break; case VolumeInterpolationMode.Cubic: reslicer.SetInterpolationModeToCubic(); break; } // select the requested slab projection mode Action <IntPtr, byte[], int, int, int, bool> slabAggregator; switch (projection) { case VolumeProjectionMode.Maximum: slabAggregator = SlabProjection.AggregateSlabMaximumIntensity; break; case VolumeProjectionMode.Minimum: slabAggregator = SlabProjection.AggregateSlabMinimumIntensity; break; case VolumeProjectionMode.Average: default: slabAggregator = SlabProjection.AggregateSlabAverageIntensity; break; } // register for errors on the reslicer executive executive.RegisterVtkErrorEvents(); executive.Update(); // get the slice output using (var imageData = reslicer.GetOutput()) { var pixelData = SlabVtkImageData(imageData, slabAggregator, volumeReference.BitsPerVoxel, volumeReference.Signed); imageData.ReleaseData(); return(pixelData); } } }
/// <summary> /// Gets the pixel data representing a thick slice (a.k.a. slab) of the volume. /// </summary> private static byte[] GetSlabPixelData(IVolumeReference volumeReference, Matrix resliceAxes, Vector3D stackOrientation, int rows, int columns, int subsamples, float rowSpacing, float columnSpacing, float sliceThickness, VolumeInterpolationMode interpolation, VolumeProjectionMode projection) { if (subsamples <= 1) return GetSlicePixelData(volumeReference, resliceAxes, rows, columns, rowSpacing, columnSpacing, interpolation); var subsampleSpacing = sliceThickness/(subsamples - 1); using (var reslicer = new vtkImageReslice()) using (var resliceAxesMatrix = new vtkMatrix4x4()) using (var executive = reslicer.GetExecutive()) using (var volume = volumeReference.Volume.CreateVtkVolumeHandle()) { // update the reslice axes matrix with the values from the slicing orientation resliceAxesMatrix.SetElements(resliceAxes); // determine offset for start of slab (we centre the slab on the requested slice position, as DICOM defines "image position (patient)" to be centre of the thick slice) var slabOffset = volumeReference.RotateToVolumeOrientation(-sliceThickness/2f*stackOrientation) + new Vector3D(resliceAxes[0, 3], resliceAxes[1, 3], resliceAxes[2, 3]); resliceAxesMatrix.SetElement(0, 3, slabOffset.X); resliceAxesMatrix.SetElement(1, 3, slabOffset.Y); resliceAxesMatrix.SetElement(2, 3, slabOffset.Z); // register for errors on the reslicer reslicer.RegisterVtkErrorEvents(); // set input to the volume reslicer.SetInput(volume.vtkImageData); reslicer.SetInformationInput(volume.vtkImageData); // instruct reslicer to output a 3D slab volume reslicer.SetOutputDimensionality(3); // use the volume's padding value for all pixels that are outside the volume reslicer.SetBackgroundLevel(volumeReference.PaddingValue); // ensure the slicer outputs at our desired spacing reslicer.SetOutputSpacing(columnSpacing, rowSpacing, subsampleSpacing); // set the reslice axes reslicer.SetResliceAxes(resliceAxesMatrix); // clamp the output based on the slice extent reslicer.SetOutputExtent(0, columns - 1, 0, rows - 1, 0, subsamples - 1); // set the output origin to the slice through-point (output image will be centered on this location) // VTK output origin is derived from the center image being 0,0 reslicer.SetOutputOrigin(-columns*columnSpacing/2, -rows*rowSpacing/2, 0); // select the requested interpolation mode switch (interpolation) { case VolumeInterpolationMode.NearestNeighbor: reslicer.SetInterpolationModeToNearestNeighbor(); break; case VolumeInterpolationMode.Linear: reslicer.SetInterpolationModeToLinear(); break; case VolumeInterpolationMode.Cubic: reslicer.SetInterpolationModeToCubic(); break; } // select the requested slab projection mode Action<IntPtr, byte[], int, int, int, bool> slabAggregator; switch (projection) { case VolumeProjectionMode.Maximum: slabAggregator = SlabProjection.AggregateSlabMaximumIntensity; break; case VolumeProjectionMode.Minimum: slabAggregator = SlabProjection.AggregateSlabMinimumIntensity; break; case VolumeProjectionMode.Average: default: slabAggregator = SlabProjection.AggregateSlabAverageIntensity; break; } // register for errors on the reslicer executive executive.RegisterVtkErrorEvents(); executive.Update(); // get the slice output using (var imageData = reslicer.GetOutput()) { var pixelData = SlabVtkImageData(imageData, slabAggregator, volumeReference.BitsPerVoxel, volumeReference.Signed); imageData.ReleaseData(); return pixelData; } } }
/// <summary> /// Gets the pixel data representing a thin slice of the volume. /// </summary> private static byte[] GetSlicePixelData(IVolumeReference volumeReference, Matrix resliceAxes, int rows, int columns, float rowSpacing, float columnSpacing, VolumeInterpolationMode interpolation) { using (var reslicer = new vtkImageReslice()) using (var resliceAxesMatrix = new vtkMatrix4x4()) using (var executive = reslicer.GetExecutive()) using (var volume = volumeReference.Volume.CreateVtkVolumeHandle()) { // update the reslice axes matrix with the values from the slicing orientation resliceAxesMatrix.SetElements(resliceAxes); // register for errors on the reslicer reslicer.RegisterVtkErrorEvents(); // set input to the volume reslicer.SetInput(volume.vtkImageData); reslicer.SetInformationInput(volume.vtkImageData); // instruct reslicer to output 2D images reslicer.SetOutputDimensionality(2); // use the volume's padding value for all pixels that are outside the volume reslicer.SetBackgroundLevel(volumeReference.PaddingValue); // ensure the slicer outputs at our desired spacing reslicer.SetOutputSpacing(columnSpacing, rowSpacing, Math.Min(columnSpacing, rowSpacing)); // set the reslice axes reslicer.SetResliceAxes(resliceAxesMatrix); // clamp the output based on the slice extent reslicer.SetOutputExtent(0, columns - 1, 0, rows - 1, 0, 0); // set the output origin to the slice through-point (output image will be centered on this location) // VTK output origin is derived from the center image being 0,0 reslicer.SetOutputOrigin(-columns * columnSpacing / 2, -rows * rowSpacing / 2, 0); // select the requested interpolation mode switch (interpolation) { case VolumeInterpolationMode.NearestNeighbor: reslicer.SetInterpolationModeToNearestNeighbor(); break; case VolumeInterpolationMode.Linear: reslicer.SetInterpolationModeToLinear(); break; case VolumeInterpolationMode.Cubic: reslicer.SetInterpolationModeToCubic(); break; } // register for errors on the reslicer executive executive.RegisterVtkErrorEvents(); executive.Update(); // get the slice output using (var imageData = reslicer.GetOutput()) { var pixelData = ReadVtkImageData(imageData); imageData.ReleaseData(); return(pixelData); } } }
/// <summary> /// Gets the pixel data representing a thin slice of the volume. /// </summary> private static byte[] GetSlicePixelData(IVolumeReference volumeReference, Matrix resliceAxes, int rows, int columns, float rowSpacing, float columnSpacing, VolumeInterpolationMode interpolation) { using (var reslicer = new vtkImageReslice()) using (var resliceAxesMatrix = new vtkMatrix4x4()) using (var executive = reslicer.GetExecutive()) using (var volume = volumeReference.Volume.CreateVtkVolumeHandle()) { // update the reslice axes matrix with the values from the slicing orientation resliceAxesMatrix.SetElements(resliceAxes); // register for errors on the reslicer reslicer.RegisterVtkErrorEvents(); // set input to the volume reslicer.SetInput(volume.vtkImageData); reslicer.SetInformationInput(volume.vtkImageData); // instruct reslicer to output 2D images reslicer.SetOutputDimensionality(2); // use the volume's padding value for all pixels that are outside the volume reslicer.SetBackgroundLevel(volumeReference.PaddingValue); // ensure the slicer outputs at our desired spacing reslicer.SetOutputSpacing(columnSpacing, rowSpacing, Math.Min(columnSpacing, rowSpacing)); // set the reslice axes reslicer.SetResliceAxes(resliceAxesMatrix); // clamp the output based on the slice extent reslicer.SetOutputExtent(0, columns - 1, 0, rows - 1, 0, 0); // set the output origin to the slice through-point (output image will be centered on this location) // VTK output origin is derived from the center image being 0,0 reslicer.SetOutputOrigin(-columns*columnSpacing/2, -rows*rowSpacing/2, 0); // select the requested interpolation mode switch (interpolation) { case VolumeInterpolationMode.NearestNeighbor: reslicer.SetInterpolationModeToNearestNeighbor(); break; case VolumeInterpolationMode.Linear: reslicer.SetInterpolationModeToLinear(); break; case VolumeInterpolationMode.Cubic: reslicer.SetInterpolationModeToCubic(); break; } // register for errors on the reslicer executive executive.RegisterVtkErrorEvents(); executive.Update(); // get the slice output using (var imageData = reslicer.GetOutput()) { var pixelData = ReadVtkImageData(imageData); imageData.ReleaseData(); return pixelData; } } }