/*========================================================================= Program: Visualization Toolkit Module: vtkImageReslice.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkImageReslice * @brief Reslices a volume along a new set of axes. * * vtkImageReslice is the swiss-army-knife of image geometry filters: * It can permute, rotate, flip, scale, resample, deform, and pad image * data in any combination with reasonably high efficiency. Simple * operations such as permutation, resampling and padding are done * with similar efficiently to the specialized vtkImagePermute, * vtkImageResample, and vtkImagePad filters. There are a number of * tasks that vtkImageReslice is well suited for: *

1) Application of simple rotations, scales, and translations to * an image. It is often a good idea to use vtkImageChangeInformation * to center the image first, so that scales and rotations occur around * the center rather than around the lower-left corner of the image. *

2) Resampling of one data set to match the voxel sampling of * a second data set via the SetInformationInput() method, e.g. for * the purpose of comparing two images or combining two images. * A transformation, either linear or nonlinear, can be applied * at the same time via the SetResliceTransform method if the two * images are not in the same coordinate space. *

3) Extraction of slices from an image volume. The most convenient * way to do this is to use SetResliceAxesDirectionCosines() to * specify the orientation of the slice. The direction cosines give * the x, y, and z axes for the output volume. The method * SetOutputDimensionality(2) is used to specify that want to output a * slice rather than a volume. The SetResliceAxesOrigin() command is * used to provide an (x,y,z) point that the slice will pass through. * You can use both the ResliceAxes and the ResliceTransform at the * same time, in order to extract slices from a volume that you have * applied a transformation to. * @warning * This filter is very inefficient if the output X dimension is 1. * @sa * vtkAbstractTransform vtkMatrix4x4 */ #ifndef vtkImageReslice_h #define vtkImageReslice_h #include "vtkImagingCoreModule.h" // For export macro #include "vtkThreadedImageAlgorithm.h" // interpolation mode constants #define VTK_RESLICE_NEAREST VTK_NEAREST_INTERPOLATION #define VTK_RESLICE_LINEAR VTK_LINEAR_INTERPOLATION #define VTK_RESLICE_CUBIC VTK_CUBIC_INTERPOLATION class vtkImageData; class vtkAbstractTransform; class vtkMatrix4x4; class vtkImageStencilData; class vtkScalarsToColors; class vtkAbstractImageInterpolator; class VTKIMAGINGCORE_EXPORT vtkImageReslice : public vtkThreadedImageAlgorithm { public: static vtkImageReslice* New(); vtkTypeMacro(vtkImageReslice, vtkThreadedImageAlgorithm); void PrintSelf(ostream& os, vtkIndent indent) override; //@{ /** * This method is used to set up the axes for the output voxels. * The output Spacing, Origin, and Extent specify the locations * of the voxels within the coordinate system defined by the axes. * The ResliceAxes are used most often to permute the data, e.g. * to extract ZY or XZ slices of a volume as 2D XY images. *

The first column of the matrix specifies the x-axis * vector (the fourth element must be set to zero), the second * column specifies the y-axis, and the third column the * z-axis. The fourth column is the origin of the * axes (the fourth element must be set to one). *

An alternative to SetResliceAxes() is to use * SetResliceAxesDirectionCosines() to set the directions of the * axes and SetResliceAxesOrigin() to set the origin of the axes. */ virtual void SetResliceAxes(vtkMatrix4x4*); vtkGetObjectMacro(ResliceAxes, vtkMatrix4x4); //@} //@{ /** * Specify the direction cosines for the ResliceAxes (i.e. the * first three elements of each of the first three columns of * the ResliceAxes matrix). This will modify the current * ResliceAxes matrix, or create a new matrix if none exists. */ void SetResliceAxesDirectionCosines(double x0, double x1, double x2, double y0, double y1, double y2, double z0, double z1, double z2); void SetResliceAxesDirectionCosines(const double x[3], const double y[3], const double z[3]) { this->SetResliceAxesDirectionCosines(x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]); } void SetResliceAxesDirectionCosines(const double xyz[9]) { this->SetResliceAxesDirectionCosines( xyz[0], xyz[1], xyz[2], xyz[3], xyz[4], xyz[5], xyz[6], xyz[7], xyz[8]); } void GetResliceAxesDirectionCosines(double x[3], double y[3], double z[3]); void GetResliceAxesDirectionCosines(double xyz[9]) { this->GetResliceAxesDirectionCosines(&xyz[0], &xyz[3], &xyz[6]); } double* GetResliceAxesDirectionCosines() VTK_SIZEHINT(9) { this->GetResliceAxesDirectionCosines(this->ResliceAxesDirectionCosines); return this->ResliceAxesDirectionCosines; } //@} //@{ /** * Specify the origin for the ResliceAxes (i.e. the first three * elements of the final column of the ResliceAxes matrix). * This will modify the current ResliceAxes matrix, or create * new matrix if none exists. */ void SetResliceAxesOrigin(double x, double y, double z); void SetResliceAxesOrigin(const double xyz[3]) { this->SetResliceAxesOrigin(xyz[0], xyz[1], xyz[2]); } void GetResliceAxesOrigin(double xyz[3]); double* GetResliceAxesOrigin() VTK_SIZEHINT(3) { this->GetResliceAxesOrigin(this->ResliceAxesOrigin); return this->ResliceAxesOrigin; } //@} //@{ /** * Set a transform to be applied to the resampling grid that has * been defined via the ResliceAxes and the output Origin, Spacing * and Extent. Note that applying a transform to the resampling * grid (which lies in the output coordinate system) is * equivalent to applying the inverse of that transform to * the input volume. Nonlinear transforms such as vtkGridTransform * and vtkThinPlateSplineTransform can be used here. */ virtual void SetResliceTransform(vtkAbstractTransform*); vtkGetObjectMacro(ResliceTransform, vtkAbstractTransform); //@} //@{ /** * Set a vtkImageData from which the default Spacing, Origin, * and WholeExtent of the output will be copied. The spacing, * origin, and extent will be permuted according to the * ResliceAxes. Any values set via SetOutputSpacing, * SetOutputOrigin, and SetOutputExtent will override these * values. By default, the Spacing, Origin, and WholeExtent * of the Input are used. */ virtual void SetInformationInput(vtkImageData*); vtkGetObjectMacro(InformationInput, vtkImageData); //@} //@{ /** * Specify whether to transform the spacing, origin and extent * of the Input (or the InformationInput) according to the * direction cosines and origin of the ResliceAxes before applying * them as the default output spacing, origin and extent * (default: On). */ vtkSetMacro(TransformInputSampling, vtkTypeBool); vtkBooleanMacro(TransformInputSampling, vtkTypeBool); vtkGetMacro(TransformInputSampling, vtkTypeBool); //@} //@{ /** * Turn this on if you want to guarantee that the extent of the * output will be large enough to ensure that none of the * data will be cropped (default: Off). */ vtkSetMacro(AutoCropOutput, vtkTypeBool); vtkBooleanMacro(AutoCropOutput, vtkTypeBool); vtkGetMacro(AutoCropOutput, vtkTypeBool); //@} //@{ /** * Turn on wrap-pad feature (default: Off). */ vtkSetMacro(Wrap, vtkTypeBool); vtkGetMacro(Wrap, vtkTypeBool); vtkBooleanMacro(Wrap, vtkTypeBool); //@} //@{ /** * Turn on mirror-pad feature (default: Off). * This will override the wrap-pad. */ vtkSetMacro(Mirror, vtkTypeBool); vtkGetMacro(Mirror, vtkTypeBool); vtkBooleanMacro(Mirror, vtkTypeBool); //@} //@{ /** * Extend the apparent input border by a half voxel (default: On). * This changes how interpolation is handled at the borders of the * input image: if the center of an output voxel is beyond the edge * of the input image, but is within a half voxel width of the edge * (using the input voxel width), then the value of the output voxel * is calculated as if the input's edge voxels were duplicated past * the edges of the input. * This has no effect if Mirror or Wrap are on. */ vtkSetMacro(Border, vtkTypeBool); vtkGetMacro(Border, vtkTypeBool); vtkBooleanMacro(Border, vtkTypeBool); //@} //@{ /** * Set the border thickness for BorderOn() (default: 0.5). * See SetBorder() for more information. */ //@{ vtkSetMacro(BorderThickness, double); vtkGetMacro(BorderThickness, double); //@} /** * Set interpolation mode (default: nearest neighbor). */ vtkSetClampMacro(InterpolationMode, int, VTK_RESLICE_NEAREST, VTK_RESLICE_CUBIC); vtkGetMacro(InterpolationMode, int); void SetInterpolationModeToNearestNeighbor() { this->SetInterpolationMode(VTK_RESLICE_NEAREST); } void SetInterpolationModeToLinear() { this->SetInterpolationMode(VTK_RESLICE_LINEAR); } void SetInterpolationModeToCubic() { this->SetInterpolationMode(VTK_RESLICE_CUBIC); } virtual const char* GetInterpolationModeAsString(); //@} //@{ /** * Set the interpolator to use. The default interpolator * supports the Nearest, Linear, and Cubic interpolation modes. */ virtual void SetInterpolator(vtkAbstractImageInterpolator* sampler); virtual vtkAbstractImageInterpolator* GetInterpolator(); //@} //@{ /** * Set the slab mode, for generating thick slices. The default is Mean. * If SetSlabNumberOfSlices(N) is called with N greater than one, then * each output slice will actually be a composite of N slices. This method * specifies the compositing mode to be used. */ vtkSetClampMacro(SlabMode, int, VTK_IMAGE_SLAB_MIN, VTK_IMAGE_SLAB_SUM); vtkGetMacro(SlabMode, int); void SetSlabModeToMin() { this->SetSlabMode(VTK_IMAGE_SLAB_MIN); } void SetSlabModeToMax() { this->SetSlabMode(VTK_IMAGE_SLAB_MAX); } void SetSlabModeToMean() { this->SetSlabMode(VTK_IMAGE_SLAB_MEAN); } void SetSlabModeToSum() { this->SetSlabMode(VTK_IMAGE_SLAB_SUM); } virtual const char* GetSlabModeAsString(); //@} //@{ /** * Set the number of slices that will be combined to create the slab. */ vtkSetMacro(SlabNumberOfSlices, int); vtkGetMacro(SlabNumberOfSlices, int); //@} //@{ /** * Use trapezoid integration for slab computation. All this does is * weigh the first and last slices by half when doing sum and mean. * It is off by default. */ vtkSetMacro(SlabTrapezoidIntegration, vtkTypeBool); vtkBooleanMacro(SlabTrapezoidIntegration, vtkTypeBool); vtkGetMacro(SlabTrapezoidIntegration, vtkTypeBool); //@} //@{ /** * The slab spacing as a fraction of the output slice spacing. * When one of the various slab modes is chosen, each output slice is * produced by generating several "temporary" output slices and then * combining them according to the slab mode. By default, the spacing * between these temporary slices is the Z component of the OutputSpacing. * This method sets the spacing between these temporary slices to be a * fraction of the output spacing. */ vtkSetMacro(SlabSliceSpacingFraction, double); vtkGetMacro(SlabSliceSpacingFraction, double); //@} //@{ /** * Turn on and off optimizations (default on, they should only be * turned off for testing purposes). */ vtkSetMacro(Optimization, vtkTypeBool); vtkGetMacro(Optimization, vtkTypeBool); vtkBooleanMacro(Optimization, vtkTypeBool); //@} //@{ /** * Set a value to add to all the output voxels. * After a sample value has been interpolated from the input image, the * equation u = (v + ScalarShift)*ScalarScale will be applied to it before * it is written to the output image. The result will always be clamped to * the limits of the output data type. */ vtkSetMacro(ScalarShift, double); vtkGetMacro(ScalarShift, double); //@} //@{ /** * Set multiplication factor to apply to all the output voxels. * After a sample value has been interpolated from the input image, the * equation u = (v + ScalarShift)*ScalarScale will be applied to it before * it is written to the output image. The result will always be clamped to * the limits of the output data type. */ vtkSetMacro(ScalarScale, double); vtkGetMacro(ScalarScale, double); //@} //@{ /** * Set the scalar type of the output to be different from the input. * The default value is -1, which means that the input scalar type will be * used to set the output scalar type. Otherwise, this must be set to one * of the following types: VTK_CHAR, VTK_SIGNED_CHAR, VTK_UNSIGNED_CHAR, * VTK_SHORT, VTK_UNSIGNED_SHORT, VTK_INT, VTK_UNSIGNED_INT, VTK_FLOAT, * or VTK_DOUBLE. Other types are not permitted. If the output type * is an integer type, the output will be rounded and clamped to the * limits of the type. */ vtkSetMacro(OutputScalarType, int); vtkGetMacro(OutputScalarType, int); //@} //@{ /** * Set the background color (for multi-component images). */ vtkSetVector4Macro(BackgroundColor, double); vtkGetVector4Macro(BackgroundColor, double); //@} //@{ /** * Set background grey level (for single-component images). */ void SetBackgroundLevel(double v) { this->SetBackgroundColor(v, v, v, v); } double GetBackgroundLevel() { return this->GetBackgroundColor()[0]; } //@} //@{ /** * Set the voxel spacing for the output data. The default output * spacing is the input spacing permuted through the ResliceAxes. */ virtual void SetOutputSpacing(double x, double y, double z); virtual void SetOutputSpacing(const double a[3]) { this->SetOutputSpacing(a[0], a[1], a[2]); } vtkGetVector3Macro(OutputSpacing, double); void SetOutputSpacingToDefault(); //@} //@{ /** * Set the origin for the output data. The default output origin * is the input origin permuted through the ResliceAxes. */ virtual void SetOutputOrigin(double x, double y, double z); virtual void SetOutputOrigin(const double a[3]) { this->SetOutputOrigin(a[0], a[1], a[2]); } vtkGetVector3Macro(OutputOrigin, double); void SetOutputOriginToDefault(); //@} //@{ /** * Set the extent for the output data. The default output extent * is the input extent permuted through the ResliceAxes. */ virtual void SetOutputExtent(int a, int b, int c, int d, int e, int f); virtual void SetOutputExtent(const int a[6]) { this->SetOutputExtent(a[0], a[1], a[2], a[3], a[4], a[5]); } vtkGetVector6Macro(OutputExtent, int); void SetOutputExtentToDefault(); //@} //@{ /** * Force the dimensionality of the output to either 1, 2, * 3 or 0 (default: 3). If the dimensionality is 2D, then * the Z extent of the output is forced to (0,0) and the Z * origin of the output is forced to 0.0 (i.e. the output * extent is confined to the xy plane). If the dimensionality * is 1D, the output extent is confined to the x axis. * For 0D, the output extent consists of a single voxel at * (0,0,0). */ vtkSetMacro(OutputDimensionality, int); vtkGetMacro(OutputDimensionality, int); //@} /** * When determining the modified time of the filter, * this check the modified time of the transform and matrix. */ vtkMTimeType GetMTime() override; /** * Report object referenced by instances of this class. */ void ReportReferences(vtkGarbageCollector*) override; //@{ /** * Convenient methods for switching between nearest-neighbor and linear * interpolation. * InterpolateOn() is equivalent to SetInterpolationModeToLinear() and * InterpolateOff() is equivalent to SetInterpolationModeToNearestNeighbor() * You should not use these methods if you use the SetInterpolationMode * methods. */ void SetInterpolate(int t) { if (t && !this->GetInterpolate()) { this->SetInterpolationModeToLinear(); } else if (!t && this->GetInterpolate()) { this->SetInterpolationModeToNearestNeighbor(); } } void InterpolateOn() { this->SetInterpolate(1); } void InterpolateOff() { this->SetInterpolate(0); } int GetInterpolate() { return (this->GetInterpolationMode() != VTK_RESLICE_NEAREST); } //@} //@{ /** * Use a stencil to limit the calculations to a specific region of * the output. Portions of the output that are 'outside' the stencil * will be cleared to the background color. */ void SetStencilData(vtkImageStencilData* stencil); vtkImageStencilData* GetStencil(); //@} //@{ /** * Generate an output stencil that defines which pixels were * interpolated and which pixels were out-of-bounds of the input. */ vtkSetMacro(GenerateStencilOutput, vtkTypeBool); vtkGetMacro(GenerateStencilOutput, vtkTypeBool); vtkBooleanMacro(GenerateStencilOutput, vtkTypeBool); //@} //@{ /** * Get the output stencil. */ vtkAlgorithmOutput* GetStencilOutputPort() { return this->GetOutputPort(1); } vtkImageStencilData* GetStencilOutput(); void SetStencilOutput(vtkImageStencilData* stencil); //@} protected: vtkImageReslice(); ~vtkImageReslice() override; vtkMatrix4x4* ResliceAxes; double ResliceAxesDirectionCosines[9]; double ResliceAxesOrigin[3]; vtkAbstractTransform* ResliceTransform; vtkAbstractImageInterpolator* Interpolator; vtkImageData* InformationInput; vtkTypeBool Wrap; vtkTypeBool Mirror; vtkTypeBool Border; int InterpolationMode; vtkTypeBool Optimization; int SlabMode; int SlabNumberOfSlices; vtkTypeBool SlabTrapezoidIntegration; double SlabSliceSpacingFraction; double ScalarShift; double ScalarScale; double BorderThickness; double BackgroundColor[4]; double OutputOrigin[3]; double OutputSpacing[3]; int OutputExtent[6]; int OutputScalarType; int OutputDimensionality; vtkTypeBool TransformInputSampling; vtkTypeBool AutoCropOutput; int HitInputExtent; int UsePermuteExecute; int ComputeOutputSpacing; int ComputeOutputOrigin; int ComputeOutputExtent; vtkTypeBool GenerateStencilOutput; vtkMatrix4x4* IndexMatrix; vtkAbstractTransform* OptimizedTransform; /** * This should be set to 1 by derived classes that override the * ConvertScalars method. */ int HasConvertScalars; /** * This should be overridden by derived classes that operate on * the interpolated data before it is placed in the output. */ virtual int ConvertScalarInfo(int& scalarType, int& numComponents); /** * This should be overridden by derived classes that operate on * the interpolated data before it is placed in the output. * The input data will usually be double or float (since the * interpolation routines use floating-point) but it could be * of any type. This method will be called from multiple threads, * so it must be thread-safe in derived classes. */ virtual void ConvertScalars(void* inPtr, void* outPtr, int inputType, int inputNumComponents, int count, int idX, int idY, int idZ, int threadId); void ConvertScalarsBase(void* inPtr, void* outPtr, int inputType, int inputNumComponents, int count, int idX, int idY, int idZ, int threadId) { this->ConvertScalars( inPtr, outPtr, inputType, inputNumComponents, count, idX, idY, idZ, threadId); } void GetAutoCroppedOutputBounds(vtkInformation* inInfo, double bounds[6]); void AllocateOutputData(vtkImageData* output, vtkInformation* outInfo, int* uExtent) override; vtkImageData* AllocateOutputData(vtkDataObject*, vtkInformation*) override; int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; void ThreadedRequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector, vtkImageData*** inData, vtkImageData** outData, int ext[6], int id) override; int FillInputPortInformation(int port, vtkInformation* info) override; int FillOutputPortInformation(int port, vtkInformation* info) override; vtkMatrix4x4* GetIndexMatrix(vtkInformation* inInfo, vtkInformation* outInfo); vtkAbstractTransform* GetOptimizedTransform() { return this->OptimizedTransform; } private: vtkImageReslice(const vtkImageReslice&) = delete; void operator=(const vtkImageReslice&) = delete; }; #endif