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.
769 lines
21 KiB
769 lines
21 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkImageEuclideanDistance.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 "vtkImageEuclideanDistance.h"
|
|
|
|
#include "vtkImageData.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
|
|
#include <math.h>
|
|
|
|
vtkCxxRevisionMacro(vtkImageEuclideanDistance, "$Revision: 1.23 $");
|
|
vtkStandardNewMacro(vtkImageEuclideanDistance);
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This defines the default values for the EDT parameters
|
|
vtkImageEuclideanDistance::vtkImageEuclideanDistance()
|
|
{
|
|
this->MaximumDistance = VTK_INT_MAX;
|
|
this->Initialize = 1;
|
|
this->ConsiderAnisotropy = 1;
|
|
this->Algorithm = VTK_EDT_SAITO;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This extent of the components changes to real and imaginary values.
|
|
int vtkImageEuclideanDistance::IterativeRequestInformation(
|
|
vtkInformation* vtkNotUsed(input), vtkInformation* output)
|
|
{
|
|
vtkDataObject::SetPointDataActiveScalarInfo(output, VTK_DOUBLE, 1);
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This method tells the superclass that the whole input array is needed
|
|
// to compute any output region.
|
|
int vtkImageEuclideanDistance::IterativeRequestUpdateExtent(
|
|
vtkInformation* input, vtkInformation* vtkNotUsed(output) )
|
|
{
|
|
int *wExt = input->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
|
|
input->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),wExt,6);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This templated execute method handles any type input, but the output
|
|
// is always doubles.
|
|
template <class TT>
|
|
void vtkImageEuclideanDistanceCopyData(vtkImageEuclideanDistance *self,
|
|
vtkImageData *inData, TT *inPtr,
|
|
vtkImageData *outData, int outExt[6],
|
|
double *outPtr )
|
|
{
|
|
vtkIdType inInc0, inInc1, inInc2;
|
|
TT *inPtr0, *inPtr1, *inPtr2;
|
|
|
|
int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
|
|
vtkIdType outInc0, outInc1, outInc2;
|
|
double *outPtr0, *outPtr1, *outPtr2;
|
|
|
|
int idx0, idx1, idx2;
|
|
|
|
// Reorder axes
|
|
self->PermuteExtent(outExt, outMin0,outMax0,outMin1,outMax1,outMin2,outMax2);
|
|
self->PermuteIncrements(inData->GetIncrements(), inInc0, inInc1, inInc2);
|
|
self->PermuteIncrements(outData->GetIncrements(), outInc0, outInc1, outInc2);
|
|
|
|
inPtr2 = inPtr;
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
inPtr1 = inPtr2;
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
inPtr0 = inPtr1;
|
|
outPtr0 = outPtr1;
|
|
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
*outPtr0 = *inPtr0 ;
|
|
inPtr0 += inInc0;
|
|
outPtr0 += outInc0;
|
|
}
|
|
inPtr1 += inInc1;
|
|
outPtr1 += outInc1;
|
|
}
|
|
inPtr2 += inInc2;
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This templated execute method handles any type input, but the output
|
|
// is always doubles.
|
|
template <class T>
|
|
void vtkImageEuclideanDistanceInitialize(vtkImageEuclideanDistance *self,
|
|
vtkImageData *inData, T *inPtr,
|
|
vtkImageData *outData,
|
|
int outExt[6], double *outPtr )
|
|
{
|
|
vtkIdType inInc0, inInc1, inInc2;
|
|
T *inPtr0, *inPtr1, *inPtr2;
|
|
|
|
int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
|
|
vtkIdType outInc0, outInc1, outInc2;
|
|
double *outPtr0, *outPtr1, *outPtr2;
|
|
|
|
int idx0, idx1, idx2;
|
|
double maxDist;
|
|
|
|
// Reorder axes
|
|
self->PermuteExtent(outExt, outMin0,outMax0,outMin1,outMax1,outMin2,outMax2);
|
|
self->PermuteIncrements(inData->GetIncrements(), inInc0, inInc1, inInc2);
|
|
self->PermuteIncrements(outData->GetIncrements(), outInc0, outInc1, outInc2);
|
|
|
|
if ( self->GetInitialize() == 1 )
|
|
// Initialization required. Input image is only used as binary mask,
|
|
// so all non-zero values are set to maxDist
|
|
//
|
|
{
|
|
maxDist = self->GetMaximumDistance();
|
|
|
|
inPtr2 = inPtr;
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
inPtr1 = inPtr2;
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
inPtr0 = inPtr1;
|
|
outPtr0 = outPtr1;
|
|
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
if( *inPtr0 == 0 ) {*outPtr0 = 0;}
|
|
else {*outPtr0 = maxDist;}
|
|
|
|
inPtr0 += inInc0;
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
inPtr1 += inInc1;
|
|
outPtr1 += outInc1;
|
|
}
|
|
inPtr2 += inInc2;
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
else
|
|
// No initialization required. We just copy inData to outData.
|
|
{
|
|
vtkImageEuclideanDistanceCopyData( self,
|
|
inData, (T *)(inPtr),
|
|
outData, outExt, (double *)(outPtr) );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Execute Saito's algorithm.
|
|
//
|
|
// T. Saito and J.I. Toriwaki. New algorithms for Euclidean distance
|
|
// transformations of an n-dimensional digitised picture with applications.
|
|
// Pattern Recognition, 27(11). pp. 1551--1565, 1994.
|
|
//
|
|
// Notations stay as close as possible to those used in the paper.
|
|
//
|
|
void vtkImageEuclideanDistanceExecuteSaito(vtkImageEuclideanDistance *self,
|
|
vtkImageData *outData,
|
|
int outExt[6], double *outPtr )
|
|
{
|
|
|
|
int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
|
|
vtkIdType outInc0, outInc1, outInc2;
|
|
double *outPtr0, *outPtr1, *outPtr2;
|
|
int idx0, idx1, idx2, inSize0;
|
|
double maxDist;
|
|
double *sq;
|
|
double *buff,buffer;
|
|
int df,a,b,n;
|
|
double m;
|
|
double spacing;
|
|
|
|
// Reorder axes (The outs here are just placeholdes
|
|
self->PermuteExtent(outExt, outMin0,outMax0,outMin1,outMax1,outMin2,outMax2);
|
|
self->PermuteIncrements(outData->GetIncrements(), outInc0, outInc1, outInc2);
|
|
|
|
inSize0 = outMax0 - outMin0 + 1;
|
|
maxDist = self->GetMaximumDistance();
|
|
|
|
buff= (double *)calloc(outMax0+1,sizeof(double));
|
|
|
|
// precompute sq[]. Anisotropy is handled here by using Spacing information
|
|
sq = (double *)calloc(inSize0*2+2,sizeof(double));
|
|
for(df=2*inSize0+1;df>inSize0;df--)
|
|
{
|
|
sq[df]=maxDist;
|
|
}
|
|
|
|
if ( self->GetConsiderAnisotropy() )
|
|
{
|
|
spacing = outData->GetSpacing()[ self->GetIteration() ];
|
|
}
|
|
else
|
|
{
|
|
spacing = 1;
|
|
}
|
|
|
|
spacing*=spacing;
|
|
|
|
for(df=inSize0;df>=0;df--)
|
|
{
|
|
sq[df]=df*df*spacing;
|
|
}
|
|
|
|
if ( self->GetIteration() == 0 )
|
|
{
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
outPtr0 = outPtr1;
|
|
df= inSize0 ;
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
if(*outPtr0 != 0)
|
|
{
|
|
df++ ;
|
|
if(sq[df] < *outPtr0) {*outPtr0 = sq[df];}
|
|
}
|
|
else
|
|
{
|
|
df=0;
|
|
}
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
outPtr0 -= outInc0;
|
|
df= inSize0 ;
|
|
for (idx0 = outMax0; idx0 >= outMin0; --idx0)
|
|
{
|
|
if(*outPtr0 != 0)
|
|
{
|
|
df++ ;
|
|
if(sq[df] < *outPtr0) {*outPtr0 = sq[df];}
|
|
}
|
|
else
|
|
{
|
|
df=0;
|
|
}
|
|
outPtr0 -= outInc0;
|
|
}
|
|
|
|
outPtr1 += outInc1;
|
|
}
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
else // next iterations are all identical.
|
|
{
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
outPtr0 = outPtr1;
|
|
|
|
// Buffer current values
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
buff[idx0]= *outPtr0;
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
// forward scan
|
|
a=0; buffer=buff[ outMin0 ];
|
|
outPtr0 = outPtr1;
|
|
outPtr0 += outInc0;
|
|
|
|
for (idx0 = outMin0+1; idx0 <= outMax0; ++idx0)
|
|
{
|
|
if(a>0) {a--;}
|
|
if(buff[idx0]>buffer+sq[1])
|
|
{
|
|
b=(int)(floor)((((buff[idx0]-buffer)/spacing)-1)/2);
|
|
if((idx0+b)>outMax0) {b=(outMax0)-idx0;}
|
|
|
|
for(n=a;n<=b;n++)
|
|
{
|
|
m=buffer+sq[n+1];
|
|
if(buff[idx0+n]<=m) {n=b;}
|
|
else if(m<*(outPtr0+n*outInc0)) {*(outPtr0+n*outInc0)=m;}
|
|
}
|
|
a=b;
|
|
}
|
|
else
|
|
{
|
|
a=0;
|
|
}
|
|
|
|
buffer=buff[idx0];
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
outPtr0 -= 2*outInc0;
|
|
a=0;
|
|
buffer=buff[outMax0];
|
|
|
|
for(idx0=outMax0-1;idx0>=outMin0; --idx0)
|
|
{
|
|
if(a>0) {a--;}
|
|
if(buff[idx0]>buffer+sq[1])
|
|
{
|
|
b=(int)(floor)((((buff[idx0]-buffer)/spacing)-1)/2);
|
|
if((idx0-b)<outMin0) {b=idx0-outMin0;}
|
|
|
|
for(n=a;n<=b;n++)
|
|
{
|
|
m=buffer+sq[n+1];
|
|
if(buff[idx0-n]<=m) {n=b;}
|
|
else if(m<*(outPtr0-n*outInc0)) {*(outPtr0-n*outInc0)=m;}
|
|
}
|
|
a=b;
|
|
}
|
|
else
|
|
{
|
|
a=0;
|
|
}
|
|
|
|
buffer=buff[idx0];
|
|
outPtr0 -= outInc0;
|
|
}
|
|
outPtr1 += outInc1;
|
|
}
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
|
|
free(buff);
|
|
free(sq);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Execute Saito's algorithm, modified for Cache Efficiency
|
|
//
|
|
void vtkImageEuclideanDistanceExecuteSaitoCached(
|
|
vtkImageEuclideanDistance *self,
|
|
vtkImageData *outData, int outExt[6], double *outPtr )
|
|
{
|
|
|
|
int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
|
|
vtkIdType outInc0, outInc1, outInc2;
|
|
double *outPtr0, *outPtr1, *outPtr2;
|
|
//
|
|
int idx0, idx1, idx2, inSize0;
|
|
|
|
double maxDist;
|
|
|
|
double *sq;
|
|
double *buff,*temp,buffer;
|
|
int df,a,b,n;
|
|
double m;
|
|
|
|
double spacing;
|
|
|
|
// Reorder axes (The outs here are just placeholdes
|
|
self->PermuteExtent(outExt, outMin0,outMax0,outMin1,outMax1,outMin2,outMax2);
|
|
self->PermuteIncrements(outData->GetIncrements(), outInc0, outInc1, outInc2);
|
|
|
|
inSize0 = outMax0 - outMin0 + 1;
|
|
maxDist = self->GetMaximumDistance();
|
|
|
|
buff= (double *)calloc(outMax0+1,sizeof(double));
|
|
temp= (double *)calloc(outMax0+1,sizeof(double));
|
|
|
|
// precompute sq[]. Anisotropy is handled here by using Spacing information
|
|
sq = (double *)calloc(inSize0*2+2,sizeof(double));
|
|
for(df=2*inSize0+1;df>inSize0;df--)
|
|
{
|
|
sq[df]=maxDist;
|
|
}
|
|
if ( self->GetConsiderAnisotropy() )
|
|
{
|
|
spacing = outData->GetSpacing()[ self->GetIteration() ];
|
|
}
|
|
else
|
|
{
|
|
spacing = 1;
|
|
}
|
|
spacing*=spacing;
|
|
|
|
for(df=inSize0;df>=0;df--)
|
|
{
|
|
sq[df]=df*df*spacing;
|
|
}
|
|
|
|
if ( self->GetIteration() == 0 )
|
|
{
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
outPtr0 = outPtr1;
|
|
df= inSize0 ;
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
if(*outPtr0 != 0)
|
|
{
|
|
df++ ;
|
|
if(sq[df] < *outPtr0) {*outPtr0 = sq[df];}
|
|
}
|
|
else
|
|
{
|
|
df=0;
|
|
}
|
|
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
outPtr0 -= outInc0;
|
|
df= inSize0 ;
|
|
for (idx0 = outMax0; idx0 >= outMin0; --idx0)
|
|
{
|
|
if(*outPtr0 != 0)
|
|
{
|
|
df++ ;
|
|
if(sq[df] < *outPtr0) {*outPtr0 = sq[df];}
|
|
}
|
|
else
|
|
{
|
|
df=0;
|
|
}
|
|
|
|
outPtr0 -= outInc0;
|
|
}
|
|
|
|
outPtr1 += outInc1;
|
|
}
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
else // next iterations are all identical.
|
|
{
|
|
outPtr2 = outPtr;
|
|
for (idx2 = outMin2; idx2 <= outMax2; ++idx2)
|
|
{
|
|
outPtr1 = outPtr2;
|
|
for (idx1 = outMin1; idx1 <= outMax1; ++idx1)
|
|
{
|
|
// Buffer current values
|
|
outPtr0 = outPtr1;
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
temp[idx0] = buff[idx0]= *outPtr0;
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
// forward scan
|
|
a=0; buffer=buff[ outMin0 ];
|
|
outPtr0 = temp ;
|
|
outPtr0 ++;
|
|
|
|
for (idx0 = outMin0+1; idx0 <= outMax0; ++idx0)
|
|
{
|
|
if(a>0) {a--;}
|
|
|
|
if(buff[idx0]>buffer+sq[1])
|
|
{
|
|
b=(int)(floor)((((buff[idx0]-buffer)/spacing)-1)/2);
|
|
if((idx0+b)>outMax0) {b=(outMax0)-idx0;}
|
|
|
|
for(n=a;n<=b;n++)
|
|
{
|
|
m=buffer+sq[n+1];
|
|
if(buff[idx0+n]<=m) {n=b;}
|
|
else if(m<*(outPtr0+n)) {*(outPtr0+n)=m;}
|
|
}
|
|
a=b;
|
|
}
|
|
else
|
|
{
|
|
a=0;
|
|
}
|
|
|
|
buffer=buff[idx0];
|
|
outPtr0 ++;
|
|
}
|
|
|
|
// backward scan
|
|
outPtr0 -= 2;
|
|
a=0;
|
|
buffer=buff[outMax0];
|
|
|
|
for(idx0=outMax0-1;idx0>=outMin0; --idx0)
|
|
{
|
|
if(a>0) {a--;}
|
|
if(buff[idx0]>buffer+sq[1])
|
|
{
|
|
b=(int)(floor)((((buff[idx0]-buffer)/spacing)-1)/2);
|
|
if((idx0-b)<outMin0) b=idx0-outMin0;
|
|
|
|
for(n=a;n<=b;n++)
|
|
{
|
|
m=buffer+sq[n+1];
|
|
if(buff[idx0-n]<=m) {n=b;}
|
|
else if(m<*(outPtr0-n)) {*(outPtr0-n)=m;}
|
|
}
|
|
a=b;
|
|
}
|
|
else
|
|
{
|
|
a=0;
|
|
}
|
|
buffer=buff[idx0];
|
|
outPtr0 --;
|
|
}
|
|
|
|
// Unbuffer current values
|
|
outPtr0 = outPtr1;
|
|
for (idx0 = outMin0; idx0 <= outMax0; ++idx0)
|
|
{
|
|
*outPtr0 = temp[idx0];
|
|
outPtr0 += outInc0;
|
|
}
|
|
|
|
outPtr1 += outInc1;
|
|
}
|
|
outPtr2 += outInc2;
|
|
}
|
|
}
|
|
|
|
free(buff);
|
|
free(temp);
|
|
free(sq);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
void vtkImageEuclideanDistance::AllocateOutputScalars(vtkImageData *outData)
|
|
{
|
|
outData->SetExtent(outData->GetWholeExtent());
|
|
outData->AllocateScalars();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This method is passed input and output Datas, and executes the
|
|
// EuclideanDistance algorithm to fill the output from the input.
|
|
int vtkImageEuclideanDistance::IterativeRequestData(
|
|
vtkInformation* vtkNotUsed( request ),
|
|
vtkInformationVector** inputVector,
|
|
vtkInformationVector* outputVector)
|
|
{
|
|
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
|
|
vtkImageData *inData = vtkImageData::SafeDownCast(
|
|
inInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
vtkImageData *outData = vtkImageData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
this->AllocateOutputScalars(outData);
|
|
|
|
void *inPtr;
|
|
void *outPtr;
|
|
|
|
vtkDebugMacro(<<"Executing image euclidean distance");
|
|
|
|
int outExt[6];
|
|
outData->GetWholeExtent( outExt );
|
|
|
|
inPtr = inData->GetScalarPointerForExtent(
|
|
inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()));
|
|
outPtr = outData->GetScalarPointer();
|
|
|
|
if (!inPtr)
|
|
{
|
|
vtkErrorMacro(<< "Execute: No scalars for update extent.")
|
|
return 1;
|
|
}
|
|
|
|
|
|
// this filter expects that the output be doubles.
|
|
if (outData->GetScalarType() != VTK_DOUBLE)
|
|
{
|
|
vtkErrorMacro(<< "Execute: Output must be be type double.");
|
|
return 1;
|
|
}
|
|
|
|
// this filter expects input to have 1 components
|
|
if (outData->GetNumberOfScalarComponents() != 1 )
|
|
{
|
|
vtkErrorMacro(<< "Execute: Cannot handle more than 1 components");
|
|
return 1;
|
|
}
|
|
|
|
if ( this->GetIteration() == 0 )
|
|
{
|
|
switch (inData->GetScalarType())
|
|
{
|
|
vtkTemplateMacro(
|
|
vtkImageEuclideanDistanceInitialize(this,
|
|
inData, (VTK_TT *)(inPtr),
|
|
outData, outExt,
|
|
(double *)(outPtr) ));
|
|
default:
|
|
vtkErrorMacro(<< "Execute: Unknown ScalarType");
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( inData != outData )
|
|
switch (inData->GetScalarType())
|
|
{
|
|
vtkTemplateMacro(
|
|
vtkImageEuclideanDistanceCopyData(this,
|
|
inData, (VTK_TT *)(inPtr),
|
|
outData, outExt,
|
|
(double *)(outPtr) ));
|
|
}
|
|
}
|
|
|
|
// Call the specific algorithms.
|
|
switch( this->GetAlgorithm() )
|
|
{
|
|
case VTK_EDT_SAITO:
|
|
vtkImageEuclideanDistanceExecuteSaito( this, outData, outExt,
|
|
(double *)(outPtr) );
|
|
break;
|
|
case VTK_EDT_SAITO_CACHED:
|
|
vtkImageEuclideanDistanceExecuteSaitoCached( this, outData, outExt,
|
|
(double *)(outPtr) );
|
|
break;
|
|
default:
|
|
vtkErrorMacro(<< "Execute: Unknown Algorithm");
|
|
}
|
|
|
|
this->UpdateProgress((this->GetIteration()+1.0)/3.0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// For streaming and threads. Splits output update extent into num pieces.
|
|
// This method needs to be called num times. Results must not overlap for
|
|
// consistent starting extent. Subclass can override this method.
|
|
// This method returns the number of peices resulting from a successful split.
|
|
// This can be from 1 to "total".
|
|
// If 1 is returned, the extent cannot be split.
|
|
int vtkImageEuclideanDistance::SplitExtent(int splitExt[6], int startExt[6],
|
|
int num, int total)
|
|
{
|
|
int splitAxis;
|
|
int min, max;
|
|
|
|
vtkDebugMacro("SplitExtent: ( " << startExt[0] << ", " << startExt[1] << ", "
|
|
<< startExt[2] << ", " << startExt[3] << ", "
|
|
<< startExt[4] << ", " << startExt[5] << "), "
|
|
<< num << " of " << total);
|
|
|
|
// start with same extent
|
|
memcpy(splitExt, startExt, 6 * sizeof(int));
|
|
|
|
splitAxis = 2;
|
|
min = startExt[4];
|
|
max = startExt[5];
|
|
while ((splitAxis == this->Iteration) || (min == max))
|
|
{
|
|
splitAxis--;
|
|
if (splitAxis < 0)
|
|
{ // cannot split
|
|
vtkDebugMacro(" Cannot Split");
|
|
return 1;
|
|
}
|
|
min = startExt[splitAxis*2];
|
|
max = startExt[splitAxis*2+1];
|
|
}
|
|
|
|
// determine the actual number of pieces that will be generated
|
|
if ((max - min + 1) < total)
|
|
{
|
|
total = max - min + 1;
|
|
}
|
|
|
|
if (num >= total)
|
|
{
|
|
vtkDebugMacro(" SplitRequest (" << num
|
|
<< ") larger than total: " << total);
|
|
return total;
|
|
}
|
|
|
|
// determine the extent of the piece
|
|
splitExt[splitAxis*2] = min + (max - min + 1)*num/total;
|
|
if (num == total - 1)
|
|
{
|
|
splitExt[splitAxis*2+1] = max;
|
|
}
|
|
else
|
|
{
|
|
splitExt[splitAxis*2+1] = (min-1) + (max - min + 1)*(num+1)/total;
|
|
}
|
|
|
|
vtkDebugMacro(" Split Piece: ( " <<splitExt[0]<< ", " <<splitExt[1]<< ", "
|
|
<< splitExt[2] << ", " << splitExt[3] << ", "
|
|
<< splitExt[4] << ", " << splitExt[5] << ")");
|
|
fflush(stderr);
|
|
|
|
return total;
|
|
}
|
|
|
|
void vtkImageEuclideanDistance::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Initialize: "
|
|
<< (this->Initialize ? "On\n" : "Off\n");
|
|
|
|
os << indent << "Consider Anisotropy: "
|
|
<< (this->ConsiderAnisotropy ? "On\n" : "Off\n");
|
|
|
|
os << indent << "Initialize: " << this->Initialize << "\n";
|
|
os << indent << "Maximum Distance: " << this->MaximumDistance << "\n";
|
|
|
|
os << indent << "Algorithm: ";
|
|
if ( this->Algorithm == VTK_EDT_SAITO )
|
|
{
|
|
os << "Saito\n";
|
|
}
|
|
else
|
|
{
|
|
os << "Saito Cached\n";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|