[Insight-users] Comparing AffineTransform and CenteredAffineTransform

Luis Ibanez luis . ibanez at kitware . com
Tue, 14 Oct 2003 10:55:45 -0400


Hi Gavin,

Thanks for posting your detailed code.

Your usage of the CenteredAffineTransform is correct.

The only detail missing is that after you have set the
center and the rotation, the method "ComputeOffset()"
must be called before using the transform.

The code will look like:

> caffine->SetCenter( centerB  );
> caffine->Rotate( 0, 1, angle );
> caffine->ComputeOffset();

This is a bit missleading here...
we should probably add a comment on the
doxygen documentation.


The CenteredAffineTransform derives from the
AffineTransform. The offset of the base class
should be recomputed in order to take into
account the center of rotation.


Regards,


   Luis


----------------------
Gavin Baker wrote:
> Hello,
> 
> I have been working with the ResampleImageFilter, and got some unexpected
> results with the transforms.  From reading the docs, it seems that
> CenteredAffineTransform is simply an AffineTransform that rotates about the
> specified center point.
> 
> So I wrote a test case (attached) to explore the difference between an
> AffineTransform and a CenteredAffineTransform.  All it is supposed to do is
> rotate the input data about the center of the image.
> 
> The AffineTransform does a:
> 
>   translate( -center )
>   rotate( angle )
>   translate( center )
> 
> While the CenteredAffineTransform does a:
> 
>   set center( center )
>   rotate( angle )
> 
> I would have expected the output to be the same for both.  However the
> output of the CenteredAffineTransform ends up translated off to the side,
> when no translation has been specified (and is not merely size/2).
> 
> Have I missed something here?  Any insights appreciated...
> 
> Thanks,
> 
>   :: Gavin
> 
> 
> 
> ------------------------------------------------------------------------
> 
> 
> #include <itkImage.h>
> #include <itkCastImageFilter.h>
> #include <itkImageFileReader.h>
> #include <itkImageFileWriter.h>
> #include <itkExtractImageFilter.h>
> #include <itkResampleImageFilter.h>
> #include <itkAffineTransform.h>
> #include <itkCenteredAffineTransform.h>
> 
> int main( int argc, char* argv[] )
> {
>     if ( argc < 4 )
>     {
>         std::cerr << "usage: test_centered <in> <out_a> <out_c>" << std::endl;
>         return 1;
>     }
> 
>     // Pixels ______________________________________________________________
> 
>     typedef unsigned short
>         InputPixelType;
> 
>     typedef unsigned short
>         InternalPixelType;
> 
>     typedef unsigned short
>         OutputPixelType;    
> 
>     // Images ______________________________________________________________
> 
>     enum { Dimension = 3 };
> 
>     typedef itk::Image<
>         InputPixelType,
>         Dimension >                             InputImageType;
> 
>     typedef itk::Image<
>         OutputPixelType,
>         Dimension >                             OutputImageType;
> 
>     // Pipeline ____________________________________________________________
> 
>     typedef itk::ImageFileReader<
>         InputImageType >                        ReaderType;
> 
>     typedef itk::ResampleImageFilter<
>         InputImageType,
>         OutputImageType >                       ResampleType;
> 
>     typedef itk::AffineTransform<
>         double,
>         3>                                      AffineType;
> 
>     typedef itk::CenteredAffineTransform<
>         double,
>         3>                                      CenteredAffineType;
> 
>     typedef itk::ImageFileWriter<
>         OutputImageType >                       WriterType;
> 
>     // Construct pipeline __________________________________________________
> 
>     ReaderType::Pointer         _reader     = ReaderType::New();
>     ResampleType::Pointer       _resample_a = ResampleType::New();
>     ResampleType::Pointer       _resample_c = ResampleType::New();
>     AffineType::Pointer         _xform_a    = AffineType::New();
>     CenteredAffineType::Pointer _xform_c    = CenteredAffineType::New();
>     WriterType::Pointer         _writer_a   = WriterType::New();
>     WriterType::Pointer         _writer_c   = WriterType::New();
> 
>     // Connect pipeline ____________________________________________________
> 
>     _reader->SetFileName( argv[1] );
> 
>     _resample_a->SetInput( _reader->GetOutput() );
>     _resample_a->SetTransform( _xform_a );
>     _writer_a->SetInput( _resample_a->GetOutput() );
> 
>     _resample_c->SetInput( _reader->GetOutput() );
>     _resample_c->SetTransform( _xform_c );
>     _writer_c->SetInput( _resample_c->GetOutput() );
> 
>     _writer_a->SetFileName( argv[2] );
>     _writer_c->SetFileName( argv[3] );
> 
>     // Set parameters _______________________________________________________
> 
>     _reader->Update();
> 
>     ResampleType::SizeType in_size =
>         _reader->GetOutput()->GetLargestPossibleRegion().GetSize();
> 
>     std::cout << "Input volume size: " << in_size << std::endl;
> 
>     float rot_angle = 0.7; // radians
> 
>     // Affine ______________________________________________________________
> 
>     AffineType::OutputVectorType center_a;
>     center_a[0] = in_size[0]/2;
>     center_a[1] = in_size[1]/2;
>     center_a[2] = in_size[2]/2;
> 
>     _xform_a->Translate( -center_a );
>     _xform_a->Rotate( 0, 1, rot_angle );
>     _xform_a->Translate( center_a );
> 
>     _resample_a->SetDefaultPixelValue( 86 ); // Get Smart!
>     _resample_a->SetSize(in_size);
> 
>     std::cout << "Center point: " << center_a << std::endl;
> 
>     _xform_a->Print(std::cout);
> 
>     // Centered ____________________________________________________________
> 
>     CenteredAffineType::InputPointType center_c;
>     center_c[0] = center_a[0];
>     center_c[1] = center_a[1];
>     center_c[2] = center_a[2];
> 
>     _xform_c->SetCenter( center_c );
>     _xform_c->Rotate( 0, 1, rot_angle );
> 
>     _resample_c->SetDefaultPixelValue( 86 );
>     _resample_c->SetSize(in_size);
> 
>     _xform_c->Print(std::cout);
> 
>     // Save the output ______________________________________________________
> 
>     try
>     {
>         std::cout << "Saving AffineTransform result..." << std::endl;
>         _writer_a->Update();
> 
>         std::cout << "Saving CenteredAffineTransform result..." << std::endl;
>         _writer_c->Update();
>     }
>     catch( itk::ExceptionObject& excep )
>     {
>         std::cerr
>             << "Exception caught !\n"
>             << excep << std::endl
>             ;
>     }
> 
>     return 0;
> }