Exemple #1
0
        /// <summary>
        /// Rotates volume along given axis.
        /// </summary>
        /// <param name="volume"></param>
        /// <param name="angles"></param>
        public static void RotateData(ref vtkImageData volume, double[] angles)
        {
            // Rotation along image center
            double[] center = volume.GetExtent().Divide(2);
            // Dimensions of rotated image
            int[] outExtent = volume.GetExtent().Multiply(1.1).Round().ToInt32();

            // Rotation parameters
            var rotate = new vtkTransform();

            rotate.Translate(center[1], center[3], center[5]);
            rotate.RotateX(angles[0]);
            rotate.RotateY(angles[1]);
            rotate.RotateZ(angles[2]); // z angle should be 0
            rotate.Translate(-center[1], -center[3], -center[5]);

            // Perform rotation
            var slice = new vtkImageReslice();

            slice.SetInput(volume);
            slice.SetResliceTransform(rotate);
            slice.SetInterpolationModeToCubic();
            slice.SetOutputSpacing(volume.GetSpacing()[0], volume.GetSpacing()[1], volume.GetSpacing()[2]);
            slice.SetOutputOrigin(volume.GetOrigin()[0], volume.GetOrigin()[1], volume.GetOrigin()[2]);
            slice.SetOutputExtent(outExtent[0], outExtent[1], outExtent[2], outExtent[3], outExtent[4], outExtent[5]);
        }
Exemple #2
0
        /// <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);
                            }
                        }
        }
Exemple #3
0
        /// <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);
                            }
                        }
        }
Exemple #4
0
	// Extract slab in specified orientation, if slabThickness is 1, this is identical
	//	to GenerateVtkSlice above, so they should be collapsed at some point.
	// TODO: Tie into Dicom for slice, will need to adjust thickness at least
		private vtkImageData GenerateVtkSlab(Matrix resliceAxes, int slabThicknessInVoxels)
		{
            VtkHelper.StaticInitializationHack();

			// Thickness should be at least 1
			if (slabThicknessInVoxels < 1)
				slabThicknessInVoxels = 1;

			using (vtkImageReslice reslicer = new vtkImageReslice())
			{
				VtkHelper.RegisterVtkErrorEvents(reslicer);

				// Obtain a pinned VTK volume for the reslicer. We'll release this when
				//	VTK is done reslicing.
				vtkImageData volumeVtkWrapper = _volume.ObtainPinnedVtkVolume();
				reslicer.SetInput(volumeVtkWrapper);
				reslicer.SetInformationInput(volumeVtkWrapper);

				if (slabThicknessInVoxels > 1)
					reslicer.SetOutputDimensionality(3);
				else
					reslicer.SetOutputDimensionality(3);

				// Use the volume's padding value for all pixels that are outside the volume
				reslicer.SetBackgroundLevel(_volume.PadValue);

				// This ensures VTK obeys the real spacing, results in all VTK slices being isotropic.
				//	Effective spacing is the minimum of these three.
				reslicer.SetOutputSpacing(_volume.Spacing.X, _volume.Spacing.Y, _volume.Spacing.Z);

				reslicer.SetResliceAxes(VtkHelper.ConvertToVtkMatrix(resliceAxes));

				// Clamp the output based on the slice extent
				int sliceExtentX = GetSliceExtentX();
				int sliceExtentY = GetSliceExtentY();
				reslicer.SetOutputExtent(0, sliceExtentX - 1, 0, sliceExtentY - 1, 0, slabThicknessInVoxels-1);

				// Set the output origin to reflect the slice through point. The slice extent is
				//	centered on the slice through point.
				// VTK output origin is derived from the center image being 0,0
				float originX = -sliceExtentX * EffectiveSpacing / 2;
				float originY = -sliceExtentY * EffectiveSpacing / 2;
				reslicer.SetOutputOrigin(originX, originY, 0);

				switch (_slicing.InterpolationMode)
				{
					case InterpolationModes.NearestNeighbor:
						reslicer.SetInterpolationModeToNearestNeighbor();
						break;
					case InterpolationModes.Linear:
						reslicer.SetInterpolationModeToLinear();
						break;
					case InterpolationModes.Cubic:
						reslicer.SetInterpolationModeToCubic();
						break;
				}

				using (vtkExecutive exec = reslicer.GetExecutive())
				{
					VtkHelper.RegisterVtkErrorEvents(exec);

					exec.Update();

					_volume.ReleasePinnedVtkVolume();

					return reslicer.GetOutput();
				}
			}
		}
Exemple #5
0
		// Extract slice in specified orientation
		private vtkImageData GenerateVtkSlice(Matrix resliceAxes)
		{
			using (vtkImageReslice reslicer = new vtkImageReslice())
			{
				VtkHelper.RegisterVtkErrorEvents(reslicer);

				// Obtain a pinned VTK volume for the reslicer. We'll release this when
				//	VTK is done reslicing.
				using (var volume = _volume.Volume.CreateVtkVolumeHandle())
				{
					reslicer.SetInput(volume.vtkImageData);
					reslicer.SetInformationInput(volume.vtkImageData);

					// Must 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(_volume.Volume.PaddingValue);

					// This ensures VTK obeys the real spacing, results in all VTK slices being isotropic.
					//	Effective spacing is the minimum of these three.
					reslicer.SetOutputSpacing(_volume.Volume.VoxelSpacing.X, _volume.Volume.VoxelSpacing.Y, _volume.Volume.VoxelSpacing.Z);

					using (vtkMatrix4x4 resliceAxesMatrix = VtkHelper.ConvertToVtkMatrix(resliceAxes))
					{
						reslicer.SetResliceAxes(resliceAxesMatrix);

						// Clamp the output based on the slice extent
						int sliceExtentX = GetSliceExtentX();
						int sliceExtentY = GetSliceExtentY();
						reslicer.SetOutputExtent(0, sliceExtentX - 1, 0, sliceExtentY - 1, 0, 0);

						// Set the output origin to reflect the slice through point. The slice extent is
						//	centered on the slice through point.
						// VTK output origin is derived from the center image being 0,0
						float originX = -sliceExtentX*EffectiveSpacing/2;
						float originY = -sliceExtentY*EffectiveSpacing/2;
						reslicer.SetOutputOrigin(originX, originY, 0);

						switch (_slicerParams.InterpolationMode)
						{
							case VolumeSlicerInterpolationMode.NearestNeighbor:
								reslicer.SetInterpolationModeToNearestNeighbor();
								break;
							case VolumeSlicerInterpolationMode.Linear:
								reslicer.SetInterpolationModeToLinear();
								break;
							case VolumeSlicerInterpolationMode.Cubic:
								reslicer.SetInterpolationModeToCubic();
								break;
						}

						using (vtkExecutive exec = reslicer.GetExecutive())
						{
							VtkHelper.RegisterVtkErrorEvents(exec);
							exec.Update();
						}

						var output = reslicer.GetOutput();
						//Just in case VTK uses the matrix internally.
						return output;
					}
				}
			}
		}
		/// <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;
				}
			}
		}
Exemple #8
0
        // Extract slab in specified orientation, if slabThickness is 1, this is identical
        //	to GenerateVtkSlice above, so they should be collapsed at some point.
        // TODO: Tie into Dicom for slice, will need to adjust thickness at least
        private vtkImageData GenerateVtkSlab(Matrix resliceAxes, int slabThicknessInVoxels)
        {
            VtkHelper.StaticInitializationHack();

            // Thickness should be at least 1
            if (slabThicknessInVoxels < 1)
            {
                slabThicknessInVoxels = 1;
            }

            using (vtkImageReslice reslicer = new vtkImageReslice())
            {
                VtkHelper.RegisterVtkErrorEvents(reslicer);

                // Obtain a pinned VTK volume for the reslicer. We'll release this when
                //	VTK is done reslicing.
                vtkImageData volumeVtkWrapper = _volume.ObtainPinnedVtkVolume();
                reslicer.SetInput(volumeVtkWrapper);
                reslicer.SetInformationInput(volumeVtkWrapper);

                if (slabThicknessInVoxels > 1)
                {
                    reslicer.SetOutputDimensionality(3);
                }
                else
                {
                    reslicer.SetOutputDimensionality(3);
                }

                // Use the volume's padding value for all pixels that are outside the volume
                reslicer.SetBackgroundLevel(_volume.PadValue);

                // This ensures VTK obeys the real spacing, results in all VTK slices being isotropic.
                //	Effective spacing is the minimum of these three.
                reslicer.SetOutputSpacing(_volume.Spacing.X, _volume.Spacing.Y, _volume.Spacing.Z);

                reslicer.SetResliceAxes(VtkHelper.ConvertToVtkMatrix(resliceAxes));

                // Clamp the output based on the slice extent
                int sliceExtentX = GetSliceExtentX();
                int sliceExtentY = GetSliceExtentY();
                reslicer.SetOutputExtent(0, sliceExtentX - 1, 0, sliceExtentY - 1, 0, slabThicknessInVoxels - 1);

                // Set the output origin to reflect the slice through point. The slice extent is
                //	centered on the slice through point.
                // VTK output origin is derived from the center image being 0,0
                float originX = -sliceExtentX * EffectiveSpacing / 2;
                float originY = -sliceExtentY * EffectiveSpacing / 2;
                reslicer.SetOutputOrigin(originX, originY, 0);

                switch (_slicing.InterpolationMode)
                {
                case InterpolationModes.NearestNeighbor:
                    reslicer.SetInterpolationModeToNearestNeighbor();
                    break;

                case InterpolationModes.Linear:
                    reslicer.SetInterpolationModeToLinear();
                    break;

                case InterpolationModes.Cubic:
                    reslicer.SetInterpolationModeToCubic();
                    break;
                }

                using (vtkExecutive exec = reslicer.GetExecutive())
                {
                    VtkHelper.RegisterVtkErrorEvents(exec);

                    exec.Update();

                    _volume.ReleasePinnedVtkVolume();

                    return(reslicer.GetOutput());
                }
            }
        }
Exemple #9
0
        // Extract slice in specified orientation
        private vtkImageData GenerateVtkSlice(Matrix resliceAxes)
        {
            using (vtkImageReslice reslicer = new vtkImageReslice())
            {
                VtkHelper.RegisterVtkErrorEvents(reslicer);

                // Obtain a pinned VTK volume for the reslicer. We'll release this when
                //	VTK is done reslicing.
                using (var volume = _volume.Volume.CreateVtkVolumeHandle())
                {
                    reslicer.SetInput(volume.vtkImageData);
                    reslicer.SetInformationInput(volume.vtkImageData);

                    // Must 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(_volume.Volume.PaddingValue);

                    // This ensures VTK obeys the real spacing, results in all VTK slices being isotropic.
                    //	Effective spacing is the minimum of these three.
                    reslicer.SetOutputSpacing(_volume.Volume.VoxelSpacing.X, _volume.Volume.VoxelSpacing.Y, _volume.Volume.VoxelSpacing.Z);

                    using (vtkMatrix4x4 resliceAxesMatrix = VtkHelper.ConvertToVtkMatrix(resliceAxes))
                    {
                        reslicer.SetResliceAxes(resliceAxesMatrix);

                        // Clamp the output based on the slice extent
                        int sliceExtentX = GetSliceExtentX();
                        int sliceExtentY = GetSliceExtentY();
                        reslicer.SetOutputExtent(0, sliceExtentX - 1, 0, sliceExtentY - 1, 0, 0);

                        // Set the output origin to reflect the slice through point. The slice extent is
                        //	centered on the slice through point.
                        // VTK output origin is derived from the center image being 0,0
                        float originX = -sliceExtentX * EffectiveSpacing / 2;
                        float originY = -sliceExtentY * EffectiveSpacing / 2;
                        reslicer.SetOutputOrigin(originX, originY, 0);

                        switch (_slicerParams.InterpolationMode)
                        {
                        case VolumeSlicerInterpolationMode.NearestNeighbor:
                            reslicer.SetInterpolationModeToNearestNeighbor();
                            break;

                        case VolumeSlicerInterpolationMode.Linear:
                            reslicer.SetInterpolationModeToLinear();
                            break;

                        case VolumeSlicerInterpolationMode.Cubic:
                            reslicer.SetInterpolationModeToCubic();
                            break;
                        }

                        using (vtkExecutive exec = reslicer.GetExecutive())
                        {
                            VtkHelper.RegisterVtkErrorEvents(exec);
                            exec.Update();
                        }

                        var output = reslicer.GetOutput();
                        //Just in case VTK uses the matrix internally.
                        return(output);
                    }
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Rotates 3D vtk volume around x and y axes.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="angle"></param>
        /// <param name="axis"></param>
        /// <param name="out_extent"></param>
        /// <returns></returns>
        public static vtkImageData rotate_sample(vtkImageData input, double angle, int axis, int out_extent = 0)
        {
            //get input data dimensions
            int[] dims = input.GetExtent();
            //Compute centers
            int[] centers = new int[] { (dims[1] + dims[0]) / 2, (dims[3] + dims[2]) / 2, (dims[5] + dims[4]) / 2 };

            //Set rotation axis
            int[] axes = new int[3];
            axes[axis] = 1;

            int[] new_dims    = new int[] { dims[0], dims[1], dims[2], dims[3], dims[4], dims[5] };
            int[] new_centers = new int[] { centers[0], centers[1], centers[2] };

            //Compute new sample dimensions
            if (axis == 0)
            {
                new_dims[3] = (int)(Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[3] + Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);
                new_dims[5] = (int)(Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[3] + Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);

                new_centers[1] = (Math.Abs(new_dims[3]) + Math.Abs(new_dims[2])) / 2;
                new_centers[2] = (Math.Abs(new_dims[5]) + Math.Abs(new_dims[4])) / 2;
            }
            if (axis == 1)
            {
                new_dims[1] = (int)(Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[1] + Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);
                new_dims[5] = (int)(Math.Sin(Math.Abs(angle / 180) * Math.PI) * new_dims[1] + Math.Cos(Math.Abs(angle / 180) * Math.PI) * new_dims[5]);

                new_centers[0] = (Math.Abs(new_dims[0]) + Math.Abs(new_dims[1])) / 2;
                new_centers[2] = (Math.Abs(new_dims[5]) + Math.Abs(new_dims[4])) / 2;
            }


            //Image transformation
            vtkTransform transform = vtkTransform.New();

            transform.Translate(centers[0], centers[1], centers[2]);
            transform.RotateWXYZ(angle, axes[0], axes[1], axes[2]);
            if (out_extent == 0)
            {
                transform.Translate(-centers[0], -centers[1], -centers[2]);
            }
            else
            {
                transform.Translate(-new_centers[0], -new_centers[1], -new_centers[2]);
            }

            //Console.ReadKey();

            transform.Update();

            //Compute new data extent
            int[] diff = new int[] { new_dims[1] - dims[1], new_dims[3] - dims[3], new_dims[5] - dims[5] };
            new_dims[0] += diff[0] / 2; new_dims[1] -= diff[0] / 2;
            new_dims[2] += diff[1] / 2; new_dims[3] -= diff[1] / 2;
            new_dims[4] += diff[2] / 2; new_dims[5] -= diff[2] / 2;



            //Image reslicing
            vtkImageReslice rotater = vtkImageReslice.New();

            rotater.SetInput(input);
            rotater.SetInformationInput(input);
            rotater.SetResliceTransform(transform);
            rotater.SetInterpolationModeToCubic();
            //rotater.SetInterpolationModeToLinear();
            if (out_extent == 1)
            {
                rotater.SetOutputSpacing(input.GetSpacing()[0], input.GetSpacing()[1], input.GetSpacing()[2]);
                rotater.SetOutputOrigin(input.GetOrigin()[0], input.GetOrigin()[1], input.GetOrigin()[2]);
                rotater.SetOutputExtent(new_dims[0], new_dims[1], new_dims[2], new_dims[3], new_dims[4], new_dims[5]);
            }
            rotater.Update();

            vtkImageData output = vtkImageData.New();

            output.DeepCopy(rotater.GetOutput());

            rotater.Dispose();
            transform.Dispose();

            return(output);
        }