[Insight-users] pointset to image registration exception
Dean Inglis
dean.inglis at camris.ca
Mon Sep 5 12:27:40 EDT 2011
my current pipeline is hopefully set up to register a set of 3D surface
points
obtained from a motion tracking/probing system to a 3D CT scan.
I am using an inverted gradient magnitude of the CT scan as the moving
image and setting the values associated with the points to be a constant:
the mean of the inverted gradient magnitude image + a factor * the std dev.
I need the transformation to allow for rotation, translation and (assuming
isotropic) scaling so I am using the Similarity3DTransform class.
With the code below I am getting an exception error that I dont know how
to resolve:
itk::ExceptionObject (00C7FACC)
Location: "class itk::CovariantVector<double,3> *__thiscall
itk::ImportImageCont
ainer<unsigned long,class itk::CovariantVector<double,3>
>::AllocateElements(uns
igned long) const"
File:
d:\developer\vs10\x86\static\install\include\insighttoolkit-4.0\itkImportI
mageContainer.txx
Line: 191
Description: Failed to allocate memory for image.
ITK is built statically, visual studio 2010, nmake, release, cmake 2.8.4 on
Win 7.
Dean
#include "itkPointSetToImageRegistrationMethod.h"
#include "itkPointSet.h"
#include <iostream>
#include <fstream>
#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkIntensityWindowingImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkMinimumMaximumImageCalculator.h"
#include "itkStatisticsImageFilter.h"
#include "itkSimilarity3DTransform.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkPointSetToImageRegistrationMethod.h"
#include "itkVersorRigid3DTransformOptimizer.h"
#include "itkNormalizedCorrelationPointSetToImageMetric.h"
//#include "itkCommandIterationUpdate.h"
//
// Observer to the optimizer
//
class CommandIterationUpdate : public itk::Command
{
public:
typedef CommandIterationUpdate Self;
typedef itk::Command Superclass;
typedef itk::SmartPointer<Self> Pointer;
itkNewMacro( Self );
protected:
CommandIterationUpdate() {};
public:
typedef itk::RegularStepGradientDescentOptimizer OptimizerType;
typedef const OptimizerType * OptimizerPointer;
void Execute(itk::Object *caller, const itk::EventObject & event)
{
Execute( (const itk::Object *)caller, event);
}
void Execute(const itk::Object * object, const itk::EventObject & event)
{
OptimizerPointer optimizer =
dynamic_cast< OptimizerPointer >( object );
if( typeid( event ) != typeid( itk::IterationEvent ) )
{
return;
}
OptimizerType::DerivativeType gradient = optimizer->GetGradient();
OptimizerType::ScalesType scales = optimizer->GetScales();
double magnitude2 = 0.0;
for(unsigned int i=0; i<gradient.size(); i++)
{
const double fc = gradient[i] / scales[i];
magnitude2 += fc * fc;
}
const double gradientMagnitude = vcl_sqrt( magnitude2 );
std::cout << optimizer->GetCurrentIteration() << " ";
std::cout << optimizer->GetValue() << " ";
std::cout << gradientMagnitude << " ";
std::cout << optimizer->GetCurrentPosition() << std::endl;
}
};
int main( int argc, char * argv[] )
{
// define the object that will hold the 3D probe points
const unsigned int Dimension = 3;
typedef unsigned char FixedPointDataType;
// associate a default value with each point
// we will use an inverted gradient magnitude image to register the
// points to, so it should be a low salar value
// for example, if the gradient magnitude image (GMI) background is zero,
// then the inverted GMI will have a high value
FixedPointDataType defaultValue = 0;
typedef itk::PointSet< FixedPointDataType, Dimension > FixedPointSetType;
FixedPointSetType::Pointer fixedPointSet = FixedPointSetType::New();
typedef FixedPointSetType::PointsContainer FixedPointsContainer;
FixedPointsContainer::Pointer fixedPointContainer =
FixedPointsContainer::New();
typedef FixedPointSetType::PointType FixedPointType;
FixedPointType fixedPoint;
// Read the file containing coordinates of fixed points.
std::ifstream fixedFile;
fixedFile.open( argv[1] );
if( fixedFile.fail() )
{
std::cerr << "Error opening points file with name : " << std::endl;
std::cerr << argv[1] << std::endl;
return EXIT_FAILURE;
}
unsigned int pointId = 0;
fixedFile >> fixedPoint;
while( !fixedFile.eof() )
{
fixedPointContainer->InsertElement( pointId, fixedPoint );
fixedFile >> fixedPoint;
std::cout << "point " << pointId << ": " << fixedPoint[0] << ", " <<
fixedPoint[1] << ", " << fixedPoint[2] << std::endl;
pointId++;
}
fixedPointSet->SetPoints( fixedPointContainer );
std::cout << "number of fixed Points = " <<
fixedPointSet->GetNumberOfPoints() << std::endl;
// read in the original dicom image
std::string inputFileName = argv[2];
// Setup image types
typedef itk::Image< float, 3 > FloatImageType;
typedef itk::Image< unsigned short, 3 > UnsignedShortImageType;
typedef itk::Image< unsigned char, 3 > UnsignedCharImageType;
// image reader
typedef itk::ImageFileReader< UnsignedShortImageType > ImageReaderType;
ImageReaderType::Pointer reader = ImageReaderType::New();
reader->SetFileName( inputFileName );
reader->Update();
std::cout << "read image " << inputFileName << std::endl;
// gradient magnitude
typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<
UnsignedShortImageType, FloatImageType > GradientFilterType;
GradientFilterType::Pointer gradientFilter = GradientFilterType::New();
gradientFilter->SetInput( reader->GetOutput() );
gradientFilter->SetSigma( 1.0 );
gradientFilter->Update();
std::cout << "grad mag calculated " << std::endl;
typedef itk::MinimumMaximumImageCalculator< FloatImageType >
CalculatorType;
CalculatorType::Pointer calculator = CalculatorType::New();
calculator->SetImage( gradientFilter->GetOutput() );
calculator->ComputeMaximum();
float maximum = calculator->GetMaximum();
std::cout << "max grad mag calculated " << maximum << std::endl;
// rescale the intensities
typedef itk::IntensityWindowingImageFilter< FloatImageType, FloatImageType
> IntensityFilterType;
IntensityFilterType::Pointer intensityFilter = IntensityFilterType::New();
intensityFilter->SetInput( gradientFilter->GetOutput() );
intensityFilter->SetWindowMinimum( 0 );
intensityFilter->SetWindowMaximum( maximum );
intensityFilter->SetOutputMinimum( 255 );
intensityFilter->SetOutputMaximum( 0 );
intensityFilter->Update();
std::cout << "intensity inversion and rescaling calculated " << std::endl;
// cast to unsigned char
typedef itk::CastImageFilter< FloatImageType, UnsignedCharImageType >
CastFilterType;
CastFilterType::Pointer castFilter = CastFilterType::New();
castFilter->SetInput( intensityFilter->GetOutput() );
castFilter->Update();
std::cout << "cast to uchar calculated " << std::endl;
// write the image out
typedef itk::ImageFileWriter< UnsignedCharImageType > ImageWriterType;
ImageWriterType::Pointer writer = ImageWriterType::New();
writer->SetFileName( "testout2.mhd" );
writer->SetInput( castFilter->GetOutput() );
writer->Update();
typedef itk::StatisticsImageFilter< UnsignedCharImageType >
StatisticsImageFilterType;
StatisticsImageFilterType::Pointer statisticsImageFilter
= StatisticsImageFilterType::New ();
statisticsImageFilter->SetInput( castFilter->GetOutput() );
statisticsImageFilter->Update();
std::cout << "Mean: " << statisticsImageFilter->GetMean() << std::endl;
std::cout << "Std.: " << statisticsImageFilter->GetSigma() << std::endl;
// set the values associated with the points to be a factor of the stdev +
mean of the cast output
float defaultScaleFactor = 0.0;
defaultValue = static_cast< FixedPointDataType >( defaultScaleFactor *
statisticsImageFilter->GetSigma() + statisticsImageFilter->GetMean() );
std::cout << "default fixed point value: " << static_cast<int>(
defaultValue )
<< " scale: " << defaultScaleFactor
<< " cast mean: " << statisticsImageFilter->GetMean()
<< " cast stddev: " << statisticsImageFilter->GetSigma()
<< std::endl;
for(int i = 0 ; i < fixedPointSet->GetNumberOfPoints(); ++i )
{
fixedPointSet->SetPointData( i, defaultValue );
}
//-----------------------------------------------------------
// Set up a Transform - does rotation (using versors), translation and
isotropic scaling
// for anisotropic scaling use itkScaleVersor3DTransform
//-----------------------------------------------------------
typedef double CoordinateRepresentationType;
typedef itk::Similarity3DTransform< CoordinateRepresentationType >
TransformType;
TransformType::Pointer transform = TransformType::New();
// Start from an Identity transform (in a normal case, the user
// can probably provide a better guess than the identity...
transform->SetIdentity();
//-----------------------------------------------------------
// Set up Metric (also known as a cost function)
// must inherit from itkPointSetToImageMetric
// other options are:
// itkMeanReciprocalSquareDifferencePointSetToImageMetric
// itkMeanSquaresPointSetToImageMetric
// itkNormalizedCorrelationPointSetToImageMetric
//-----------------------------------------------------------
typedef itk::NormalizedCorrelationPointSetToImageMetric<
FixedPointSetType, UnsignedCharImageType > MetricType;
MetricType::Pointer metric = MetricType::New();
typedef MetricType::TransformType TransformBaseType;
typedef TransformBaseType::ParametersType ParametersType;
//------------------------------------------------------------
// Set up transform parameters
//------------------------------------------------------------
ParametersType parameters( transform->GetNumberOfParameters() );
// initialize the offset/vector part
for( unsigned int k = 0; k <Dimension; k++ )
{
parameters[k]= 0.0f;
}
//------------------------------------------------------------
// Set up an Interpolator
//------------------------------------------------------------
typedef itk::LinearInterpolateImageFunction< UnsignedCharImageType,
CoordinateRepresentationType > InterpolatorType;
InterpolatorType::Pointer interpolator = InterpolatorType::New();
//------------------------------------------------------------
//------------------------------------------------------------
// Optimizer Type
//------------------------------------------------------------
typedef itk::VersorRigid3DTransformOptimizer OptimizerType;
OptimizerType::Pointer optimizer = OptimizerType::New();
unsigned long numberOfIterations = 50;
//double translationScale = 1.0; // not used
double maximumStepLenght = 1.0; // no step will be larger than
this
double minimumStepLenght = 0.01; // convergence criterion
double gradientTolerance = 1e-6; // convergence criterion
// Scale the translation components of the Transform in the Optimizer
//OptimizerType::ScalesType scales( transform->GetNumberOfParameters() );
//scales.Fill( 1.0 );
//optimizer->SetScales( scales );
optimizer->SetNumberOfIterations( numberOfIterations );
optimizer->SetMinimumStepLength( minimumStepLenght );
optimizer->SetMaximumStepLength( maximumStepLenght );
optimizer->SetGradientMagnitudeTolerance( gradientTolerance );
optimizer->MinimizeOn();
typedef CommandIterationUpdate IterationObserverType;
IterationObserverType::Pointer iterationObserver;
//optimizer->AddObserver( itk::IterationEvent(), iterationObserver );
//------------------------------------------------------------
// registration method
//------------------------------------------------------------
typedef itk::PointSetToImageRegistrationMethod< FixedPointSetType,
UnsignedCharImageType > RegistrationType;
RegistrationType::Pointer registration = RegistrationType::New();
//------------------------------------------------------
// Connect all the components required for Registration
//------------------------------------------------------
registration->SetMetric( metric );
registration->SetOptimizer( optimizer );
registration->SetTransform( transform );
registration->SetFixedPointSet( fixedPointSet );
registration->SetMovingImage( castFilter->GetOutput() );
registration->SetInterpolator( interpolator );
try
{
registration->StartRegistration();
}
catch( itk::ExceptionObject & e )
{
std::cout << e << std::endl;
return EXIT_FAILURE;
}
std::cout << "output written " << std::endl;
return EXIT_SUCCESS;
}
More information about the Insight-users
mailing list