You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3294 lines
95 KiB
3294 lines
95 KiB
2 years ago
|
/*=========================================================================
|
||
|
|
||
|
Program: Visualization Toolkit
|
||
|
Module: $RCSfile: vtkImageReslice.cxx,v $
|
||
|
|
||
|
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.
|
||
|
|
||
|
=========================================================================*/
|
||
|
#include "vtkImageReslice.h"
|
||
|
|
||
|
#include "vtkImageData.h"
|
||
|
#include "vtkImageStencilData.h"
|
||
|
#include "vtkInformation.h"
|
||
|
#include "vtkInformationVector.h"
|
||
|
#include "vtkMath.h"
|
||
|
#include "vtkObjectFactory.h"
|
||
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
||
|
#include "vtkTransform.h"
|
||
|
#include "vtkDataSetAttributes.h"
|
||
|
|
||
|
#include "vtkTemplateAliasMacro.h"
|
||
|
// turn off 64-bit ints when templating over all types
|
||
|
# undef VTK_USE_INT64
|
||
|
# define VTK_USE_INT64 0
|
||
|
# undef VTK_USE_UINT64
|
||
|
# define VTK_USE_UINT64 0
|
||
|
|
||
|
#include <limits.h>
|
||
|
#include <float.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
vtkCxxRevisionMacro(vtkImageReslice, "$Revision: 1.63.6.2 $");
|
||
|
vtkStandardNewMacro(vtkImageReslice);
|
||
|
vtkCxxSetObjectMacro(vtkImageReslice, InformationInput, vtkImageData);
|
||
|
vtkCxxSetObjectMacro(vtkImageReslice,ResliceAxes,vtkMatrix4x4);
|
||
|
vtkCxxSetObjectMacro(vtkImageReslice,ResliceTransform,vtkAbstractTransform);
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// The 'floor' function on x86 and mips is many times slower than these
|
||
|
// and is used a lot in this code, optimize for different CPU architectures
|
||
|
template<class F>
|
||
|
inline int vtkResliceFloor(double x, F &f)
|
||
|
{
|
||
|
#if defined mips || defined sparc || defined __ppc__
|
||
|
x += 2147483648.0;
|
||
|
unsigned int i = (unsigned int)(x);
|
||
|
f = x - i;
|
||
|
return (int)(i - 2147483648U);
|
||
|
#elif defined i386 || defined _M_IX86
|
||
|
union { double d; unsigned short s[4]; unsigned int i[2]; } dual;
|
||
|
dual.d = x + 103079215104.0; // (2**(52-16))*1.5
|
||
|
f = dual.s[0]*0.0000152587890625; // 2**(-16)
|
||
|
return (int)((dual.i[1]<<16)|((dual.i[0])>>16));
|
||
|
#elif defined ia64 || defined __ia64__ || defined IA64
|
||
|
x += 103079215104.0;
|
||
|
long long i = (long long)(x);
|
||
|
f = x - i;
|
||
|
return (int)(i - 103079215104LL);
|
||
|
#else
|
||
|
double y = floor(x);
|
||
|
f = x - y;
|
||
|
return (int)(y);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline int vtkResliceRound(double x)
|
||
|
{
|
||
|
#if defined mips || defined sparc || defined __ppc__
|
||
|
return (int)((unsigned int)(x + 2147483648.5) - 2147483648U);
|
||
|
#elif defined i386 || defined _M_IX86
|
||
|
union { double d; unsigned int i[2]; } dual;
|
||
|
dual.d = x + 103079215104.5; // (2**(52-16))*1.5
|
||
|
return (int)((dual.i[1]<<16)|((dual.i[0])>>16));
|
||
|
#elif defined ia64 || defined __ia64__ || defined IA64
|
||
|
x += 103079215104.5;
|
||
|
long long i = (long long)(x);
|
||
|
return (int)(i - 103079215104LL);
|
||
|
#else
|
||
|
return (int)(floor(x+0.5));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
vtkImageReslice::vtkImageReslice()
|
||
|
{
|
||
|
// if NULL, the main Input is used
|
||
|
this->InformationInput = NULL;
|
||
|
this->TransformInputSampling = 1;
|
||
|
this->AutoCropOutput = 0;
|
||
|
this->OutputDimensionality = 3;
|
||
|
|
||
|
// flag to use default Spacing
|
||
|
this->OutputSpacing[0] = VTK_DOUBLE_MAX;
|
||
|
this->OutputSpacing[1] = VTK_DOUBLE_MAX;
|
||
|
this->OutputSpacing[2] = VTK_DOUBLE_MAX;
|
||
|
|
||
|
// ditto
|
||
|
this->OutputOrigin[0] = VTK_DOUBLE_MAX;
|
||
|
this->OutputOrigin[1] = VTK_DOUBLE_MAX;
|
||
|
this->OutputOrigin[2] = VTK_DOUBLE_MAX;
|
||
|
|
||
|
// ditto
|
||
|
this->OutputExtent[0] = VTK_INT_MIN;
|
||
|
this->OutputExtent[2] = VTK_INT_MIN;
|
||
|
this->OutputExtent[4] = VTK_INT_MIN;
|
||
|
|
||
|
this->OutputExtent[1] = VTK_INT_MAX;
|
||
|
this->OutputExtent[3] = VTK_INT_MAX;
|
||
|
this->OutputExtent[5] = VTK_INT_MAX;
|
||
|
|
||
|
this->Wrap = 0; // don't wrap
|
||
|
this->Mirror = 0; // don't mirror
|
||
|
this->Border = 1; // apply a border
|
||
|
this->InterpolationMode = VTK_RESLICE_NEAREST; // no interpolation
|
||
|
this->Optimization = 1; // turn off when you're paranoid
|
||
|
|
||
|
// default black background
|
||
|
this->BackgroundColor[0] = 0;
|
||
|
this->BackgroundColor[1] = 0;
|
||
|
this->BackgroundColor[2] = 0;
|
||
|
this->BackgroundColor[3] = 0;
|
||
|
|
||
|
// default reslice axes are x, y, z
|
||
|
this->ResliceAxesDirectionCosines[0] = 1.0;
|
||
|
this->ResliceAxesDirectionCosines[1] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[2] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[3] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[4] = 1.0;
|
||
|
this->ResliceAxesDirectionCosines[5] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[6] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[7] = 0.0;
|
||
|
this->ResliceAxesDirectionCosines[8] = 1.0;
|
||
|
|
||
|
// default (0,0,0) axes origin
|
||
|
this->ResliceAxesOrigin[0] = 0.0;
|
||
|
this->ResliceAxesOrigin[1] = 0.0;
|
||
|
this->ResliceAxesOrigin[2] = 0.0;
|
||
|
|
||
|
// axes and transform are identity if set to NULL
|
||
|
this->ResliceAxes = NULL;
|
||
|
this->ResliceTransform = NULL;
|
||
|
|
||
|
// cache a matrix that converts output voxel indices -> input voxel indices
|
||
|
this->IndexMatrix = NULL;
|
||
|
this->OptimizedTransform = NULL;
|
||
|
|
||
|
// set to zero when we completely missed the input extent
|
||
|
this->HitInputExtent = 1;
|
||
|
|
||
|
// There is an optional second input.
|
||
|
this->SetNumberOfInputPorts(2);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
vtkImageReslice::~vtkImageReslice()
|
||
|
{
|
||
|
this->SetResliceTransform(NULL);
|
||
|
this->SetResliceAxes(NULL);
|
||
|
if (this->IndexMatrix)
|
||
|
{
|
||
|
this->IndexMatrix->Delete();
|
||
|
}
|
||
|
if (this->OptimizedTransform)
|
||
|
{
|
||
|
this->OptimizedTransform->Delete();
|
||
|
}
|
||
|
this->SetInformationInput(NULL);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::PrintSelf(ostream& os, vtkIndent indent)
|
||
|
{
|
||
|
this->Superclass::PrintSelf(os,indent);
|
||
|
|
||
|
os << indent << "ResliceAxes: " << this->ResliceAxes << "\n";
|
||
|
if (this->ResliceAxes)
|
||
|
{
|
||
|
this->ResliceAxes->PrintSelf(os,indent.GetNextIndent());
|
||
|
}
|
||
|
this->GetResliceAxesDirectionCosines(this->ResliceAxesDirectionCosines);
|
||
|
os << indent << "ResliceAxesDirectionCosines: " <<
|
||
|
this->ResliceAxesDirectionCosines[0] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[1] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[2] << "\n";
|
||
|
os << indent << " " <<
|
||
|
this->ResliceAxesDirectionCosines[3] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[4] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[5] << "\n";
|
||
|
os << indent << " " <<
|
||
|
this->ResliceAxesDirectionCosines[6] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[7] << " " <<
|
||
|
this->ResliceAxesDirectionCosines[8] << "\n";
|
||
|
this->GetResliceAxesOrigin(this->ResliceAxesOrigin);
|
||
|
os << indent << "ResliceAxesOrigin: " <<
|
||
|
this->ResliceAxesOrigin[0] << " " <<
|
||
|
this->ResliceAxesOrigin[1] << " " <<
|
||
|
this->ResliceAxesOrigin[2] << "\n";
|
||
|
os << indent << "ResliceTransform: " << this->ResliceTransform << "\n";
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
this->ResliceTransform->PrintSelf(os,indent.GetNextIndent());
|
||
|
}
|
||
|
os << indent << "InformationInput: " << this->InformationInput << "\n";
|
||
|
os << indent << "TransformInputSampling: " <<
|
||
|
(this->TransformInputSampling ? "On\n":"Off\n");
|
||
|
os << indent << "AutoCropOutput: " <<
|
||
|
(this->AutoCropOutput ? "On\n":"Off\n");
|
||
|
os << indent << "OutputSpacing: " << this->OutputSpacing[0] << " " <<
|
||
|
this->OutputSpacing[1] << " " << this->OutputSpacing[2] << "\n";
|
||
|
os << indent << "OutputOrigin: " << this->OutputOrigin[0] << " " <<
|
||
|
this->OutputOrigin[1] << " " << this->OutputOrigin[2] << "\n";
|
||
|
os << indent << "OutputExtent: " << this->OutputExtent[0] << " " <<
|
||
|
this->OutputExtent[1] << " " << this->OutputExtent[2] << " " <<
|
||
|
this->OutputExtent[3] << " " << this->OutputExtent[4] << " " <<
|
||
|
this->OutputExtent[5] << "\n";
|
||
|
os << indent << "OutputDimensionality: " <<
|
||
|
this->OutputDimensionality << "\n";
|
||
|
os << indent << "Wrap: " << (this->Wrap ? "On\n":"Off\n");
|
||
|
os << indent << "Mirror: " << (this->Mirror ? "On\n":"Off\n");
|
||
|
os << indent << "Border: " << (this->Border ? "On\n":"Off\n");
|
||
|
os << indent << "InterpolationMode: "
|
||
|
<< this->GetInterpolationModeAsString() << "\n";
|
||
|
os << indent << "Optimization: " << (this->Optimization ? "On\n":"Off\n");
|
||
|
os << indent << "BackgroundColor: " <<
|
||
|
this->BackgroundColor[0] << " " << this->BackgroundColor[1] << " " <<
|
||
|
this->BackgroundColor[2] << " " << this->BackgroundColor[3] << "\n";
|
||
|
os << indent << "BackgroundLevel: " << this->BackgroundColor[0] << "\n";
|
||
|
os << indent << "Stencil: " << this->GetStencil() << "\n";
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::SetStencil(vtkImageStencilData *stencil)
|
||
|
{
|
||
|
this->SetInput(1, stencil);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
vtkImageStencilData *vtkImageReslice::GetStencil()
|
||
|
{
|
||
|
if (this->GetNumberOfInputConnections(1) < 1)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
return vtkImageStencilData::SafeDownCast(
|
||
|
this->GetExecutive()->GetInputData(1, 0));
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::SetResliceAxesDirectionCosines(double x0, double x1,
|
||
|
double x2, double y0,
|
||
|
double y1, double y2,
|
||
|
double z0, double z1,
|
||
|
double z2)
|
||
|
{
|
||
|
if (!this->ResliceAxes)
|
||
|
{
|
||
|
// consistent registers/unregisters
|
||
|
this->SetResliceAxes(vtkMatrix4x4::New());
|
||
|
this->ResliceAxes->Delete();
|
||
|
this->Modified();
|
||
|
}
|
||
|
this->ResliceAxes->SetElement(0,0,x0);
|
||
|
this->ResliceAxes->SetElement(1,0,x1);
|
||
|
this->ResliceAxes->SetElement(2,0,x2);
|
||
|
this->ResliceAxes->SetElement(3,0,0);
|
||
|
this->ResliceAxes->SetElement(0,1,y0);
|
||
|
this->ResliceAxes->SetElement(1,1,y1);
|
||
|
this->ResliceAxes->SetElement(2,1,y2);
|
||
|
this->ResliceAxes->SetElement(3,1,0);
|
||
|
this->ResliceAxes->SetElement(0,2,z0);
|
||
|
this->ResliceAxes->SetElement(1,2,z1);
|
||
|
this->ResliceAxes->SetElement(2,2,z2);
|
||
|
this->ResliceAxes->SetElement(3,2,0);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::GetResliceAxesDirectionCosines(double xdircos[3],
|
||
|
double ydircos[3],
|
||
|
double zdircos[3])
|
||
|
{
|
||
|
if (!this->ResliceAxes)
|
||
|
{
|
||
|
xdircos[0] = ydircos[1] = zdircos[2] = 1;
|
||
|
xdircos[1] = ydircos[2] = zdircos[0] = 0;
|
||
|
xdircos[2] = ydircos[0] = zdircos[1] = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
xdircos[i] = this->ResliceAxes->GetElement(i,0);
|
||
|
ydircos[i] = this->ResliceAxes->GetElement(i,1);
|
||
|
zdircos[i] = this->ResliceAxes->GetElement(i,2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::SetResliceAxesOrigin(double x, double y, double z)
|
||
|
{
|
||
|
if (!this->ResliceAxes)
|
||
|
{
|
||
|
// consistent registers/unregisters
|
||
|
this->SetResliceAxes(vtkMatrix4x4::New());
|
||
|
this->ResliceAxes->Delete();
|
||
|
this->Modified();
|
||
|
}
|
||
|
|
||
|
this->ResliceAxes->SetElement(0,3,x);
|
||
|
this->ResliceAxes->SetElement(1,3,y);
|
||
|
this->ResliceAxes->SetElement(2,3,z);
|
||
|
this->ResliceAxes->SetElement(3,3,1);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::GetResliceAxesOrigin(double origin[3])
|
||
|
{
|
||
|
if (!this->ResliceAxes)
|
||
|
{
|
||
|
origin[0] = origin[1] = origin[2] = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
origin[i] = this->ResliceAxes->GetElement(i,3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Account for the MTime of the transform and its matrix when determining
|
||
|
// the MTime of the filter
|
||
|
unsigned long int vtkImageReslice::GetMTime()
|
||
|
{
|
||
|
unsigned long mTime=this->vtkObject::GetMTime();
|
||
|
unsigned long time;
|
||
|
|
||
|
if ( this->ResliceTransform != NULL )
|
||
|
{
|
||
|
time = this->ResliceTransform->GetMTime();
|
||
|
mTime = ( time > mTime ? time : mTime );
|
||
|
if (this->ResliceTransform->IsA("vtkHomogeneousTransform"))
|
||
|
{ // this is for people who directly modify the transform matrix
|
||
|
time = ((vtkHomogeneousTransform *)this->ResliceTransform)
|
||
|
->GetMatrix()->GetMTime();
|
||
|
mTime = ( time > mTime ? time : mTime );
|
||
|
}
|
||
|
}
|
||
|
if ( this->ResliceAxes != NULL)
|
||
|
{
|
||
|
time = this->ResliceAxes->GetMTime();
|
||
|
mTime = ( time > mTime ? time : mTime );
|
||
|
}
|
||
|
|
||
|
return mTime;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int vtkImageReslice::RequestUpdateExtent(
|
||
|
vtkInformation *vtkNotUsed(request),
|
||
|
vtkInformationVector **inputVector,
|
||
|
vtkInformationVector *outputVector)
|
||
|
{
|
||
|
int inExt[6], outExt[6];
|
||
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
||
|
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
|
||
|
|
||
|
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), outExt);
|
||
|
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
this->ResliceTransform->Update();
|
||
|
if (!this->ResliceTransform->IsA("vtkHomogeneousTransform"))
|
||
|
{ // update the whole input extent if the transform is nonlinear
|
||
|
inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inExt);
|
||
|
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExt, 6);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int i,j,k;
|
||
|
int idX,idY,idZ;
|
||
|
double xAxis[4], yAxis[4], zAxis[4], origin[4];
|
||
|
double inPoint0[4];
|
||
|
double inPoint1[4];
|
||
|
double point[4],f;
|
||
|
double *inSpacing,*inOrigin,*outSpacing,*outOrigin,inInvSpacing[3];
|
||
|
|
||
|
int wrap = this->Wrap || this->Mirror;
|
||
|
|
||
|
inOrigin = inInfo->Get(vtkDataObject::ORIGIN());
|
||
|
inSpacing = inInfo->Get(vtkDataObject::SPACING());
|
||
|
outOrigin = outInfo->Get(vtkDataObject::ORIGIN());
|
||
|
outSpacing = outInfo->Get(vtkDataObject::SPACING());
|
||
|
|
||
|
if (this->Optimization)
|
||
|
{
|
||
|
vtkMatrix4x4 *matrix = this->GetIndexMatrix(inInfo, outInfo);
|
||
|
|
||
|
// convert matrix from world coordinates to pixel indices
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
xAxis[i] = matrix->GetElement(i,0);
|
||
|
yAxis[i] = matrix->GetElement(i,1);
|
||
|
zAxis[i] = matrix->GetElement(i,2);
|
||
|
origin[i] = matrix->GetElement(i,3);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// save effor later: invert inSpacing
|
||
|
inInvSpacing[0] = 1.0/inSpacing[0];
|
||
|
inInvSpacing[1] = 1.0/inSpacing[1];
|
||
|
inInvSpacing[2] = 1.0/inSpacing[2];
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
inExt[2*i] = VTK_INT_MAX;
|
||
|
inExt[2*i+1] = VTK_INT_MIN;
|
||
|
}
|
||
|
|
||
|
// check the coordinates of the 8 corners of the output extent
|
||
|
// (this must be done exactly the same as the calculation in
|
||
|
// vtkImageResliceExecute)
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
// get output coords
|
||
|
idX = outExt[i%2];
|
||
|
idY = outExt[2+(i/2)%2];
|
||
|
idZ = outExt[4+(i/4)%2];
|
||
|
|
||
|
if (this->Optimization)
|
||
|
{
|
||
|
inPoint0[0] = origin[0] + idZ*zAxis[0]; // incremental transform
|
||
|
inPoint0[1] = origin[1] + idZ*zAxis[1];
|
||
|
inPoint0[2] = origin[2] + idZ*zAxis[2];
|
||
|
inPoint0[3] = origin[3] + idZ*zAxis[3];
|
||
|
|
||
|
inPoint1[0] = inPoint0[0] + idY*yAxis[0]; // incremental transform
|
||
|
inPoint1[1] = inPoint0[1] + idY*yAxis[1];
|
||
|
inPoint1[2] = inPoint0[2] + idY*yAxis[2];
|
||
|
inPoint1[3] = inPoint0[3] + idY*yAxis[3];
|
||
|
|
||
|
point[0] = inPoint1[0] + idX*xAxis[0];
|
||
|
point[1] = inPoint1[1] + idX*xAxis[1];
|
||
|
point[2] = inPoint1[2] + idX*xAxis[2];
|
||
|
point[3] = inPoint1[3] + idX*xAxis[3];
|
||
|
|
||
|
if (point[3] != 1.0)
|
||
|
{
|
||
|
f = 1/point[3];
|
||
|
point[0] *= f;
|
||
|
point[1] *= f;
|
||
|
point[2] *= f;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
point[0] = idX*outSpacing[0] + outOrigin[0];
|
||
|
point[1] = idY*outSpacing[1] + outOrigin[1];
|
||
|
point[2] = idZ*outSpacing[2] + outOrigin[2];
|
||
|
|
||
|
if (this->ResliceAxes)
|
||
|
{
|
||
|
point[3] = 1.0;
|
||
|
this->ResliceAxes->MultiplyPoint(point, point);
|
||
|
f = 1.0/point[3];
|
||
|
point[0] *= f;
|
||
|
point[1] *= f;
|
||
|
point[2] *= f;
|
||
|
}
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
this->ResliceTransform->TransformPoint(point, point);
|
||
|
}
|
||
|
|
||
|
point[0] = (point[0] - inOrigin[0])*inInvSpacing[0];
|
||
|
point[1] = (point[1] - inOrigin[1])*inInvSpacing[1];
|
||
|
point[2] = (point[2] - inOrigin[2])*inInvSpacing[2];
|
||
|
}
|
||
|
|
||
|
// set the extent appropriately according to the interpolation mode
|
||
|
if (this->GetInterpolationMode() != VTK_RESLICE_NEAREST)
|
||
|
{
|
||
|
int extra = (this->GetInterpolationMode() == VTK_RESLICE_CUBIC);
|
||
|
for (j = 0; j < 3; j++)
|
||
|
{
|
||
|
k = vtkResliceFloor(point[j], f);
|
||
|
if (f == 0)
|
||
|
{
|
||
|
if (k < inExt[2*j])
|
||
|
{
|
||
|
inExt[2*j] = k;
|
||
|
}
|
||
|
if (k > inExt[2*j+1])
|
||
|
{
|
||
|
inExt[2*j+1] = k;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (k - extra < inExt[2*j])
|
||
|
{
|
||
|
inExt[2*j] = k - extra;
|
||
|
}
|
||
|
if (k + 1 + extra > inExt[2*j+1])
|
||
|
{
|
||
|
inExt[2*j+1] = k + 1 + extra;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (j = 0; j < 3; j++)
|
||
|
{
|
||
|
k = vtkResliceRound(point[j]);
|
||
|
if (k < inExt[2*j])
|
||
|
{
|
||
|
inExt[2*j] = k;
|
||
|
}
|
||
|
if (k > inExt[2*j+1])
|
||
|
{
|
||
|
inExt[2*j+1] = k;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clip to whole extent, make sure we hit the extent
|
||
|
int wholeExtent[6];
|
||
|
inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent);
|
||
|
this->HitInputExtent = 1;
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (inExt[2*i] < wholeExtent[2*i])
|
||
|
{
|
||
|
inExt[2*i] = wholeExtent[2*i];
|
||
|
if (wrap)
|
||
|
{
|
||
|
inExt[2*i+1] = wholeExtent[2*i+1];
|
||
|
}
|
||
|
else if (inExt[2*i+1] < wholeExtent[2*i])
|
||
|
{
|
||
|
// didn't hit any of the input extent
|
||
|
inExt[2*i+1] = wholeExtent[2*i];
|
||
|
this->HitInputExtent = 0;
|
||
|
}
|
||
|
}
|
||
|
if (inExt[2*i+1] > wholeExtent[2*i+1])
|
||
|
{
|
||
|
inExt[2*i+1] = wholeExtent[2*i+1];
|
||
|
if (wrap)
|
||
|
{
|
||
|
inExt[2*i] = wholeExtent[2*i];
|
||
|
}
|
||
|
else if (inExt[2*i] > wholeExtent[2*i+1])
|
||
|
{
|
||
|
// didn't hit any of the input extent
|
||
|
inExt[2*i] = wholeExtent[2*i+1];
|
||
|
// finally, check for null input extent
|
||
|
if (inExt[2*i] < wholeExtent[2*i])
|
||
|
{
|
||
|
inExt[2*i] = wholeExtent[2*i];
|
||
|
}
|
||
|
this->HitInputExtent = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExt, 6);
|
||
|
|
||
|
// need to set the stencil update extent to the output extent
|
||
|
if (this->GetNumberOfInputConnections(1) > 0)
|
||
|
{
|
||
|
vtkInformation *stencilInfo = inputVector[1]->GetInformationObject(0);
|
||
|
stencilInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
|
||
|
outExt, 6);
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int vtkImageReslice::FillInputPortInformation(int port, vtkInformation *info)
|
||
|
{
|
||
|
if (port == 1)
|
||
|
{
|
||
|
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageStencilData");
|
||
|
// the stencil input is optional
|
||
|
info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void vtkImageReslice::GetAutoCroppedOutputBounds(vtkInformation *inInfo,
|
||
|
double bounds[6])
|
||
|
{
|
||
|
int i, j;
|
||
|
double inSpacing[3], inOrigin[3];
|
||
|
int inWholeExt[6];
|
||
|
double f;
|
||
|
double point[4];
|
||
|
|
||
|
inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inWholeExt);
|
||
|
inInfo->Get(vtkDataObject::SPACING(), inSpacing);
|
||
|
inInfo->Get(vtkDataObject::ORIGIN(), inOrigin);
|
||
|
|
||
|
vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
|
||
|
if (this->ResliceAxes)
|
||
|
{
|
||
|
vtkMatrix4x4::Invert(this->ResliceAxes, matrix);
|
||
|
}
|
||
|
vtkAbstractTransform* transform = NULL;
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
transform = this->ResliceTransform->GetInverse();
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
bounds[2*i] = VTK_DOUBLE_MAX;
|
||
|
bounds[2*i+1] = -VTK_DOUBLE_MAX;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 8; i++)
|
||
|
{
|
||
|
point[0] = inOrigin[0] + inWholeExt[i%2]*inSpacing[0];
|
||
|
point[1] = inOrigin[1] + inWholeExt[2+(i/2)%2]*inSpacing[1];
|
||
|
point[2] = inOrigin[2] + inWholeExt[4+(i/4)%2]*inSpacing[2];
|
||
|
point[3] = 1.0;
|
||
|
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
transform->TransformPoint(point,point);
|
||
|
}
|
||
|
matrix->MultiplyPoint(point,point);
|
||
|
|
||
|
f = 1.0/point[3];
|
||
|
point[0] *= f;
|
||
|
point[1] *= f;
|
||
|
point[2] *= f;
|
||
|
|
||
|
for (j = 0; j < 3; j++)
|
||
|
{
|
||
|
if (point[j] > bounds[2*j+1])
|
||
|
{
|
||
|
bounds[2*j+1] = point[j];
|
||
|
}
|
||
|
if (point[j] < bounds[2*j])
|
||
|
{
|
||
|
bounds[2*j] = point[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
matrix->Delete();
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int vtkImageReslice::RequestInformation(
|
||
|
vtkInformation *vtkNotUsed(request),
|
||
|
vtkInformationVector **inputVector,
|
||
|
vtkInformationVector *outputVector)
|
||
|
{
|
||
|
int i,j;
|
||
|
double inSpacing[3], inOrigin[3];
|
||
|
int inWholeExt[6];
|
||
|
double outSpacing[3], outOrigin[3];
|
||
|
int outWholeExt[6];
|
||
|
double maxBounds[6];
|
||
|
|
||
|
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
|
||
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
||
|
|
||
|
if (this->InformationInput)
|
||
|
{
|
||
|
this->InformationInput->UpdateInformation();
|
||
|
this->InformationInput->GetWholeExtent(inWholeExt);
|
||
|
this->InformationInput->GetSpacing(inSpacing);
|
||
|
this->InformationInput->GetOrigin(inOrigin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), inWholeExt);
|
||
|
inInfo->Get(vtkDataObject::SPACING(), inSpacing);
|
||
|
inInfo->Get(vtkDataObject::ORIGIN(), inOrigin);
|
||
|
}
|
||
|
|
||
|
// reslice axes matrix is identity by default
|
||
|
double matrix[4][4];
|
||
|
double imatrix[4][4];
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
matrix[i][0] = matrix[i][1] = matrix[i][2] = matrix[i][3] = 0;
|
||
|
matrix[i][i] = 1;
|
||
|
imatrix[i][0] = imatrix[i][1] = imatrix[i][2] = imatrix[i][3] = 0;
|
||
|
imatrix[i][i] = 1;
|
||
|
}
|
||
|
if (this->ResliceAxes)
|
||
|
{
|
||
|
vtkMatrix4x4::DeepCopy(*matrix, this->ResliceAxes);
|
||
|
vtkMatrix4x4::Invert(*matrix,*imatrix);
|
||
|
}
|
||
|
|
||
|
if (this->AutoCropOutput)
|
||
|
{
|
||
|
this->GetAutoCroppedOutputBounds(inInfo, maxBounds);
|
||
|
}
|
||
|
|
||
|
// pass the center of the volume through the inverse of the
|
||
|
// 3x3 direction cosines matrix
|
||
|
double inCenter[3];
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
inCenter[i] = inOrigin[i] + \
|
||
|
0.5*(inWholeExt[2*i] + inWholeExt[2*i+1])*inSpacing[i];
|
||
|
}
|
||
|
|
||
|
// the default spacing, extent and origin are the input spacing, extent
|
||
|
// and origin, transformed by the direction cosines of the ResliceAxes
|
||
|
// if requested (note that the transformed output spacing will always
|
||
|
// be positive)
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
double s = 0; // default output spacing
|
||
|
double d = 0; // default linear dimension
|
||
|
double e = 0; // default extent start
|
||
|
double c = 0; // transformed center-of-volume
|
||
|
|
||
|
if (this->TransformInputSampling)
|
||
|
{
|
||
|
double r = 0.0;
|
||
|
for (j = 0; j < 3; j++)
|
||
|
{
|
||
|
c += imatrix[i][j]*(inCenter[j] - matrix[j][3]);
|
||
|
double tmp = matrix[j][i]*matrix[j][i];
|
||
|
s += tmp*fabs(inSpacing[j]);
|
||
|
d += tmp*(inWholeExt[2*j+1] - inWholeExt[2*j])*fabs(inSpacing[j]);
|
||
|
e += tmp*inWholeExt[2*j];
|
||
|
r += tmp;
|
||
|
}
|
||
|
s /= r;
|
||
|
d /= r*sqrt(r);
|
||
|
e /= r;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s = inSpacing[i];
|
||
|
d = (inWholeExt[2*i+1] - inWholeExt[2*i])*s;
|
||
|
e = inWholeExt[2*i];
|
||
|
}
|
||
|
|
||
|
if (this->OutputSpacing[i] == VTK_DOUBLE_MAX)
|
||
|
{
|
||
|
outSpacing[i] = s;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
outSpacing[i] = this->OutputSpacing[i];
|
||
|
}
|
||
|
|
||
|
if (i >= this->OutputDimensionality)
|
||
|
{
|
||
|
outWholeExt[2*i] = 0;
|
||
|
outWholeExt[2*i+1] = 0;
|
||
|
}
|
||
|
else if (this->OutputExtent[2*i] == VTK_INT_MIN ||
|
||
|
this->OutputExtent[2*i+1] == VTK_INT_MAX)
|
||
|
{
|
||
|
if (this->AutoCropOutput)
|
||
|
{
|
||
|
d = maxBounds[2*i+1] - maxBounds[2*i];
|
||
|
}
|
||
|
outWholeExt[2*i] = vtkResliceRound(e);
|
||
|
outWholeExt[2*i+1] = vtkResliceRound(outWholeExt[2*i] +
|
||
|
fabs(d/outSpacing[i]));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
outWholeExt[2*i] = this->OutputExtent[2*i];
|
||
|
outWholeExt[2*i+1] = this->OutputExtent[2*i+1];
|
||
|
}
|
||
|
|
||
|
if (i >= this->OutputDimensionality)
|
||
|
{
|
||
|
outOrigin[i] = 0;
|
||
|
}
|
||
|
else if (this->OutputOrigin[i] == VTK_DOUBLE_MAX)
|
||
|
{
|
||
|
if (this->AutoCropOutput)
|
||
|
{ // set origin so edge of extent is edge of bounds
|
||
|
outOrigin[i] = maxBounds[2*i] - outWholeExt[2*i]*outSpacing[i];
|
||
|
}
|
||
|
else
|
||
|
{ // center new bounds over center of input bounds
|
||
|
outOrigin[i] = c - \
|
||
|
0.5*(outWholeExt[2*i] + outWholeExt[2*i+1])*outSpacing[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
outOrigin[i] = this->OutputOrigin[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),outWholeExt,6);
|
||
|
outInfo->Set(vtkDataObject::SPACING(), outSpacing, 3);
|
||
|
outInfo->Set(vtkDataObject::ORIGIN(), outOrigin, 3);
|
||
|
|
||
|
this->GetIndexMatrix(inInfo, outInfo);
|
||
|
|
||
|
if (this->GetNumberOfInputConnections(1) > 0)
|
||
|
{
|
||
|
vtkInformation *stencilInfo = inputVector[1]->GetInformationObject(0);
|
||
|
stencilInfo->Set(vtkDataObject::SPACING(),
|
||
|
inInfo->Get(vtkDataObject::SPACING()), 3);
|
||
|
stencilInfo->Set(vtkDataObject::ORIGIN(),
|
||
|
inInfo->Get(vtkDataObject::ORIGIN()), 3);
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Interpolation subroutines and associated code
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
// Three interpolation functions are supported: NearestNeighbor, Trilinear,
|
||
|
// and Tricubic. These routines have the following signature:
|
||
|
//
|
||
|
//int interpolate(T *&outPtr,
|
||
|
// const T *inPtr,
|
||
|
// const int inExt[6],
|
||
|
// const vtkIdType inInc[3],
|
||
|
// int numscalars,
|
||
|
// const F point[3],
|
||
|
// int mode,
|
||
|
// const T *background)
|
||
|
//
|
||
|
// where 'T' is any arithmetic type and 'F' is a float type
|
||
|
//
|
||
|
// The result of the interpolation is put in *outPtr, and outPtr is
|
||
|
// incremented.
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// constants for different boundary-handling modes
|
||
|
|
||
|
#define VTK_RESLICE_BACKGROUND 0 // use background if out-of-bounds
|
||
|
#define VTK_RESLICE_WRAP 1 // wrap to opposite side of image
|
||
|
#define VTK_RESLICE_MIRROR 2 // mirror off of the boundary
|
||
|
#define VTK_RESLICE_BORDER 3 // use a half-voxel border
|
||
|
#define VTK_RESLICE_NULL 4 // do nothing to *outPtr if out-of-bounds
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// rounding functions for each type, where 'F' is a floating-point type
|
||
|
|
||
|
#if (VTK_USE_INT8 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeInt8& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT8 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeUInt8& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_INT16 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeInt16& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT16 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeUInt16& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_INT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeInt32& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeUInt32& rnd)
|
||
|
{
|
||
|
rnd = vtkResliceRound(val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_FLOAT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeFloat32& rnd)
|
||
|
{
|
||
|
rnd = val;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_FLOAT64 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceRound(F val, vtkTypeFloat64& rnd)
|
||
|
{
|
||
|
rnd = val;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// clamping functions for each type
|
||
|
|
||
|
#if (VTK_USE_INT8 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeInt8& clamp)
|
||
|
{
|
||
|
if (val < -128.0)
|
||
|
{
|
||
|
val = -128.0;
|
||
|
}
|
||
|
if (val > 127.0)
|
||
|
{
|
||
|
val = 127.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT8 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeUInt8& clamp)
|
||
|
{
|
||
|
if (val < 0)
|
||
|
{
|
||
|
val = 0;
|
||
|
}
|
||
|
if (val > 255.0)
|
||
|
{
|
||
|
val = 255.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_INT16 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeInt16& clamp)
|
||
|
{
|
||
|
if (val < -32768.0)
|
||
|
{
|
||
|
val = -32768.0;
|
||
|
}
|
||
|
if (val > 32767.0)
|
||
|
{
|
||
|
val = 32767.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT16 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeUInt16& clamp)
|
||
|
{
|
||
|
if (val < 0)
|
||
|
{
|
||
|
val = 0;
|
||
|
}
|
||
|
if (val > 65535.0)
|
||
|
{
|
||
|
val = 65535.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_INT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeInt32& clamp)
|
||
|
{
|
||
|
if (val < -2147483648.0)
|
||
|
{
|
||
|
val = -2147483648.0;
|
||
|
}
|
||
|
if (val > 2147483647.0)
|
||
|
{
|
||
|
val = 2147483647.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_UINT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeUInt32& clamp)
|
||
|
{
|
||
|
if (val < 0)
|
||
|
{
|
||
|
val = 0;
|
||
|
}
|
||
|
if (val > 4294967295.0)
|
||
|
{
|
||
|
val = 4294967295.0;
|
||
|
}
|
||
|
vtkResliceRound(val,clamp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_FLOAT32 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeFloat32& clamp)
|
||
|
{
|
||
|
clamp = val;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (VTK_USE_FLOAT64 != 0)
|
||
|
template <class F>
|
||
|
inline void vtkResliceClamp(F val, vtkTypeFloat64& clamp)
|
||
|
{
|
||
|
clamp = val;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Perform a wrap to limit an index to [0,range).
|
||
|
// Ensures correct behaviour when the index is negative.
|
||
|
|
||
|
inline int vtkInterpolateWrap(int num, int range)
|
||
|
{
|
||
|
if ((num %= range) < 0)
|
||
|
{
|
||
|
num += range; // required for some % implementations
|
||
|
}
|
||
|
return num;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Perform a mirror to limit an index to [0,range).
|
||
|
|
||
|
inline int vtkInterpolateMirror(int num, int range)
|
||
|
{
|
||
|
if (num < 0)
|
||
|
{
|
||
|
num = -num - 1;
|
||
|
}
|
||
|
int count = num/range;
|
||
|
num %= range;
|
||
|
if (count & 0x1)
|
||
|
{
|
||
|
num = range - num - 1;
|
||
|
}
|
||
|
return num;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// If the value is within one half voxel of the range [0,inExtX), then
|
||
|
// set it to "0" or "inExtX-1" as appropriate.
|
||
|
|
||
|
inline int vtkInterpolateBorder(int &inIdX0, int &inIdX1, int inExtX,
|
||
|
double fx)
|
||
|
{
|
||
|
if (inIdX0 >= 0 && inIdX1 < inExtX)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
if (inIdX0 == -1 && fx >= 0.5)
|
||
|
{
|
||
|
inIdX1 = inIdX0 = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
if (inIdX0 == inExtX - 1 && fx < 0.5)
|
||
|
{
|
||
|
inIdX1 = inIdX0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
inline int vtkInterpolateBorderCheck(int inIdX0, int inIdX1, int inExtX,
|
||
|
double fx)
|
||
|
{
|
||
|
if ((inIdX0 >= 0 && inIdX1 < inExtX) ||
|
||
|
(inIdX0 == -1 && fx >= 0.5) ||
|
||
|
(inIdX0 == inExtX - 1 && fx < 0.5))
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Do nearest-neighbor interpolation of the input data 'inPtr' of extent
|
||
|
// 'inExt' at the 'point'. The result is placed at 'outPtr'.
|
||
|
// If the lookup data is beyond the extent 'inExt', set 'outPtr' to
|
||
|
// the background color 'background'.
|
||
|
// The number of scalar components in the data is 'numscalars'
|
||
|
template <class F, class T>
|
||
|
int vtkNearestNeighborInterpolation(T *&outPtr, const T *inPtr,
|
||
|
const int inExt[6],
|
||
|
const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode, const T *background)
|
||
|
{
|
||
|
int inIdX0 = vtkResliceRound(point[0]) - inExt[0];
|
||
|
int inIdY0 = vtkResliceRound(point[1]) - inExt[2];
|
||
|
int inIdZ0 = vtkResliceRound(point[2]) - inExt[4];
|
||
|
|
||
|
int inExtX = inExt[1] - inExt[0] + 1;
|
||
|
int inExtY = inExt[3] - inExt[2] + 1;
|
||
|
int inExtZ = inExt[5] - inExt[4] + 1;
|
||
|
|
||
|
if (inIdX0 < 0 || inIdX0 >= inExtX ||
|
||
|
inIdY0 < 0 || inIdY0 >= inExtY ||
|
||
|
inIdZ0 < 0 || inIdZ0 >= inExtZ)
|
||
|
{
|
||
|
if (mode == VTK_RESLICE_WRAP)
|
||
|
{
|
||
|
inIdX0 = vtkInterpolateWrap(inIdX0, inExtX);
|
||
|
inIdY0 = vtkInterpolateWrap(inIdY0, inExtY);
|
||
|
inIdZ0 = vtkInterpolateWrap(inIdZ0, inExtZ);
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_MIRROR)
|
||
|
{
|
||
|
inIdX0 = vtkInterpolateMirror(inIdX0, inExtX);
|
||
|
inIdY0 = vtkInterpolateMirror(inIdY0, inExtY);
|
||
|
inIdZ0 = vtkInterpolateMirror(inIdZ0, inExtZ);
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_BACKGROUND ||
|
||
|
mode == VTK_RESLICE_BORDER)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *background++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inPtr += inIdX0*inInc[0]+inIdY0*inInc[1]+inIdZ0*inInc[2];
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *inPtr++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Do trilinear interpolation of the input data 'inPtr' of extent 'inExt'
|
||
|
// at the 'point'. The result is placed at 'outPtr'.
|
||
|
// If the lookup data is beyond the extent 'inExt', set 'outPtr' to
|
||
|
// the background color 'background'.
|
||
|
// The number of scalar components in the data is 'numscalars'
|
||
|
template <class F, class T>
|
||
|
int vtkTrilinearInterpolation(T *&outPtr, const T *inPtr,
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode, const T *background)
|
||
|
{
|
||
|
F fx, fy, fz;
|
||
|
int floorX = vtkResliceFloor(point[0], fx);
|
||
|
int floorY = vtkResliceFloor(point[1], fy);
|
||
|
int floorZ = vtkResliceFloor(point[2], fz);
|
||
|
|
||
|
int inIdX0 = floorX - inExt[0];
|
||
|
int inIdY0 = floorY - inExt[2];
|
||
|
int inIdZ0 = floorZ - inExt[4];
|
||
|
|
||
|
int inIdX1 = inIdX0 + (fx != 0);
|
||
|
int inIdY1 = inIdY0 + (fy != 0);
|
||
|
int inIdZ1 = inIdZ0 + (fz != 0);
|
||
|
|
||
|
int inExtX = inExt[1] - inExt[0] + 1;
|
||
|
int inExtY = inExt[3] - inExt[2] + 1;
|
||
|
int inExtZ = inExt[5] - inExt[4] + 1;
|
||
|
|
||
|
if (inIdX0 < 0 || inIdX1 >= inExtX ||
|
||
|
inIdY0 < 0 || inIdY1 >= inExtY ||
|
||
|
inIdZ0 < 0 || inIdZ1 >= inExtZ)
|
||
|
{
|
||
|
if (mode == VTK_RESLICE_BORDER)
|
||
|
{
|
||
|
if (vtkInterpolateBorder(inIdX0, inIdX1, inExtX, fx) ||
|
||
|
vtkInterpolateBorder(inIdY0, inIdY1, inExtY, fy) ||
|
||
|
vtkInterpolateBorder(inIdZ0, inIdZ1, inExtZ, fz))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *background++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_WRAP)
|
||
|
{
|
||
|
inIdX0 = vtkInterpolateWrap(inIdX0, inExtX);
|
||
|
inIdY0 = vtkInterpolateWrap(inIdY0, inExtY);
|
||
|
inIdZ0 = vtkInterpolateWrap(inIdZ0, inExtZ);
|
||
|
|
||
|
inIdX1 = vtkInterpolateWrap(inIdX1, inExtX);
|
||
|
inIdY1 = vtkInterpolateWrap(inIdY1, inExtY);
|
||
|
inIdZ1 = vtkInterpolateWrap(inIdZ1, inExtZ);
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_MIRROR)
|
||
|
{
|
||
|
inIdX0 = vtkInterpolateMirror(inIdX0, inExtX);
|
||
|
inIdY0 = vtkInterpolateMirror(inIdY0, inExtY);
|
||
|
inIdZ0 = vtkInterpolateMirror(inIdZ0, inExtZ);
|
||
|
|
||
|
inIdX1 = vtkInterpolateMirror(inIdX1, inExtX);
|
||
|
inIdY1 = vtkInterpolateMirror(inIdY1, inExtY);
|
||
|
inIdZ1 = vtkInterpolateMirror(inIdZ1, inExtZ);
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_BACKGROUND)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *background++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
vtkIdType factX0 = inIdX0*inInc[0];
|
||
|
vtkIdType factX1 = inIdX1*inInc[0];
|
||
|
vtkIdType factY0 = inIdY0*inInc[1];
|
||
|
vtkIdType factY1 = inIdY1*inInc[1];
|
||
|
vtkIdType factZ0 = inIdZ0*inInc[2];
|
||
|
vtkIdType factZ1 = inIdZ1*inInc[2];
|
||
|
|
||
|
vtkIdType i00 = factY0 + factZ0;
|
||
|
vtkIdType i01 = factY0 + factZ1;
|
||
|
vtkIdType i10 = factY1 + factZ0;
|
||
|
vtkIdType i11 = factY1 + factZ1;
|
||
|
|
||
|
F rx = 1 - fx;
|
||
|
F ry = 1 - fy;
|
||
|
F rz = 1 - fz;
|
||
|
|
||
|
F ryrz = ry*rz;
|
||
|
F fyrz = fy*rz;
|
||
|
F ryfz = ry*fz;
|
||
|
F fyfz = fy*fz;
|
||
|
|
||
|
const T *inPtr0 = inPtr + factX0;
|
||
|
const T *inPtr1 = inPtr + factX1;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
F result = (rx*(ryrz*inPtr0[i00] + ryfz*inPtr0[i01] +
|
||
|
fyrz*inPtr0[i10] + fyfz*inPtr0[i11]) +
|
||
|
fx*(ryrz*inPtr1[i00] + ryfz*inPtr1[i01] +
|
||
|
fyrz*inPtr1[i10] + fyfz*inPtr1[i11]));
|
||
|
|
||
|
vtkResliceRound(result, *outPtr++);
|
||
|
inPtr0++;
|
||
|
inPtr1++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Do tricubic interpolation of the input data 'inPtr' of extent 'inExt'
|
||
|
// at the 'point'. The result is placed at 'outPtr'.
|
||
|
// The number of scalar components in the data is 'numscalars'
|
||
|
// The tricubic interpolation ensures that both the intensity and
|
||
|
// the first derivative of the intensity are smooth across the
|
||
|
// image. The first derivative is estimated using a
|
||
|
// centered-difference calculation.
|
||
|
|
||
|
|
||
|
// helper function: set up the lookup indices and the interpolation
|
||
|
// coefficients
|
||
|
|
||
|
template <class T>
|
||
|
void vtkTricubicInterpCoeffs(T F[4], int l, int h, T f)
|
||
|
{
|
||
|
static const T half = T(0.5);
|
||
|
|
||
|
int order = h - l;
|
||
|
|
||
|
if (order == 0)
|
||
|
{ // no interpolation
|
||
|
F[0] = 0;
|
||
|
F[1] = 1;
|
||
|
F[2] = 0;
|
||
|
F[3] = 0;
|
||
|
return;
|
||
|
}
|
||
|
if (order == 3)
|
||
|
{ // cubic interpolation
|
||
|
T fm1 = f - 1;
|
||
|
T fd2 = f*half;
|
||
|
T ft3 = f*3;
|
||
|
F[0] = -fd2*fm1*fm1;
|
||
|
F[1] = ((ft3 - 2)*fd2 - 1)*fm1;
|
||
|
F[2] = -((ft3 - 4)*f - 1)*fd2;
|
||
|
F[3] = f*fd2*fm1;
|
||
|
return;
|
||
|
}
|
||
|
if (order == 1)
|
||
|
{ // linear interpolation
|
||
|
F[0] = 0;
|
||
|
F[1] = 1 - f;
|
||
|
F[2] = f;
|
||
|
F[3] = 0;
|
||
|
return;
|
||
|
}
|
||
|
if (l == 0)
|
||
|
{ // quadratic interpolation
|
||
|
T fp1 = f + 1;
|
||
|
T fm1 = f - 1;
|
||
|
T fd2 = f*half;
|
||
|
F[0] = fd2*fm1;
|
||
|
F[1] = -fp1*fm1;
|
||
|
F[2] = fp1*fd2;
|
||
|
F[3] = 0;
|
||
|
return;
|
||
|
}
|
||
|
// else
|
||
|
{ // quadratic interpolation
|
||
|
T fm1 = f - 1;
|
||
|
T fm2 = fm1 - 1;
|
||
|
T fm1d2 = fm1*half;
|
||
|
F[0] = 0;
|
||
|
F[1] = fm1d2*fm2;
|
||
|
F[2] = -f*fm2;
|
||
|
F[3] = f*fm1d2;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// tricubic interpolation
|
||
|
template <class F, class T>
|
||
|
int vtkTricubicInterpolation(T *&outPtr, const T *inPtr,
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode, const T *background)
|
||
|
{
|
||
|
F fx, fy, fz;
|
||
|
int floorX = vtkResliceFloor(point[0], fx);
|
||
|
int floorY = vtkResliceFloor(point[1], fy);
|
||
|
int floorZ = vtkResliceFloor(point[2], fz);
|
||
|
|
||
|
int fxIsNotZero = (fx != 0);
|
||
|
int fyIsNotZero = (fy != 0);
|
||
|
int fzIsNotZero = (fz != 0);
|
||
|
|
||
|
int inIdX0 = floorX - inExt[0];
|
||
|
int inIdY0 = floorY - inExt[2];
|
||
|
int inIdZ0 = floorZ - inExt[4];
|
||
|
|
||
|
int inIdX1 = inIdX0 + fxIsNotZero;
|
||
|
int inIdY1 = inIdY0 + fyIsNotZero;
|
||
|
int inIdZ1 = inIdZ0 + fzIsNotZero;
|
||
|
|
||
|
int inExtX = inExt[1] - inExt[0] + 1;
|
||
|
int inExtY = inExt[3] - inExt[2] + 1;
|
||
|
int inExtZ = inExt[5] - inExt[4] + 1;
|
||
|
|
||
|
vtkIdType inIncX = inInc[0];
|
||
|
vtkIdType inIncY = inInc[1];
|
||
|
vtkIdType inIncZ = inInc[2];
|
||
|
|
||
|
vtkIdType factX[4], factY[4], factZ[4];
|
||
|
|
||
|
if (inIdX0 < 0 || inIdX1 >= inExtX ||
|
||
|
inIdY0 < 0 || inIdY1 >= inExtY ||
|
||
|
inIdZ0 < 0 || inIdZ1 >= inExtZ)
|
||
|
{
|
||
|
if (mode == VTK_RESLICE_BORDER)
|
||
|
{
|
||
|
if (vtkInterpolateBorderCheck(inIdX0, inIdX1, inExtX, fx) ||
|
||
|
vtkInterpolateBorderCheck(inIdY0, inIdY1, inExtY, fy) ||
|
||
|
vtkInterpolateBorderCheck(inIdZ0, inIdZ1, inExtZ, fz))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *background++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else if (mode != VTK_RESLICE_WRAP && mode != VTK_RESLICE_MIRROR)
|
||
|
{
|
||
|
if (mode == VTK_RESLICE_BACKGROUND)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *background++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
F fX[4], fY[4], fZ[4];
|
||
|
int k1, k2, j1, j2, i1, i2;
|
||
|
|
||
|
if (mode == VTK_RESLICE_WRAP || mode == VTK_RESLICE_MIRROR)
|
||
|
{
|
||
|
i1 = 0;
|
||
|
i2 = 3;
|
||
|
vtkTricubicInterpCoeffs(fX, i1, i2, fx);
|
||
|
|
||
|
j1 = 1 - fyIsNotZero;
|
||
|
j2 = 1 + (fyIsNotZero<<1);
|
||
|
vtkTricubicInterpCoeffs(fY, j1, j2, fy);
|
||
|
|
||
|
k1 = 1 - fzIsNotZero;
|
||
|
k2 = 1 + (fzIsNotZero<<1);
|
||
|
vtkTricubicInterpCoeffs(fZ, k1, k2, fz);
|
||
|
|
||
|
if (mode == VTK_RESLICE_WRAP)
|
||
|
{
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
factX[i] = vtkInterpolateWrap(inIdX0 + i - 1, inExtX)*inIncX;
|
||
|
factY[i] = vtkInterpolateWrap(inIdY0 + i - 1, inExtY)*inIncY;
|
||
|
factZ[i] = vtkInterpolateWrap(inIdZ0 + i - 1, inExtZ)*inIncZ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
factX[i] = vtkInterpolateMirror(inIdX0 + i - 1, inExtX)*inIncX;
|
||
|
factY[i] = vtkInterpolateMirror(inIdY0 + i - 1, inExtY)*inIncY;
|
||
|
factZ[i] = vtkInterpolateMirror(inIdZ0 + i - 1, inExtZ)*inIncZ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (mode == VTK_RESLICE_BORDER)
|
||
|
{
|
||
|
// clamp to the border of the input extent
|
||
|
|
||
|
i1 = 1 - fxIsNotZero;
|
||
|
j1 = 1 - fyIsNotZero;
|
||
|
k1 = 1 - fzIsNotZero;
|
||
|
|
||
|
i2 = 1 + 2*fxIsNotZero;
|
||
|
j2 = 1 + 2*fyIsNotZero;
|
||
|
k2 = 1 + 2*fzIsNotZero;
|
||
|
|
||
|
vtkTricubicInterpCoeffs(fX, i1, i2, fx);
|
||
|
vtkTricubicInterpCoeffs(fY, j1, j2, fy);
|
||
|
vtkTricubicInterpCoeffs(fZ, k1, k2, fz);
|
||
|
|
||
|
int tmpExt = inExtX - 1;
|
||
|
int tmpId = tmpExt - inIdX0 - 1;
|
||
|
factX[0] = (inIdX0 - 1)*(inIdX0 - 1 >= 0)*inIncX;
|
||
|
factX[1] = (inIdX0)*(inIdX0 >= 0)*inIncX;
|
||
|
factX[2] = (tmpExt - (tmpId)*(tmpId >= 0))*inIncX;
|
||
|
factX[3] = (tmpExt - (tmpId - 1)*(tmpId - 1 >= 0))*inIncX;
|
||
|
|
||
|
tmpExt = inExtY - 1;
|
||
|
tmpId = tmpExt - inIdY0 - 1;
|
||
|
factY[0] = (inIdY0 - 1)*(inIdY0 - 1 >= 0)*inIncY;
|
||
|
factY[1] = (inIdY0)*(inIdY0 >= 0)*inIncY;
|
||
|
factY[2] = (tmpExt - (tmpId)*(tmpId >= 0))*inIncY;
|
||
|
factY[3] = (tmpExt - (tmpId - 1)*(tmpId - 1 >= 0))*inIncY;
|
||
|
|
||
|
tmpExt = inExtZ - 1;
|
||
|
tmpId = tmpExt - inIdZ0 - 1;
|
||
|
factZ[0] = (inIdZ0 - 1)*(inIdZ0 - 1 >= 0)*inIncZ;
|
||
|
factZ[1] = (inIdZ0)*(inIdZ0 >= 0)*inIncZ;
|
||
|
factZ[2] = (tmpExt - (tmpId)*(tmpId >= 0))*inIncZ;
|
||
|
factZ[3] = (tmpExt - (tmpId - 1)*(tmpId - 1 >= 0))*inIncZ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// depending on whether we are at the edge of the
|
||
|
// input extent, choose the appropriate interpolation
|
||
|
// method to use
|
||
|
|
||
|
i1 = 1 - (inIdX0 > 0)*fxIsNotZero;
|
||
|
j1 = 1 - (inIdY0 > 0)*fyIsNotZero;
|
||
|
k1 = 1 - (inIdZ0 > 0)*fzIsNotZero;
|
||
|
|
||
|
i2 = 1 + (1 + (inIdX0 + 2 < inExtX))*fxIsNotZero;
|
||
|
j2 = 1 + (1 + (inIdY0 + 2 < inExtY))*fyIsNotZero;
|
||
|
k2 = 1 + (1 + (inIdZ0 + 2 < inExtZ))*fzIsNotZero;
|
||
|
|
||
|
vtkTricubicInterpCoeffs(fX, i1, i2, fx);
|
||
|
vtkTricubicInterpCoeffs(fY, j1, j2, fy);
|
||
|
vtkTricubicInterpCoeffs(fZ, k1, k2, fz);
|
||
|
|
||
|
factX[1] = inIdX0*inIncX;
|
||
|
factX[0] = factX[1] - inIncX;
|
||
|
factX[2] = factX[1] + inIncX;
|
||
|
factX[3] = factX[2] + inIncX;
|
||
|
|
||
|
factY[1] = inIdY0*inIncY;
|
||
|
factY[0] = factY[1] - inIncY;
|
||
|
factY[2] = factY[1] + inIncY;
|
||
|
factY[3] = factY[2] + inIncY;
|
||
|
|
||
|
factZ[1] = inIdZ0*inIncZ;
|
||
|
factZ[0] = factZ[1] - inIncZ;
|
||
|
factZ[2] = factZ[1] + inIncZ;
|
||
|
factZ[3] = factZ[2] + inIncZ;
|
||
|
|
||
|
// this little bit of wierdness allows us to unroll the x loop
|
||
|
if (i1 > 0)
|
||
|
{
|
||
|
factX[0] = factX[1];
|
||
|
}
|
||
|
if (i2 < 3)
|
||
|
{
|
||
|
factX[3] = factX[1];
|
||
|
if (i2 < 2)
|
||
|
{
|
||
|
factX[2] = factX[1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
do // loop over components
|
||
|
{
|
||
|
F val = 0;
|
||
|
int k = k1;
|
||
|
do // loop over z
|
||
|
{
|
||
|
F ifz = fZ[k];
|
||
|
vtkIdType factz = factZ[k];
|
||
|
int j = j1;
|
||
|
do // loop over y
|
||
|
{
|
||
|
F ify = fY[j];
|
||
|
F fzy = ifz*ify;
|
||
|
vtkIdType factzy = factz + factY[j];
|
||
|
const T *tmpPtr = inPtr + factzy;
|
||
|
// loop over x is unrolled (significant performance boost)
|
||
|
val += fzy*(fX[0]*tmpPtr[factX[0]] +
|
||
|
fX[1]*tmpPtr[factX[1]] +
|
||
|
fX[2]*tmpPtr[factX[2]] +
|
||
|
fX[3]*tmpPtr[factX[3]]);
|
||
|
}
|
||
|
while (++j <= j2);
|
||
|
}
|
||
|
while (++k <= k2);
|
||
|
|
||
|
vtkResliceClamp(val, *outPtr++);
|
||
|
inPtr++;
|
||
|
}
|
||
|
while (--numscalars);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// get appropriate interpolation function according to interpolation mode
|
||
|
// and scalar type
|
||
|
template<class F>
|
||
|
void vtkGetResliceInterpFunc(vtkImageReslice *self,
|
||
|
int (**interpolate)(void *&outPtr,
|
||
|
const void *inPtr,
|
||
|
const int inExt[6],
|
||
|
const vtkIdType inInc[3],
|
||
|
int numscalars,
|
||
|
const F point[3],
|
||
|
int mode,
|
||
|
const void *background))
|
||
|
{
|
||
|
int dataType = self->GetOutput()->GetScalarType();
|
||
|
int interpolationMode = self->GetInterpolationMode();
|
||
|
|
||
|
switch (interpolationMode)
|
||
|
{
|
||
|
case VTK_RESLICE_NEAREST:
|
||
|
switch (dataType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((int (**)(VTK_TT *&outPtr, const VTK_TT *inPtr,
|
||
|
const int inExt[6],
|
||
|
const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode,
|
||
|
const VTK_TT *background))interpolate) = \
|
||
|
&vtkNearestNeighborInterpolation);
|
||
|
default:
|
||
|
interpolate = 0;
|
||
|
}
|
||
|
break;
|
||
|
case VTK_RESLICE_LINEAR:
|
||
|
switch (dataType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((int (**)(VTK_TT *&outPtr, const VTK_TT *inPtr,
|
||
|
const int inExt[6],
|
||
|
const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode,
|
||
|
const VTK_TT *background))interpolate) = \
|
||
|
&vtkTrilinearInterpolation);
|
||
|
default:
|
||
|
interpolate = 0;
|
||
|
}
|
||
|
break;
|
||
|
case VTK_RESLICE_CUBIC:
|
||
|
switch (dataType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((int (**)(VTK_TT *&outPtr, const VTK_TT *inPtr,
|
||
|
const int inExt[6],
|
||
|
const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode,
|
||
|
const VTK_TT *background))interpolate) = \
|
||
|
&vtkTricubicInterpolation);
|
||
|
default:
|
||
|
interpolate = 0;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
interpolate = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Some helper functions for 'RequestData'
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// pixel copy function, templated for different scalar types
|
||
|
template<class T>
|
||
|
void vtkSetPixels(T *&outPtr, const T *inPtr, int numscalars, int n)
|
||
|
{
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
const T *tmpPtr = inPtr;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *tmpPtr++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// optimized for 1 scalar components
|
||
|
template<class T>
|
||
|
void vtkSetPixels1(T *&outPtr, const T *inPtr,
|
||
|
int vtkNotUsed(numscalars), int n)
|
||
|
{
|
||
|
T val = *inPtr;
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
*outPtr++ = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get a pixel copy function that is appropriate for the data type
|
||
|
void vtkGetSetPixelsFunc(vtkImageReslice *self,
|
||
|
void (**setpixels)(void *&out, const void *in,
|
||
|
int numscalars, int n))
|
||
|
{
|
||
|
int dataType = self->GetOutput()->GetScalarType();
|
||
|
int numscalars = self->GetOutput()->GetNumberOfScalarComponents();
|
||
|
|
||
|
switch (numscalars)
|
||
|
{
|
||
|
case 1:
|
||
|
switch (dataType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((void (**)(VTK_TT *&out, const VTK_TT *in,
|
||
|
int numscalars, int n))setpixels) = \
|
||
|
vtkSetPixels1);
|
||
|
default:
|
||
|
setpixels = 0;
|
||
|
}
|
||
|
default:
|
||
|
switch (dataType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((void (**)(VTK_TT *&out, const VTK_TT *in,
|
||
|
int numscalars, int n))setpixels) = \
|
||
|
vtkSetPixels);
|
||
|
default:
|
||
|
setpixels = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Convert background color from float to appropriate type
|
||
|
template <class T>
|
||
|
void vtkAllocBackgroundPixelT(vtkImageReslice *self,
|
||
|
T **background_ptr, int numComponents)
|
||
|
{
|
||
|
*background_ptr = new T[numComponents];
|
||
|
T *background = *background_ptr;
|
||
|
|
||
|
for (int i = 0; i < numComponents; i++)
|
||
|
{
|
||
|
if (i < 4)
|
||
|
{
|
||
|
vtkResliceClamp(self->GetBackgroundColor()[i], background[i]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
background[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void vtkAllocBackgroundPixel(vtkImageReslice *self, void **rval,
|
||
|
int numComponents)
|
||
|
{
|
||
|
switch (self->GetOutput()->GetScalarType())
|
||
|
{
|
||
|
vtkTemplateAliasMacro(vtkAllocBackgroundPixelT(self, (VTK_TT **)rval,
|
||
|
numComponents));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void vtkFreeBackgroundPixel(vtkImageReslice *self, void **rval)
|
||
|
{
|
||
|
switch (self->GetOutput()->GetScalarType())
|
||
|
{
|
||
|
vtkTemplateAliasMacro(delete [] *((VTK_TT **)rval));
|
||
|
}
|
||
|
|
||
|
*rval = 0;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// helper function for clipping of the output with a stencil
|
||
|
int vtkResliceGetNextExtent(vtkImageStencilData *stencil,
|
||
|
int &r1, int &r2, int rmin, int rmax,
|
||
|
int yIdx, int zIdx,
|
||
|
void *&outPtr, void *background,
|
||
|
int numscalars,
|
||
|
void (*setpixels)(void *&out,
|
||
|
const void *in,
|
||
|
int numscalars,
|
||
|
int n),
|
||
|
int &iter)
|
||
|
{
|
||
|
// trivial case if stencil is not set
|
||
|
if (!stencil)
|
||
|
{
|
||
|
if (iter++ == 0)
|
||
|
{
|
||
|
r1 = rmin;
|
||
|
r2 = rmax;
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// for clearing, start at last r2 plus 1
|
||
|
int clear1 = r2 + 1;
|
||
|
if (iter == 0)
|
||
|
{ // if no 'last time', start at rmin
|
||
|
clear1 = rmin;
|
||
|
}
|
||
|
|
||
|
int rval = stencil->GetNextExtent(r1, r2, rmin, rmax, yIdx, zIdx, iter);
|
||
|
int clear2 = r1 - 1;
|
||
|
if (rval == 0)
|
||
|
{
|
||
|
clear2 = rmax;
|
||
|
}
|
||
|
|
||
|
setpixels(outPtr, background, numscalars, clear2 - clear1 + 1);
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// This function simply clears the entire output to the background color,
|
||
|
// for cases where the transformation places the output extent completely
|
||
|
// outside of the input extent.
|
||
|
void vtkImageResliceClearExecute(vtkImageReslice *self,
|
||
|
vtkImageData *, void *,
|
||
|
vtkImageData *outData, void *outPtr,
|
||
|
int outExt[6], int id)
|
||
|
{
|
||
|
int numscalars;
|
||
|
int idY, idZ;
|
||
|
vtkIdType outIncX, outIncY, outIncZ;
|
||
|
int scalarSize;
|
||
|
unsigned long count = 0;
|
||
|
unsigned long target;
|
||
|
void *background;
|
||
|
void (*setpixels)(void *&out, const void *in, int numscalars, int n);
|
||
|
|
||
|
// for the progress meter
|
||
|
target = (unsigned long)
|
||
|
((outExt[5]-outExt[4]+1)*(outExt[3]-outExt[2]+1)/50.0);
|
||
|
target++;
|
||
|
|
||
|
// Get Increments to march through data
|
||
|
outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
|
||
|
scalarSize = outData->GetScalarSize();
|
||
|
numscalars = outData->GetNumberOfScalarComponents();
|
||
|
|
||
|
// allocate a voxel to copy into the background (out-of-bounds) regions
|
||
|
vtkAllocBackgroundPixel(self, &background, numscalars);
|
||
|
// get the appropriate function for pixel copying
|
||
|
vtkGetSetPixelsFunc(self, &setpixels);
|
||
|
|
||
|
// Loop through output voxels
|
||
|
for (idZ = outExt[4]; idZ <= outExt[5]; idZ++)
|
||
|
{
|
||
|
for (idY = outExt[2]; idY <= outExt[3]; idY++)
|
||
|
{
|
||
|
if (id == 0)
|
||
|
{ // update the progress if this is the main thread
|
||
|
if (!(count%target))
|
||
|
{
|
||
|
self->UpdateProgress(count/(50.0*target));
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
// clear the pixels to background color and go to next row
|
||
|
setpixels(outPtr, background, numscalars, outExt[1]-outExt[0]+1);
|
||
|
outPtr = (void *)((char *)outPtr + outIncY*scalarSize);
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outIncZ*scalarSize);
|
||
|
}
|
||
|
|
||
|
vtkFreeBackgroundPixel(self, &background);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// This function executes the filter for any type of data. It is much simpler
|
||
|
// in structure than vtkImageResliceOptimizedExecute.
|
||
|
void vtkImageResliceExecute(vtkImageReslice *self,
|
||
|
vtkImageData *inData, void *inPtr,
|
||
|
vtkImageData *outData, void *outPtr,
|
||
|
int outExt[6], int id)
|
||
|
{
|
||
|
int numscalars;
|
||
|
int idX, idY, idZ;
|
||
|
int idXmin, idXmax, iter;
|
||
|
vtkIdType outIncX, outIncY, outIncZ;
|
||
|
int scalarSize;
|
||
|
int inExt[6];
|
||
|
vtkIdType inInc[3];
|
||
|
unsigned long count = 0;
|
||
|
unsigned long target;
|
||
|
double point[4];
|
||
|
double f;
|
||
|
double *inSpacing, *inOrigin, *outSpacing, *outOrigin, inInvSpacing[3];
|
||
|
void *background;
|
||
|
int (*interpolate)(void *&outPtr, const void *inPtr,
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int numscalars, const double point[3],
|
||
|
int mode, const void *background);
|
||
|
void (*setpixels)(void *&out, const void *in, int numscalars, int n);
|
||
|
|
||
|
// the 'mode' species what to do with the 'pad' (out-of-bounds) area
|
||
|
int mode = VTK_RESLICE_BACKGROUND;
|
||
|
if (self->GetMirror())
|
||
|
{
|
||
|
mode = VTK_RESLICE_MIRROR;
|
||
|
}
|
||
|
else if (self->GetWrap())
|
||
|
{
|
||
|
mode = VTK_RESLICE_WRAP;
|
||
|
}
|
||
|
else if (self->GetBorder())
|
||
|
{
|
||
|
mode = VTK_RESLICE_BORDER;
|
||
|
}
|
||
|
|
||
|
// the transformation to apply to the data
|
||
|
vtkAbstractTransform *transform = self->GetResliceTransform();
|
||
|
vtkMatrix4x4 *matrix = self->GetResliceAxes();
|
||
|
|
||
|
// for conversion to data coordinates
|
||
|
inOrigin = inData->GetOrigin();
|
||
|
inSpacing = inData->GetSpacing();
|
||
|
outOrigin = outData->GetOrigin();
|
||
|
outSpacing = outData->GetSpacing();
|
||
|
|
||
|
// save effor later: invert inSpacing
|
||
|
inInvSpacing[0] = 1.0/inSpacing[0];
|
||
|
inInvSpacing[1] = 1.0/inSpacing[1];
|
||
|
inInvSpacing[2] = 1.0/inSpacing[2];
|
||
|
|
||
|
// find maximum input range
|
||
|
inData->GetExtent(inExt);
|
||
|
|
||
|
// for the progress meter
|
||
|
target = (unsigned long)
|
||
|
((outExt[5]-outExt[4]+1)*(outExt[3]-outExt[2]+1)/50.0);
|
||
|
target++;
|
||
|
|
||
|
// Get Increments to march through data
|
||
|
inData->GetIncrements(inInc);
|
||
|
outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
|
||
|
scalarSize = outData->GetScalarSize();
|
||
|
numscalars = inData->GetNumberOfScalarComponents();
|
||
|
|
||
|
// allocate a voxel to copy into the background (out-of-bounds) regions
|
||
|
vtkAllocBackgroundPixel(self, &background, numscalars);
|
||
|
|
||
|
// get the appropriate functions for interpolation and pixel copying
|
||
|
vtkGetResliceInterpFunc(self, &interpolate);
|
||
|
vtkGetSetPixelsFunc(self, &setpixels);
|
||
|
|
||
|
// get the stencil
|
||
|
vtkImageStencilData *stencil = self->GetStencil();
|
||
|
|
||
|
// Loop through output voxels
|
||
|
for (idZ = outExt[4]; idZ <= outExt[5]; idZ++)
|
||
|
{
|
||
|
for (idY = outExt[2]; idY <= outExt[3]; idY++)
|
||
|
{
|
||
|
if (id == 0)
|
||
|
{ // update the progress if this is the main thread
|
||
|
if (!(count%target))
|
||
|
{
|
||
|
self->UpdateProgress(count/(50.0*target));
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
iter = 0; // if there is a stencil, it is applied here
|
||
|
while (vtkResliceGetNextExtent(stencil, idXmin, idXmax,
|
||
|
outExt[0], outExt[1], idY, idZ,
|
||
|
outPtr, background, numscalars,
|
||
|
setpixels, iter))
|
||
|
{
|
||
|
for (idX = idXmin; idX <= idXmax; idX++)
|
||
|
{
|
||
|
// convert to data coordinates
|
||
|
point[0] = idX*outSpacing[0] + outOrigin[0];
|
||
|
point[1] = idY*outSpacing[1] + outOrigin[1];
|
||
|
point[2] = idZ*outSpacing[2] + outOrigin[2];
|
||
|
|
||
|
// apply ResliceAxes matrix
|
||
|
if (matrix)
|
||
|
{
|
||
|
point[3] = 1.0;
|
||
|
matrix->MultiplyPoint(point, point);
|
||
|
f = 1.0/point[3];
|
||
|
point[0] *= f;
|
||
|
point[1] *= f;
|
||
|
point[2] *= f;
|
||
|
}
|
||
|
|
||
|
// apply ResliceTransform
|
||
|
if (transform)
|
||
|
{
|
||
|
transform->InternalTransformPoint(point, point);
|
||
|
}
|
||
|
|
||
|
// convert back to voxel indices
|
||
|
point[0] = (point[0] - inOrigin[0])*inInvSpacing[0];
|
||
|
point[1] = (point[1] - inOrigin[1])*inInvSpacing[1];
|
||
|
point[2] = (point[2] - inOrigin[2])*inInvSpacing[2];
|
||
|
|
||
|
// interpolate output voxel from input data set
|
||
|
interpolate(outPtr, inPtr, inExt, inInc, numscalars,
|
||
|
point, mode, background);
|
||
|
}
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outIncY*scalarSize);
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outIncZ*scalarSize);
|
||
|
}
|
||
|
|
||
|
vtkFreeBackgroundPixel(self, &background);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//----------------------------------------------------------------------------
|
||
|
// The remainder of this file is the 'optimized' version of the code.
|
||
|
//----------------------------------------------------------------------------
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
// application of the transform has different forms for fixed-point
|
||
|
// vs. floating-point
|
||
|
template<class F>
|
||
|
inline
|
||
|
void vtkResliceApplyTransform(vtkAbstractTransform *newtrans,
|
||
|
F inPoint[3], F inOrigin[3],
|
||
|
F inInvSpacing[3])
|
||
|
{
|
||
|
newtrans->InternalTransformPoint(inPoint, inPoint);
|
||
|
inPoint[0] -= inOrigin[0];
|
||
|
inPoint[1] -= inOrigin[1];
|
||
|
inPoint[2] -= inOrigin[2];
|
||
|
inPoint[0] *= inInvSpacing[0];
|
||
|
inPoint[1] *= inInvSpacing[1];
|
||
|
inPoint[2] *= inInvSpacing[2];
|
||
|
}
|
||
|
|
||
|
// The vtkOptimizedExecute() is like vtkImageResliceExecute, except that
|
||
|
// it provides a few optimizations:
|
||
|
// 1) the ResliceAxes and ResliceTransform are joined to create a
|
||
|
// single 4x4 matrix if possible
|
||
|
// 2) the transformation is calculated incrementally to increase efficiency
|
||
|
// 3) nearest-neighbor interpolation is treated specially in order to
|
||
|
// increase efficiency
|
||
|
|
||
|
template <class F>
|
||
|
void vtkOptimizedExecute(vtkImageReslice *self,
|
||
|
vtkImageData *inData, void *inPtr,
|
||
|
vtkImageData *outData, void *outPtr,
|
||
|
int outExt[6], int id, F newmat[4][4],
|
||
|
vtkAbstractTransform *newtrans)
|
||
|
{
|
||
|
int i, numscalars;
|
||
|
int idX, idY, idZ;
|
||
|
vtkIdType outIncX, outIncY, outIncZ;
|
||
|
int scalarSize;
|
||
|
int inExt[6];
|
||
|
vtkIdType inInc[3];
|
||
|
unsigned long count = 0;
|
||
|
unsigned long target;
|
||
|
int iter, idXmin, idXmax;
|
||
|
double temp[3];
|
||
|
F inOrigin[3], inInvSpacing[3];
|
||
|
F xAxis[4], yAxis[4], zAxis[4], origin[4];
|
||
|
F inPoint0[4];
|
||
|
F inPoint1[4];
|
||
|
F inPoint[4], f;
|
||
|
void *background;
|
||
|
int (*interpolate)(void *&outPtr, const void *inPtr,
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int numscalars, const F point[3],
|
||
|
int mode, const void *background);
|
||
|
void (*setpixels)(void *&out, const void *in, int numscalars, int n);
|
||
|
|
||
|
int mode = VTK_RESLICE_BACKGROUND;
|
||
|
int wrap = 0;
|
||
|
|
||
|
if (self->GetMirror())
|
||
|
{
|
||
|
mode = VTK_RESLICE_MIRROR;
|
||
|
wrap = 1;
|
||
|
}
|
||
|
else if (self->GetWrap())
|
||
|
{
|
||
|
mode = VTK_RESLICE_WRAP;
|
||
|
wrap = 1;
|
||
|
}
|
||
|
else if (self->GetBorder())
|
||
|
{
|
||
|
mode = VTK_RESLICE_BORDER;
|
||
|
}
|
||
|
|
||
|
int perspective = 0;
|
||
|
if (newmat[3][0] != 0 || newmat[3][1] != 0 ||
|
||
|
newmat[3][2] != 0 || newmat[3][3] != 1)
|
||
|
{
|
||
|
perspective = 1;
|
||
|
}
|
||
|
|
||
|
int optimizeNearest = 0;
|
||
|
if (self->GetInterpolationMode() == VTK_RESLICE_NEAREST &&
|
||
|
!(wrap || newtrans || perspective))
|
||
|
{
|
||
|
optimizeNearest = 1;
|
||
|
}
|
||
|
|
||
|
// find maximum input range
|
||
|
inData->GetExtent(inExt);
|
||
|
|
||
|
target = (unsigned long)
|
||
|
((outExt[5]-outExt[4]+1)*(outExt[3]-outExt[2]+1)/50.0);
|
||
|
target++;
|
||
|
|
||
|
// Get Increments to march through data
|
||
|
inData->GetIncrements(inInc);
|
||
|
outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
|
||
|
scalarSize = outData->GetScalarSize();
|
||
|
numscalars = inData->GetNumberOfScalarComponents();
|
||
|
|
||
|
// break matrix into a set of axes plus an origin
|
||
|
// (this allows us to calculate the transform Incrementally)
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
xAxis[i] = newmat[i][0];
|
||
|
yAxis[i] = newmat[i][1];
|
||
|
zAxis[i] = newmat[i][2];
|
||
|
origin[i] = newmat[i][3];
|
||
|
}
|
||
|
|
||
|
// get the input origin and spacing for conversion purposes
|
||
|
inData->GetOrigin(temp);
|
||
|
inOrigin[0] = F(temp[0]);
|
||
|
inOrigin[1] = F(temp[1]);
|
||
|
inOrigin[2] = F(temp[2]);
|
||
|
|
||
|
inData->GetSpacing(temp);
|
||
|
inInvSpacing[0] = F(1.0/temp[0]);
|
||
|
inInvSpacing[1] = F(1.0/temp[1]);
|
||
|
inInvSpacing[2] = F(1.0/temp[2]);
|
||
|
|
||
|
// set color for area outside of input volume extent
|
||
|
vtkAllocBackgroundPixel(self, &background, numscalars);
|
||
|
|
||
|
// Set interpolation method
|
||
|
vtkGetResliceInterpFunc(self, &interpolate);
|
||
|
vtkGetSetPixelsFunc(self, &setpixels);
|
||
|
|
||
|
// get the stencil
|
||
|
vtkImageStencilData *stencil = self->GetStencil();
|
||
|
|
||
|
// Loop through output pixels
|
||
|
for (idZ = outExt[4]; idZ <= outExt[5]; idZ++)
|
||
|
{
|
||
|
inPoint0[0] = origin[0] + idZ*zAxis[0]; // incremental transform
|
||
|
inPoint0[1] = origin[1] + idZ*zAxis[1];
|
||
|
inPoint0[2] = origin[2] + idZ*zAxis[2];
|
||
|
inPoint0[3] = origin[3] + idZ*zAxis[3];
|
||
|
|
||
|
for (idY = outExt[2]; idY <= outExt[3]; idY++)
|
||
|
{
|
||
|
inPoint1[0] = inPoint0[0] + idY*yAxis[0]; // incremental transform
|
||
|
inPoint1[1] = inPoint0[1] + idY*yAxis[1];
|
||
|
inPoint1[2] = inPoint0[2] + idY*yAxis[2];
|
||
|
inPoint1[3] = inPoint0[3] + idY*yAxis[3];
|
||
|
|
||
|
if (!id)
|
||
|
{
|
||
|
if (!(count%target))
|
||
|
{
|
||
|
self->UpdateProgress(count/(50.0*target));
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
iter = 0;
|
||
|
while (vtkResliceGetNextExtent(stencil, idXmin, idXmax,
|
||
|
outExt[0], outExt[1], idY, idZ,
|
||
|
outPtr, background, numscalars,
|
||
|
setpixels, iter))
|
||
|
{
|
||
|
if (!optimizeNearest)
|
||
|
{
|
||
|
for (idX = idXmin; idX <= idXmax; idX++)
|
||
|
{
|
||
|
inPoint[0] = inPoint1[0] + idX*xAxis[0];
|
||
|
inPoint[1] = inPoint1[1] + idX*xAxis[1];
|
||
|
inPoint[2] = inPoint1[2] + idX*xAxis[2];
|
||
|
if (perspective)
|
||
|
{ // only do perspective if necessary
|
||
|
inPoint[3] = inPoint1[3] + idX*xAxis[3];
|
||
|
f = 1/inPoint[3];
|
||
|
inPoint[0] *= f;
|
||
|
inPoint[1] *= f;
|
||
|
inPoint[2] *= f;
|
||
|
}
|
||
|
if (newtrans)
|
||
|
{ // apply the AbstractTransform if there is one
|
||
|
vtkResliceApplyTransform(newtrans, inPoint, inOrigin,
|
||
|
inInvSpacing);
|
||
|
}
|
||
|
// call the interpolation function
|
||
|
interpolate(outPtr, inPtr, inExt, inInc, numscalars,
|
||
|
inPoint, mode, background);
|
||
|
}
|
||
|
}
|
||
|
else // optimize for nearest-neighbor interpolation
|
||
|
{
|
||
|
int inExtX = inExt[1] - inExt[0] + 1;
|
||
|
int inExtY = inExt[3] - inExt[2] + 1;
|
||
|
int inExtZ = inExt[5] - inExt[4] + 1;
|
||
|
|
||
|
for (int iidX = idXmin; iidX <= idXmax; iidX++)
|
||
|
{
|
||
|
void *inPtrTmp = background;
|
||
|
|
||
|
inPoint[0] = inPoint1[0] + iidX*xAxis[0];
|
||
|
inPoint[1] = inPoint1[1] + iidX*xAxis[1];
|
||
|
inPoint[2] = inPoint1[2] + iidX*xAxis[2];
|
||
|
|
||
|
int inIdX = vtkResliceRound(inPoint[0]) - inExt[0];
|
||
|
int inIdY = vtkResliceRound(inPoint[1]) - inExt[2];
|
||
|
int inIdZ = vtkResliceRound(inPoint[2]) - inExt[4];
|
||
|
|
||
|
if (inIdX >= 0 && inIdX < inExtX &&
|
||
|
inIdY >= 0 && inIdY < inExtY &&
|
||
|
inIdZ >= 0 && inIdZ < inExtZ)
|
||
|
{
|
||
|
inPtrTmp = (void *)((char *)inPtr + \
|
||
|
(inIdX*inInc[0] +
|
||
|
inIdY*inInc[1] +
|
||
|
inIdZ*inInc[2])*scalarSize);
|
||
|
}
|
||
|
|
||
|
setpixels(outPtr, inPtrTmp, numscalars, 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outIncY*scalarSize);
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outIncZ*scalarSize);
|
||
|
}
|
||
|
|
||
|
vtkFreeBackgroundPixel(self, &background);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// vtkReslicePermuteExecute is specifically optimized for
|
||
|
// cases where the IndexMatrix has only one non-zero component
|
||
|
// per row, i.e. when the matrix is permutation+scale+translation.
|
||
|
// All of the interpolation coefficients are calculated ahead
|
||
|
// of time instead of on a pixel-by-pixel basis.
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// helper function for nearest neighbor interpolation
|
||
|
template<class F, class T>
|
||
|
void vtkPermuteNearestSummation(T *&outPtr, const T *inPtr,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *,
|
||
|
const vtkIdType *iY, const F *,
|
||
|
const vtkIdType *iZ, const F *,
|
||
|
const int [3])
|
||
|
{
|
||
|
const T *inPtr0 = inPtr + iY[0] + iZ[0];
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
const T *tmpPtr = &inPtr0[iX[0]];
|
||
|
iX++;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *tmpPtr++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ditto, but optimized for numscalars = 1
|
||
|
template<class F, class T>
|
||
|
void vtkPermuteNearestSummation1(T *&outPtr, const T *inPtr,
|
||
|
int, int n,
|
||
|
const vtkIdType *iX, const F *,
|
||
|
const vtkIdType *iY, const F *,
|
||
|
const vtkIdType *iZ, const F *,
|
||
|
const int [3])
|
||
|
{
|
||
|
const T *inPtr0 = inPtr + iY[0] + iZ[0];
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
*outPtr++ = inPtr0[iX[0]];
|
||
|
iX++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// helper function for linear interpolation
|
||
|
template<class F, class T>
|
||
|
void vtkPermuteTrilinearSummation(T *&outPtr, const T *inPtr,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearestNeighbor[3])
|
||
|
{
|
||
|
vtkIdType i00 = iY[0] + iZ[0];
|
||
|
vtkIdType i01 = iY[0] + iZ[1];
|
||
|
vtkIdType i10 = iY[1] + iZ[0];
|
||
|
vtkIdType i11 = iY[1] + iZ[1];
|
||
|
|
||
|
F ry = fY[0];
|
||
|
F fy = fY[1];
|
||
|
F rz = fZ[0];
|
||
|
F fz = fZ[1];
|
||
|
|
||
|
F ryrz = ry*rz;
|
||
|
F ryfz = ry*fz;
|
||
|
F fyrz = fy*rz;
|
||
|
F fyfz = fy*fz;
|
||
|
|
||
|
if (useNearestNeighbor[0] && fy == 0 && fz == 0)
|
||
|
{ // no interpolation needed at all
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
vtkIdType t0 = iX[0];
|
||
|
iX += 2;
|
||
|
|
||
|
const T *inPtr0 = inPtr + i00 + t0;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
*outPtr++ = *inPtr0++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
else if (useNearestNeighbor[0] && fy == 0)
|
||
|
{ // only need linear z interpolation
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
vtkIdType t0 = iX[0];
|
||
|
iX += 2;
|
||
|
|
||
|
const T *inPtr0 = inPtr + t0;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
F result = (rz*inPtr0[i00] + fz*inPtr0[i01]);
|
||
|
vtkResliceRound(result, *outPtr++);
|
||
|
inPtr0++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
else if (fz == 0)
|
||
|
{ // bilinear interpolation in x,y
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
F rx = fX[0];
|
||
|
F fx = fX[1];
|
||
|
fX += 2;
|
||
|
|
||
|
vtkIdType t0 = iX[0];
|
||
|
vtkIdType t1 = iX[1];
|
||
|
iX += 2;
|
||
|
|
||
|
const T *inPtr0 = inPtr + t0;
|
||
|
const T *inPtr1 = inPtr + t1;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
F result = (rx*(ry*inPtr0[i00] + fy*inPtr0[i10]) +
|
||
|
fx*(ry*inPtr1[i00] + fy*inPtr1[i10]));
|
||
|
|
||
|
vtkResliceRound(result, *outPtr++);
|
||
|
inPtr0++;
|
||
|
inPtr1++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // do full trilinear interpolation
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
F rx = fX[0];
|
||
|
F fx = fX[1];
|
||
|
fX += 2;
|
||
|
|
||
|
vtkIdType t0 = iX[0];
|
||
|
vtkIdType t1 = iX[1];
|
||
|
iX += 2;
|
||
|
|
||
|
const T *inPtr0 = inPtr + t0;
|
||
|
const T *inPtr1 = inPtr + t1;
|
||
|
int m = numscalars;
|
||
|
do
|
||
|
{
|
||
|
F result = (rx*(ryrz*inPtr0[i00] + ryfz*inPtr0[i01] +
|
||
|
fyrz*inPtr0[i10] + fyfz*inPtr0[i11]) +
|
||
|
fx*(ryrz*inPtr1[i00] + ryfz*inPtr1[i01] +
|
||
|
fyrz*inPtr1[i10] + fyfz*inPtr1[i11]));
|
||
|
|
||
|
vtkResliceRound(result, *outPtr++);
|
||
|
inPtr0++;
|
||
|
inPtr1++;
|
||
|
}
|
||
|
while (--m);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// helper function for tricubic interpolation
|
||
|
template<class F, class T>
|
||
|
void vtkPermuteTricubicSummation(T *&outPtr, const T *inPtr,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearestNeighbor[3])
|
||
|
{
|
||
|
// speed things up a bit for bicubic interpolation
|
||
|
int k1 = 0;
|
||
|
int k2 = 3;
|
||
|
if (useNearestNeighbor[2])
|
||
|
{
|
||
|
k1 = k2 = 1;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
vtkIdType iX0 = iX[0];
|
||
|
vtkIdType iX1 = iX[1];
|
||
|
vtkIdType iX2 = iX[2];
|
||
|
vtkIdType iX3 = iX[3];
|
||
|
iX += 4;
|
||
|
|
||
|
F fX0 = fX[0];
|
||
|
F fX1 = fX[1];
|
||
|
F fX2 = fX[2];
|
||
|
F fX3 = fX[3];
|
||
|
fX += 4;
|
||
|
|
||
|
const T *inPtr0 = inPtr;
|
||
|
int c = numscalars;
|
||
|
do
|
||
|
{ // loop over components
|
||
|
F result = 0;
|
||
|
|
||
|
int k = k1;
|
||
|
do
|
||
|
{ // loop over z
|
||
|
F fz = fZ[k];
|
||
|
if (fz != 0)
|
||
|
{
|
||
|
vtkIdType iz = iZ[k];
|
||
|
int j = 0;
|
||
|
do
|
||
|
{ // loop over y
|
||
|
F fy = fY[j];
|
||
|
F fzy = fz*fy;
|
||
|
vtkIdType izy = iz + iY[j];
|
||
|
const T *tmpPtr = inPtr0 + izy;
|
||
|
// loop over x is unrolled (significant performance boost)
|
||
|
result += fzy*(fX0*tmpPtr[iX0] +
|
||
|
fX1*tmpPtr[iX1] +
|
||
|
fX2*tmpPtr[iX2] +
|
||
|
fX3*tmpPtr[iX3]);
|
||
|
}
|
||
|
while (++j <= 3);
|
||
|
}
|
||
|
}
|
||
|
while (++k <= k2);
|
||
|
|
||
|
vtkResliceClamp(result, *outPtr++);
|
||
|
inPtr0++;
|
||
|
}
|
||
|
while (--c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// get approprate summation function for different interpolation modes
|
||
|
// and different scalar types
|
||
|
template<class F>
|
||
|
void vtkGetResliceSummationFunc(vtkImageReslice *self,
|
||
|
void (**summation)(void *&out, const void *in,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearest[3]),
|
||
|
int interpolationMode)
|
||
|
{
|
||
|
int scalarType = self->GetOutput()->GetScalarType();
|
||
|
|
||
|
switch (interpolationMode)
|
||
|
{
|
||
|
case VTK_RESLICE_NEAREST:
|
||
|
switch (scalarType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((void (**)(VTK_TT *&out, const VTK_TT *in,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearest[3]))summation) = \
|
||
|
vtkPermuteNearestSummation);
|
||
|
default:
|
||
|
summation = 0;
|
||
|
}
|
||
|
break;
|
||
|
case VTK_RESLICE_LINEAR:
|
||
|
switch (scalarType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((void (**)(VTK_TT *&out, const VTK_TT *in,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearest[3]))summation) = \
|
||
|
vtkPermuteTrilinearSummation);
|
||
|
default:
|
||
|
summation = 0;
|
||
|
}
|
||
|
break;
|
||
|
case VTK_RESLICE_CUBIC:
|
||
|
switch (scalarType)
|
||
|
{
|
||
|
vtkTemplateAliasMacro(*((void (**)(VTK_TT *&out, const VTK_TT *in,
|
||
|
int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearest[3]))summation) = \
|
||
|
vtkPermuteTricubicSummation);
|
||
|
default:
|
||
|
summation = 0;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
summation = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
template <class F>
|
||
|
void vtkPermuteNearestTable(vtkImageReslice *self, const int outExt[6],
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int clipExt[6], vtkIdType **traversal,
|
||
|
F **vtkNotUsed(constants),
|
||
|
int useNearestNeighbor[3], F newmat[4][4])
|
||
|
{
|
||
|
// set up input traversal table for nearest-neighbor interpolation
|
||
|
for (int j = 0; j < 3; j++)
|
||
|
{
|
||
|
int k;
|
||
|
for (k = 0; k < 3; k++)
|
||
|
{ // set k to the element which is nonzero
|
||
|
if (newmat[k][j] != 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// this is just for symmetry with Linear and Cubic
|
||
|
useNearestNeighbor[j] = 1;
|
||
|
|
||
|
int inExtK = inExt[2*k+1] - inExt[2*k] + 1;
|
||
|
|
||
|
int region = 0;
|
||
|
for (int i = outExt[2*j]; i <= outExt[2*j+1]; i++)
|
||
|
{
|
||
|
int inId = vtkResliceRound((newmat[k][3] + i*newmat[k][j]));
|
||
|
inId -= inExt[2*k];
|
||
|
if (self->GetMirror())
|
||
|
{
|
||
|
inId = vtkInterpolateMirror(inId, inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else if (self->GetWrap())
|
||
|
{
|
||
|
inId = vtkInterpolateWrap(inId, inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (inId < 0 || inId >= inExtK)
|
||
|
{
|
||
|
if (region == 1)
|
||
|
{ // leaving the input extent
|
||
|
region = 2;
|
||
|
clipExt[2*j+1] = i - 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (region == 0)
|
||
|
{ // entering the input extent
|
||
|
region = 1;
|
||
|
clipExt[2*j] = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
traversal[j][i] = inId*inInc[k];
|
||
|
}
|
||
|
if (region == 0)
|
||
|
{ // never entered input extent!
|
||
|
clipExt[2*j] = clipExt[2*j+1] + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
template <class F>
|
||
|
void vtkPermuteLinearTable(vtkImageReslice *self, const int outExt[6],
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int clipExt[6], vtkIdType **traversal,
|
||
|
F **constants,
|
||
|
int useNearestNeighbor[3], F newmat[4][4])
|
||
|
{
|
||
|
// set up input traversal table for linear interpolation
|
||
|
for (int j = 0; j < 3; j++)
|
||
|
{
|
||
|
int k;
|
||
|
for (k = 0; k < 3; k++)
|
||
|
{ // set k to the element which is nonzero
|
||
|
if (newmat[k][j] != 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// do the output pixels lie exactly on top of the input pixels?
|
||
|
F f1, f2;
|
||
|
vtkResliceFloor(newmat[k][j], f1);
|
||
|
vtkResliceFloor(newmat[k][3], f2);
|
||
|
useNearestNeighbor[j] = (f1 == 0 && f2 == 0);
|
||
|
|
||
|
int inExtK = inExt[2*k+1] - inExt[2*k] + 1;
|
||
|
|
||
|
int region = 0;
|
||
|
for (int i = outExt[2*j]; i <= outExt[2*j+1]; i++)
|
||
|
{
|
||
|
F point = newmat[k][3] + i*newmat[k][j];
|
||
|
F f;
|
||
|
int trunc = vtkResliceFloor(point, f);
|
||
|
constants[j][2*i] = 1 - f;
|
||
|
constants[j][2*i+1] = f;
|
||
|
|
||
|
int fIsNotZero = (f != 0);
|
||
|
int inId0 = trunc - inExt[2*k];
|
||
|
int inId1 = inId0 + fIsNotZero;
|
||
|
|
||
|
if (self->GetMirror())
|
||
|
{
|
||
|
inId0 = vtkInterpolateMirror(inId0, inExtK);
|
||
|
inId1 = vtkInterpolateMirror(inId1, inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else if (self->GetWrap())
|
||
|
{
|
||
|
inId0 = vtkInterpolateWrap(inId0, inExtK);
|
||
|
inId1 = vtkInterpolateWrap(inId1, inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else if (self->GetBorder())
|
||
|
{
|
||
|
if (vtkInterpolateBorder(inId0, inId1, inExtK, f))
|
||
|
{
|
||
|
if (region == 1)
|
||
|
{ // leaving the input extent
|
||
|
region = 2;
|
||
|
clipExt[2*j+1] = i - 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (region == 0)
|
||
|
{ // entering the input extent
|
||
|
region = 1;
|
||
|
clipExt[2*j] = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else // not self->GetBorder()
|
||
|
{
|
||
|
if (inId0 < 0 || inId1 >= inExtK)
|
||
|
{
|
||
|
if (region == 1)
|
||
|
{ // leaving the input extent
|
||
|
region = 2;
|
||
|
clipExt[2*j+1] = i - 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (region == 0)
|
||
|
{ // entering the input extent
|
||
|
region = 1;
|
||
|
clipExt[2*j] = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
traversal[j][2*i] = inId0*inInc[k];
|
||
|
traversal[j][2*i+1] = inId1*inInc[k];
|
||
|
}
|
||
|
if (region == 0)
|
||
|
{ // never entered input extent!
|
||
|
clipExt[2*j] = clipExt[2*j+1] + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
template <class F>
|
||
|
void vtkPermuteCubicTable(vtkImageReslice *self, const int outExt[6],
|
||
|
const int inExt[6], const vtkIdType inInc[3],
|
||
|
int clipExt[6], vtkIdType **traversal,
|
||
|
F **constants,
|
||
|
int useNearestNeighbor[3], F newmat[4][4])
|
||
|
{
|
||
|
// set up input traversal table for cubic interpolation
|
||
|
for (int j = 0; j < 3; j++)
|
||
|
{
|
||
|
int k;
|
||
|
for (k = 0; k < 3; k++)
|
||
|
{ // set k to the element which is nonzero
|
||
|
if (newmat[k][j] != 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// do the output pixels lie exactly on top of the input pixels?
|
||
|
F f1, f2;
|
||
|
vtkResliceFloor(newmat[k][j], f1);
|
||
|
vtkResliceFloor(newmat[k][3], f2);
|
||
|
useNearestNeighbor[j] = (f1 == 0 && f2 == 0);
|
||
|
|
||
|
int inExtK = inExt[2*k+1] - inExt[2*k] + 1;
|
||
|
|
||
|
int region = 0;
|
||
|
for (int i = outExt[2*j]; i <= outExt[2*j+1]; i++)
|
||
|
{
|
||
|
F point = newmat[k][3] + i*newmat[k][j];
|
||
|
F f;
|
||
|
int trunc = vtkResliceFloor(point, f);
|
||
|
int fIsNotZero = (f != 0);
|
||
|
int inId[4];
|
||
|
inId[1] = trunc - inExt[2*k];
|
||
|
inId[0] = inId[1] - 1;
|
||
|
inId[2] = inId[1] + 1;
|
||
|
inId[3] = inId[1] + 2;
|
||
|
|
||
|
int low = 1 - fIsNotZero;
|
||
|
int high = 1 + 2*fIsNotZero;
|
||
|
if (self->GetMirror())
|
||
|
{
|
||
|
inId[0] = vtkInterpolateMirror(inId[0], inExtK);
|
||
|
inId[1] = vtkInterpolateMirror(inId[1], inExtK);
|
||
|
inId[2] = vtkInterpolateMirror(inId[2], inExtK);
|
||
|
inId[3] = vtkInterpolateMirror(inId[3], inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else if (self->GetWrap())
|
||
|
{
|
||
|
inId[0] = vtkInterpolateWrap(inId[0], inExtK);
|
||
|
inId[1] = vtkInterpolateWrap(inId[1], inExtK);
|
||
|
inId[2] = vtkInterpolateWrap(inId[2], inExtK);
|
||
|
inId[3] = vtkInterpolateWrap(inId[3], inExtK);
|
||
|
region = 1;
|
||
|
}
|
||
|
else if (self->GetBorder())
|
||
|
{
|
||
|
if (vtkInterpolateBorderCheck(inId[1], inId[2], inExtK, f))
|
||
|
{
|
||
|
if (region == 1)
|
||
|
{ // leaving the input extent
|
||
|
region = 2;
|
||
|
clipExt[2*j+1] = i - 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (region == 0)
|
||
|
{ // entering the input extent
|
||
|
region = 1;
|
||
|
clipExt[2*j] = i;
|
||
|
}
|
||
|
}
|
||
|
int tmpExt = inExtK - 1;
|
||
|
inId[0] = (inId[0])*(inId[0] >= 0);
|
||
|
inId[1] = (inId[1])*(inId[1] >= 0);
|
||
|
inId[2] = tmpExt - (tmpExt - inId[2])*(tmpExt - inId[2] >= 0);
|
||
|
inId[3] = tmpExt - (tmpExt - inId[3])*(tmpExt - inId[3] >= 0);
|
||
|
low = 1 - fIsNotZero;
|
||
|
high = 1 + 2*fIsNotZero;
|
||
|
}
|
||
|
else // not self->GetBorder()
|
||
|
{
|
||
|
if (inId[1] < 0 || inId[1] + fIsNotZero >= inExtK)
|
||
|
{
|
||
|
if (region == 1)
|
||
|
{ // leaving the input extent
|
||
|
region = 2;
|
||
|
clipExt[2*j+1] = i - 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (region == 0)
|
||
|
{ // entering the input extent
|
||
|
region = 1;
|
||
|
clipExt[2*j] = i;
|
||
|
}
|
||
|
}
|
||
|
low = 1 - (inId[0] >= 0)*fIsNotZero;
|
||
|
high = 1 + (1 + (inId[3] < inExtK))*fIsNotZero;
|
||
|
}
|
||
|
vtkTricubicInterpCoeffs(&constants[j][4*i], low, high, f);
|
||
|
|
||
|
// set default values
|
||
|
int l;
|
||
|
for (l = 0; l < 4; l++)
|
||
|
{
|
||
|
traversal[j][4*i+l] = inId[1]*inInc[k];
|
||
|
}
|
||
|
for (l = low; l <= high; l++)
|
||
|
{
|
||
|
traversal[j][4*i+l] = inId[l]*inInc[k];
|
||
|
}
|
||
|
}
|
||
|
if (region == 0)
|
||
|
{ // never entered input extent!
|
||
|
clipExt[2*j] = clipExt[2*j+1] + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Check to see if we can do nearest-neighbor instead of linear or cubic.
|
||
|
// This check only works on permutation+scale+translation matrices.
|
||
|
template <class F>
|
||
|
inline int vtkCanUseNearestNeighbor(F matrix[4][4], int outExt[6])
|
||
|
{
|
||
|
// loop through dimensions
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
int j;
|
||
|
for (j = 0; j < 3; j++)
|
||
|
{
|
||
|
if (matrix[i][j] != 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
F x = matrix[i][j];
|
||
|
F y = matrix[i][3];
|
||
|
if (outExt[2*j] == outExt[2*j+1])
|
||
|
{
|
||
|
y += x*outExt[2*i];
|
||
|
x = 0;
|
||
|
}
|
||
|
F fx, fy;
|
||
|
vtkResliceFloor(x, fx);
|
||
|
vtkResliceFloor(y, fy);
|
||
|
if (fx != 0 || fy != 0)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// the ReslicePermuteExecute path is taken when the output slices are
|
||
|
// orthogonal to the input slices
|
||
|
template <class F>
|
||
|
void vtkReslicePermuteExecute(vtkImageReslice *self,
|
||
|
vtkImageData *inData, void *inPtr,
|
||
|
vtkImageData *outData, void *outPtr,
|
||
|
int outExt[6], int id, F newmat[4][4])
|
||
|
{
|
||
|
vtkIdType outInc[3];
|
||
|
int scalarSize, numscalars;
|
||
|
vtkIdType inInc[3];
|
||
|
int inExt[6], clipExt[6];
|
||
|
vtkIdType *traversal[3];
|
||
|
F *constants[3];
|
||
|
int useNearestNeighbor[3];
|
||
|
int i;
|
||
|
|
||
|
// find maximum input range
|
||
|
inData->GetExtent(inExt);
|
||
|
|
||
|
// Get Increments to march through data
|
||
|
inData->GetIncrements(inInc);
|
||
|
outData->GetContinuousIncrements(outExt, outInc[0], outInc[1], outInc[2]);
|
||
|
scalarSize = outData->GetScalarSize();
|
||
|
numscalars = inData->GetNumberOfScalarComponents();
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
clipExt[2*i] = outExt[2*i];
|
||
|
clipExt[2*i+1] = outExt[2*i+1];
|
||
|
}
|
||
|
|
||
|
int interpolationMode = self->GetInterpolationMode();
|
||
|
if (vtkCanUseNearestNeighbor(newmat, outExt))
|
||
|
{
|
||
|
interpolationMode = VTK_RESLICE_NEAREST;
|
||
|
}
|
||
|
|
||
|
// the step size is the number of coefficients per dimension
|
||
|
int step = 1;
|
||
|
switch (interpolationMode)
|
||
|
{
|
||
|
case VTK_RESLICE_NEAREST:
|
||
|
step = 1;
|
||
|
break;
|
||
|
case VTK_RESLICE_LINEAR:
|
||
|
step = 2;
|
||
|
break;
|
||
|
case VTK_RESLICE_CUBIC:
|
||
|
step = 4;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// allocate the interpolation tables
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
int outExtI = outExt[2*i+1] - outExt[2*i] + 1;
|
||
|
|
||
|
traversal[i] = new vtkIdType[outExtI*step];
|
||
|
traversal[i] -= step*outExt[2*i];
|
||
|
constants[i] = new F[outExtI*step];
|
||
|
constants[i] -= step*outExt[2*i];
|
||
|
}
|
||
|
|
||
|
// fill in the interpolation tables
|
||
|
switch (interpolationMode)
|
||
|
{
|
||
|
case VTK_RESLICE_NEAREST:
|
||
|
vtkPermuteNearestTable(self, outExt, inExt, inInc, clipExt,
|
||
|
traversal, constants,
|
||
|
useNearestNeighbor, newmat);
|
||
|
break;
|
||
|
case VTK_RESLICE_LINEAR:
|
||
|
vtkPermuteLinearTable(self, outExt, inExt, inInc, clipExt,
|
||
|
traversal, constants,
|
||
|
useNearestNeighbor, newmat);
|
||
|
break;
|
||
|
case VTK_RESLICE_CUBIC:
|
||
|
vtkPermuteCubicTable(self, outExt, inExt, inInc, clipExt,
|
||
|
traversal, constants,
|
||
|
useNearestNeighbor, newmat);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// get type-specific functions
|
||
|
void (*summation)(void *&out, const void *in, int numscalars, int n,
|
||
|
const vtkIdType *iX, const F *fX,
|
||
|
const vtkIdType *iY, const F *fY,
|
||
|
const vtkIdType *iZ, const F *fZ,
|
||
|
const int useNearestNeighbor[3]);
|
||
|
void (*setpixels)(void *&out, const void *in, int numscalars, int n);
|
||
|
vtkGetResliceSummationFunc(self, &summation, interpolationMode);
|
||
|
vtkGetSetPixelsFunc(self, &setpixels);
|
||
|
|
||
|
// set color for area outside of input volume extent
|
||
|
void *background;
|
||
|
vtkAllocBackgroundPixel(self, &background, numscalars);
|
||
|
|
||
|
// get the stencil
|
||
|
vtkImageStencilData *stencil = self->GetStencil();
|
||
|
|
||
|
// for tracking progress
|
||
|
unsigned long count = 0;
|
||
|
unsigned long target = (unsigned long)
|
||
|
((outExt[5]-outExt[4]+1)*(outExt[3]-outExt[2]+1)/50.0);
|
||
|
target++;
|
||
|
|
||
|
// Loop through output pixels
|
||
|
for (int idZ = outExt[4]; idZ <= outExt[5]; idZ++)
|
||
|
{
|
||
|
int idZ0 = idZ*step;
|
||
|
|
||
|
for (int idY = outExt[2]; idY <= outExt[3]; idY++)
|
||
|
{
|
||
|
int idY0 = idY*step;
|
||
|
|
||
|
if (id == 0)
|
||
|
{ // track progress if we are main thread
|
||
|
if (!(count%target))
|
||
|
{
|
||
|
self->UpdateProgress(count/(50.0*target));
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
// do extent check
|
||
|
if (idZ < clipExt[4] || idZ > clipExt[5] ||
|
||
|
idY < clipExt[2] || idY > clipExt[3])
|
||
|
{ // just clear, we're completely outside
|
||
|
setpixels(outPtr, background, numscalars, outExt[1] - outExt[0] + 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// clear pixels to left of input extent
|
||
|
setpixels(outPtr, background, numscalars, clipExt[0] - outExt[0]);
|
||
|
|
||
|
int iter = 0;
|
||
|
int idXmin, idXmax;
|
||
|
while (vtkResliceGetNextExtent(stencil, idXmin, idXmax,
|
||
|
clipExt[0], clipExt[1], idY, idZ,
|
||
|
outPtr, background, numscalars,
|
||
|
setpixels, iter))
|
||
|
{
|
||
|
int idX0 = idXmin*step;
|
||
|
|
||
|
summation(outPtr, inPtr, numscalars, idXmax - idXmin + 1,
|
||
|
&traversal[0][idX0], &constants[0][idX0],
|
||
|
&traversal[1][idY0], &constants[1][idY0],
|
||
|
&traversal[2][idZ0], &constants[2][idZ0],
|
||
|
useNearestNeighbor);
|
||
|
}
|
||
|
|
||
|
// clear pixels to right of input extent
|
||
|
setpixels(outPtr, background, numscalars, outExt[1] - clipExt[1]);
|
||
|
}
|
||
|
|
||
|
outPtr = (void *)((char *)outPtr + outInc[1]*scalarSize);
|
||
|
}
|
||
|
outPtr = (void *)((char *)outPtr + outInc[2]*scalarSize);
|
||
|
}
|
||
|
|
||
|
vtkFreeBackgroundPixel(self, &background);
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
{
|
||
|
traversal[i] += step*outExt[2*i];
|
||
|
constants[i] += step*outExt[2*i];
|
||
|
delete [] traversal[i];
|
||
|
delete [] constants[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// check a matrix to ensure that it is a permutation+scale+translation
|
||
|
// matrix
|
||
|
|
||
|
template <class F>
|
||
|
int vtkIsPermutationMatrix(F matrix[4][4])
|
||
|
{
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (matrix[3][i] != 0)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
if (matrix[3][3] != 1)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
for (int j = 0; j < 3; j++)
|
||
|
{
|
||
|
int k = 0;
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (matrix[i][j] != 0)
|
||
|
{
|
||
|
k++;
|
||
|
}
|
||
|
}
|
||
|
if (k != 1)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// check a matrix to see whether it is the identity matrix
|
||
|
|
||
|
int vtkIsIdentityMatrix(vtkMatrix4x4 *matrix)
|
||
|
{
|
||
|
static double identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||
|
int i,j;
|
||
|
|
||
|
for (i = 0; i < 4; i++)
|
||
|
{
|
||
|
for (j = 0; j < 4; j++)
|
||
|
{
|
||
|
if (matrix->GetElement(i,j) != identity[4*i+j])
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// The transform matrix supplied by the user converts output coordinates
|
||
|
// to input coordinates.
|
||
|
// To speed up the pixel lookup, the following function provides a
|
||
|
// matrix which converts output pixel indices to input pixel indices.
|
||
|
//
|
||
|
// This will also concatenate the ResliceAxes and the ResliceTransform
|
||
|
// if possible (if the ResliceTransform is a 4x4 matrix transform).
|
||
|
// If it does, this->OptimizedTransform will be set to NULL, otherwise
|
||
|
// this->OptimizedTransform will be equal to this->ResliceTransform.
|
||
|
|
||
|
vtkMatrix4x4 *vtkImageReslice::GetIndexMatrix(vtkInformation *inInfo,
|
||
|
vtkInformation *outInfo)
|
||
|
{
|
||
|
// first verify that we have to update the matrix
|
||
|
if (this->IndexMatrix == NULL)
|
||
|
{
|
||
|
this->IndexMatrix = vtkMatrix4x4::New();
|
||
|
}
|
||
|
|
||
|
int isIdentity = 0;
|
||
|
double inOrigin[3];
|
||
|
double inSpacing[3];
|
||
|
double outOrigin[3];
|
||
|
double outSpacing[3];
|
||
|
|
||
|
inInfo->Get(vtkDataObject::SPACING(), inSpacing);
|
||
|
inInfo->Get(vtkDataObject::ORIGIN(), inOrigin);
|
||
|
outInfo->Get(vtkDataObject::SPACING(), outSpacing);
|
||
|
outInfo->Get(vtkDataObject::ORIGIN(), outOrigin);
|
||
|
|
||
|
vtkTransform *transform = vtkTransform::New();
|
||
|
vtkMatrix4x4 *inMatrix = vtkMatrix4x4::New();
|
||
|
vtkMatrix4x4 *outMatrix = vtkMatrix4x4::New();
|
||
|
|
||
|
if (this->OptimizedTransform)
|
||
|
{
|
||
|
this->OptimizedTransform->Delete();
|
||
|
}
|
||
|
this->OptimizedTransform = NULL;
|
||
|
|
||
|
if (this->ResliceAxes)
|
||
|
{
|
||
|
transform->SetMatrix(this->GetResliceAxes());
|
||
|
}
|
||
|
if (this->ResliceTransform)
|
||
|
{
|
||
|
if (this->ResliceTransform->IsA("vtkHomogeneousTransform"))
|
||
|
{
|
||
|
transform->PostMultiply();
|
||
|
transform->Concatenate(((vtkHomogeneousTransform *)
|
||
|
this->ResliceTransform)->GetMatrix());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this->ResliceTransform->Register(this);
|
||
|
this->OptimizedTransform = this->ResliceTransform;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check to see if we have an identity matrix
|
||
|
isIdentity = vtkIsIdentityMatrix(transform->GetMatrix());
|
||
|
|
||
|
// the outMatrix takes OutputData indices to OutputData coordinates,
|
||
|
// the inMatrix takes InputData coordinates to InputData indices
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if ((this->OptimizedTransform == NULL &&
|
||
|
(inSpacing[i] != outSpacing[i] || inOrigin[i] != outOrigin[i])) ||
|
||
|
(this->OptimizedTransform != NULL &&
|
||
|
(inSpacing[i] != 1.0 || inOrigin[i] != 0.0)))
|
||
|
{
|
||
|
isIdentity = 0;
|
||
|
}
|
||
|
inMatrix->Element[i][i] = 1.0/inSpacing[i];
|
||
|
inMatrix->Element[i][3] = -inOrigin[i]/inSpacing[i];
|
||
|
outMatrix->Element[i][i] = outSpacing[i];
|
||
|
outMatrix->Element[i][3] = outOrigin[i];
|
||
|
}
|
||
|
outInfo->Get(vtkDataObject::ORIGIN(), outOrigin);
|
||
|
|
||
|
if (!isIdentity)
|
||
|
{
|
||
|
transform->PreMultiply();
|
||
|
transform->Concatenate(outMatrix);
|
||
|
if (this->OptimizedTransform == NULL)
|
||
|
{
|
||
|
transform->PostMultiply();
|
||
|
transform->Concatenate(inMatrix);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
transform->GetMatrix(this->IndexMatrix);
|
||
|
|
||
|
transform->Delete();
|
||
|
inMatrix->Delete();
|
||
|
outMatrix->Delete();
|
||
|
|
||
|
return this->IndexMatrix;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// This method is passed a input and output region, and executes the filter
|
||
|
// algorithm to fill the output from the input.
|
||
|
// It just executes a switch statement to call the correct function for
|
||
|
// the regions data types.
|
||
|
void vtkImageReslice::ThreadedRequestData(
|
||
|
vtkInformation *vtkNotUsed(request),
|
||
|
vtkInformationVector **vtkNotUsed(inputVector),
|
||
|
vtkInformationVector *vtkNotUsed(outputVector),
|
||
|
vtkImageData ***inData,
|
||
|
vtkImageData **outData,
|
||
|
int outExt[6], int id)
|
||
|
{
|
||
|
|
||
|
vtkDebugMacro(<< "Execute: inData = " << inData[0][0]
|
||
|
<< ", outData = " << outData[0]);
|
||
|
|
||
|
// this filter expects that input is the same type as output.
|
||
|
if (inData[0][0]->GetScalarType() != outData[0]->GetScalarType())
|
||
|
{
|
||
|
vtkErrorMacro(<< "Execute: input ScalarType, "
|
||
|
<< inData[0][0]->GetScalarType()
|
||
|
<< ", must match out ScalarType "
|
||
|
<< outData[0]->GetScalarType());
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int inExt[6];
|
||
|
inData[0][0]->GetExtent(inExt);
|
||
|
// check for empty input extent
|
||
|
if (inExt[1] < inExt[0] ||
|
||
|
inExt[3] < inExt[2] ||
|
||
|
inExt[5] < inExt[4])
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the output pointer
|
||
|
void *outPtr = outData[0]->GetScalarPointerForExtent(outExt);
|
||
|
|
||
|
if (this->HitInputExtent == 0)
|
||
|
{
|
||
|
vtkImageResliceClearExecute(this, inData[0][0], 0, outData[0], outPtr,
|
||
|
outExt, id);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Now that we know that we need the input, get the input pointer
|
||
|
void *inPtr = inData[0][0]->GetScalarPointerForExtent(inExt);
|
||
|
|
||
|
if (this->Optimization)
|
||
|
{
|
||
|
// change transform matrix so that instead of taking
|
||
|
// input coords -> output coords it takes output indices -> input indices
|
||
|
vtkMatrix4x4 *matrix = this->IndexMatrix;
|
||
|
|
||
|
// get the portion of the transformation that remains apart from
|
||
|
// the IndexMatrix
|
||
|
vtkAbstractTransform *newtrans = this->OptimizedTransform;
|
||
|
|
||
|
double newmat[4][4];
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
{
|
||
|
newmat[i][0] = matrix->GetElement(i,0);
|
||
|
newmat[i][1] = matrix->GetElement(i,1);
|
||
|
newmat[i][2] = matrix->GetElement(i,2);
|
||
|
newmat[i][3] = matrix->GetElement(i,3);
|
||
|
}
|
||
|
|
||
|
if (vtkIsPermutationMatrix(newmat) && newtrans == NULL)
|
||
|
{
|
||
|
vtkReslicePermuteExecute(this, inData[0][0], inPtr, outData[0], outPtr,
|
||
|
outExt, id, newmat);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vtkOptimizedExecute(this, inData[0][0], inPtr, outData[0], outPtr,
|
||
|
outExt, id, newmat, newtrans);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vtkImageResliceExecute(this, inData[0][0], inPtr, outData[0], outPtr,
|
||
|
outExt, id);
|
||
|
}
|
||
|
}
|
||
|
|