[Insight-users] Change in patient orientation after registration
Diego Persano
persano at isi.it
Tue May 29 05:48:48 EDT 2007
Hi all,
I'm trying to registered two MRI images in NifTi format (*.nii) using a
simple translation (the code is below). The metric converges and the final
translation seems to be OK, but the patient orientation of the transformed
image is changed as can be seen printing the image information with the
method image->Print(std::cout):
Fixed image:
(...)
Dimension: 3
Index: [0, 0, 0]
Size: [512, 512, 132]
Spacing: [0.625, 0.625, 1.3]
Origin: [155.785, 162.614, -66.2875]
Direction:
-1 0 0
0 -1 0
0 0 1
(...)
Moving image:
(...)
Dimension: 3
Index: [0, 0, 0]
Size: [512, 512, 132]
Spacing: [0.625, 0.625, 1.3]
Origin: [155.785, 162.614, -66.2875]
Direction:
-1 0 0
0 -1 0
0 0 1
(...)
Transformed image (output of the reg.):
(...)
Dimension: 3
Index: [0, 0, 0]
Size: [512, 512, 132]
Spacing: [0.625, 0.625, 1.3]
Origin: [155.785, 162.614, -66.2875]
Direction:
1 0 0
0 1 0
0 0 1
(...)
Any idea about what is happening?
If you need further information about the images or something else, please
let me know.
Thank you.
Diego
/**** Code ****/
#include "itkImageRegistrationMethod.h"
#include "itkTranslationTransform.h"
#include "itkMattesMutualInformationImageToImageMetric.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkRegularStepGradientDescentOptimizer.h"
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkResampleImageFilter.h"
#include "itkCastImageFilter.h"
//Command observer used to monitor the evolution of the registration
process
#include "itkCommand.h"
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;
}
std::cout << optimizer->GetCurrentIteration() << " ";
std::cout << optimizer->GetValue() << " ";
std::cout << optimizer->GetCurrentPosition() << std::endl;
}
};
int main( int argc, char *argv[] )
{
//Verify the number of required parameters from the command line
if( argc < 4 )
{
std::cerr << "Missing Parameters " << std::endl;
std::cerr << "Usage: " << argv[0];
std::cerr << " fixedImageFile movingImageFile ";
std::cerr << "inputFile outputImagefile" << std::endl;
return 1;
}
//Instantiation of the fixed and moving images
const unsigned int Dimension = 3;
typedef signed short PixelType;
typedef itk::Image< PixelType, Dimension > FixedImageType;
typedef itk::Image< PixelType, Dimension > MovingImageType;
//Components required in the coregistration framework
typedef itk::TranslationTransform< double, Dimension >
TransformType;
typedef itk::RegularStepGradientDescentOptimizer
OptimizerType;
typedef itk::LinearInterpolateImageFunction< MovingImageType, double >
InterpolatorType;
typedef itk::ImageRegistrationMethod< FixedImageType, MovingImageType >
RegistrationType;
typedef itk::MattesMutualInformationImageToImageMetric< FixedImageType,
MovingImageType > MetricType;
//Creation of the coregistration components
TransformType::Pointer transform = TransformType::New();
OptimizerType::Pointer optimizer = OptimizerType::New();
InterpolatorType::Pointer interpolator = InterpolatorType::New();
RegistrationType::Pointer registration = RegistrationType::New();
MetricType::Pointer metric = MetricType::New();
registration->SetOptimizer( optimizer );
registration->SetTransform( transform );
registration->SetInterpolator( interpolator );
registration->SetMetric( metric );
//Read the fixed and moving images
typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
FixedImageReaderType::Pointer fixedImageReader =
FixedImageReaderType::New();
MovingImageReaderType::Pointer movingImageReader =
MovingImageReaderType::New();
fixedImageReader->SetFileName( argv[1] );
movingImageReader->SetFileName( argv[2] );
registration->SetFixedImage( fixedImageReader->GetOutput() );
registration->SetMovingImage( movingImageReader->GetOutput() );
//Read the filter input file
std::cout << std::endl;
std::cout << "Reading filter input " << argv[3] << std::endl;
std::ifstream fin( argv[3] );
if( !fin )
{
std::cout << "Cannot read" << argv[3] << std::endl;
std::cout << std::endl;
return 1;
}
//Read comments
std::string buffer;
getline( fin, buffer );
while( buffer.at( buffer.find_first_not_of(" ") ) == '#' )
{
std::cout << buffer << std::endl;
getline( fin, buffer );
}
//Put back the last read line: it's not any more a comment
fin.seekg( fin.tellg() - std::istream::pos_type(buffer.size() + 1) );
//Select a region of the fixed image as input to the metric computation
//Coordinates of the region
unsigned int startx, starty, startz;
fin >> startx >> starty >> startz;
std::cout << startx << " " << starty << " " << startz << std::endl;
unsigned int sizex, sizey, sizez;
fin >> sizex >> sizey >> sizez;
std::cout << sizex << " " << sizey << " " << sizez << std::endl;
FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();
fixedImageReader->Update();
FixedImageType::IndexType start;
start[0] = startx; // first index on X
start[1] = starty; // first index on Y
start[2] = startz; // first index on Z
FixedImageType::SizeType size;
size[0] = sizex; // size along X
size[1] = sizey; // size along Y
size[2] = sizez; // size along Z
FixedImageType::RegionType fixedRegion;
fixedRegion.SetSize( size );
fixedRegion.SetIndex( start );
// FixedImageType::RegionType fixedRegion =
fixedImage->GetBufferedRegion();
registration->SetFixedImageRegion( fixedRegion );
//Parameters required by the metric
unsigned int numberOfBins;
fin >> numberOfBins;
std::cout << numberOfBins << std::endl;
metric->SetNumberOfHistogramBins( numberOfBins );
float spatialSamples;
fin >> spatialSamples;
std::cout << spatialSamples << std::endl;
const unsigned int numberOfSamples = fixedRegion.GetNumberOfPixels() *
spatialSamples;
metric->SetNumberOfSpatialSamples( numberOfSamples );
//Initial parameters for the transform (x y z) translations
typedef RegistrationType::ParametersType ParametersType;
ParametersType initialParameters( transform->GetNumberOfParameters() );
fin >> initialParameters[0] >> initialParameters[1] >>
initialParameters[2];
std::cout << initialParameters[0] << " " << initialParameters[1] << " "
<< initialParameters[2] << std::endl;
registration->SetInitialTransformParameters( initialParameters );
//Parameters required by the optimizer
float maxStepLength;
fin >> maxStepLength;
std::cout << maxStepLength << std::endl;
optimizer->SetMaximumStepLength( maxStepLength );
float minStepLength;
fin >> minStepLength;
std::cout << minStepLength << std::endl;
optimizer->SetMinimumStepLength( minStepLength );
unsigned int maxNumberOfIterations;
fin >> maxNumberOfIterations;
std::cout << maxNumberOfIterations << std::endl;
optimizer->SetNumberOfIterations( maxNumberOfIterations );
optimizer->SetGradientMagnitudeTolerance( 1e-7 );
//Fix a voxel value for the region outside of the mapping
unsigned int voxelValue;
fin >> voxelValue;
std::cout << voxelValue << std::endl;
PixelType defaultVoxelValue = voxelValue;
fin.close();
std::cout << "Done" << std::endl;
std::cout << std::endl;
//Print size of the fixed image region
FixedImageType::SizeType fixedImageSize = fixedRegion.GetSize();
std::cout << "Size of fixed-image region in voxles: ";
std::cout << fixedImageSize[0] << " x " << fixedImageSize[1] << " x " <<
fixedImageSize[2] << std::endl;
std::cout << std::endl;
std::cout << "Starting Registration" << std::endl;
//Create the Command observer and register it with the optimizer
CommandIterationUpdate::Pointer observer =
CommandIterationUpdate::New();
optimizer->AddObserver( itk::IterationEvent(), observer );
//Trigger the coregistration process
try
{
registration->StartRegistration();
}
catch( itk::ExceptionObject & err )
{
std::cout << "ExceptionObject caught !" << std::endl;
std::cout << err << std::endl;
return -1;
}
//Get the last values of the coregistration process
ParametersType finalParameters =
registration->GetLastTransformParameters();
double TranslationAlongX = finalParameters[0];
double TranslationAlongY = finalParameters[1];
double TranslationAlongZ = finalParameters[2];
unsigned int numberOfIterations = optimizer->GetCurrentIteration();
double bestValue = optimizer->GetValue();
//Print out results
std::cout << std::endl;
std::cout << "Result = " << std::endl;
std::cout << " Translation X = " << TranslationAlongX << std::endl;
std::cout << " Translation Y = " << TranslationAlongY << std::endl;
std::cout << " Translation Z = " << TranslationAlongZ << std::endl;
std::cout << " Iterations = " << numberOfIterations << std::endl;
std::cout << " Metric value = " << bestValue << std::endl;
std::cout << " Stop Condition = " << optimizer->GetStopCondition() <<
std::endl;
//Re-sampling of the moving image using the resulting transform
typedef itk::ResampleImageFilter< MovingImageType, FixedImageType >
ResampleFilterType;
TransformType::Pointer finalTransform = TransformType::New();
finalTransform->SetParameters( finalParameters );
ResampleFilterType::Pointer resample = ResampleFilterType::New();
//Parameters required by the re-sampling filter
resample->SetTransform( finalTransform );
resample->SetInput( movingImageReader->GetOutput() );
resample->SetSize(
fixedImage->GetLargestPossibleRegion().GetSize() );
resample->SetOutputOrigin( fixedImage->GetOrigin() );
resample->SetOutputSpacing( fixedImage->GetSpacing() );
resample->SetDefaultPixelValue( defaultVoxelValue );
//Instantiation of the output image and the cast and writer filter
typedef signed short OutputPixelType;
typedef itk::Image< OutputPixelType, Dimension >
OutputImageType;
typedef itk::CastImageFilter< FixedImageType, OutputImageType >
CastFilterType;
typedef itk::ImageFileWriter< OutputImageType >
WriterType;
WriterType::Pointer writer = WriterType::New();
CastFilterType::Pointer caster = CastFilterType::New();
//Write output image file
std::cout << std::endl;
std::cout << "Writing output image " << argv[4] << std::endl;
writer->SetFileName( argv[4] );
caster->SetInput( resample->GetOutput() );
writer->SetInput( caster->GetOutput() );
writer->Update();
std::cout << "Done" << std::endl;
return 0;
}
More information about the Insight-users
mailing list