Hello all,<br><br>As a further test of the modified VersorRigid3DTransform has given confusing results...<br><br>I modified my pre-deformation image-stack by rotating (around one axis) and translating it by defined parameters (nothing very large, and completely rigid), and used the transformed image as the &quot;MovingImage&quot;.<br>
<br>The program was able to compute the translation fairly accurately, but the rotation matrix still came out as a singularity with the versor indicating no rotation. AND the output image was filled with pixelValue = 0.<br>
<br>The images I am using are in the analyze format (.hdr and image file), 16-bit unsigned pixel type, 48 images/stack, 256x256 image resolution.<br><br>I&#39;ve pasted the modified program code before (sorry for the length) - any endeavors to tease out solutions are most welcome!<br>
<br>Thanks,<br><br>Tim Bhatnagar<br><br>#if defined(_MSC_VER)<br>#pragma warning ( disable : 4786 )<br>#endif<br><br>//  Software Guide : BeginCommandLineArgs<br>//    INPUTS: {brainweb1e1a10f20.mha}<br>//    INPUTS: {brainweb1e1a10f20Rot10Tx15.mha}<br>
//    ImageRegistration8Output.mhd<br>//    ImageRegistration8DifferenceBefore.mhd<br>//    ImageRegistration8DifferenceAfter.mhd<br>//    OUTPUTS: {ImageRegistration8Output.png}<br>//    OUTPUTS: {ImageRegistration8DifferenceBefore.png}<br>
//    OUTPUTS: {ImageRegistration8DifferenceAfter.png}<br>//  Software Guide : EndCommandLineArgs<br><br>// Software Guide : BeginLatex<br>//<br>// This example illustrates the use of the \doxygen{VersorRigid3DTransform}<br>
// class for performing registration of two $3D$ images. The example code is<br>// for the most part identical to the code presented in<br>// Section~\ref{sec:RigidRegistrationIn2D}.  The major difference is that this<br>
// example is done in $3D$. The class \doxygen{CenteredTransformInitializer} is<br>// used to initialize the center and translation of the transform.  The case of<br>// rigid registration of 3D images is probably one of the most commonly found<br>
// cases of image registration.<br>//<br>//<br>// \index{itk::VersorRigid3DTransform}<br>// \index{itk::CenteredTransformInitializer!In 3D}<br>//<br>//<br>// Software Guide : EndLatex <br><br>#include &quot;itkImageRegistrationMethod.h&quot;<br>
<br>#include &quot;itkMeanSquaresImageToImageMetric.h&quot;<br>#include &quot;itkMattesMutualInformationImageToImageMetric.h&quot;<br>#include &quot;itkGradientDifferenceImageToImageMetric.h&quot;<br><br>#include &quot;itkLinearInterpolateImageFunction.h&quot;<br>
#include &quot;itkBSplineInterpolateImageFunction.h&quot;<br><br>#include &quot;itkImage.h&quot;<br><br><br>#include &quot;itkVersorRigid3DTransform.h&quot;<br>#include &quot;itkCenteredTransformInitializer.h&quot;<br><br>
<br>//  Software Guide : BeginLatex<br>//  <br>//  The parameter space of the \code{VersorRigid3DTransform} is not a vector<br>//  space, due to the fact that addition is not a closed operation in the space<br>//  of versor components. This precludes the use of standard gradient descent<br>
//  algorithms for optimizing the parameter space of this transform. A special<br>//  optimizer should be used in this registration configuration. The optimizer<br>//  designed for this transform is the<br>//  \doxygen{VersorRigid3DTransformOptimizer}. This optimizer uses Versor<br>
//  composition for updating the first three components of the parameters<br>//  array, and Vector addition for updating the last three components of the<br>//  parameters array~\cite{Hamilton1866,Joly1905}.<br>//<br>//  \index{itk::VersorRigid3DTransformOptimizer!header}<br>
// <br>//  Software Guide : EndLatex <br><br>// Software Guide : BeginCodeSnippet<br>#include &quot;itkVersorRigid3DTransformOptimizer.h&quot;<br>// Software Guide : EndCodeSnippet<br><br>#include &quot;itkImageFileReader.h&quot;<br>
#include &quot;itkImageFileWriter.h&quot;<br><br>#include &quot;itkResampleImageFilter.h&quot;<br>#include &quot;itkCastImageFilter.h&quot;<br>#include &quot;itkSubtractImageFilter.h&quot;<br>#include &quot;itkRescaleIntensityImageFilter.h&quot;<br>
#include &quot;itkExtractImageFilter.h&quot;<br><br>#include &quot;itkCommand.h&quot;<br>class CommandIterationUpdate : public itk::Command <br>{<br>public:<br>  typedef  CommandIterationUpdate   Self;<br>  typedef  itk::Command             Superclass;<br>
  typedef itk::SmartPointer&lt;Self&gt;  Pointer;<br>  itkNewMacro( Self );<br>protected:<br>  CommandIterationUpdate() {};<br>public:<br>  typedef itk::VersorRigid3DTransformOptimizer     OptimizerType;<br>  typedef   const OptimizerType   *    OptimizerPointer;<br>
<br>  void Execute(itk::Object *caller, const itk::EventObject &amp; event)<br>    {<br>      Execute( (const itk::Object *)caller, event);<br>    }<br><br>  void Execute(const itk::Object * object, const itk::EventObject &amp; event)<br>
    {<br>      OptimizerPointer optimizer = <br>        dynamic_cast&lt; OptimizerPointer &gt;( object );<br>      if( ! itk::IterationEvent().CheckEvent( &amp;event ) )<br>        {<br>        return;<br>        }<br>      std::cout &lt;&lt; optimizer-&gt;GetCurrentIteration() &lt;&lt; &quot;   &quot;;<br>
      std::cout &lt;&lt; optimizer-&gt;GetValue() &lt;&lt; &quot;   &quot;;<br>      std::cout &lt;&lt; optimizer-&gt;GetCurrentPosition() &lt;&lt; std::endl;<br>    }<br>};<br><br><br>int main( int argc, char *argv[] )<br>
{<br>  if( argc &lt; 5 )<br>    {<br>    std::cerr &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; &quot;Missing Parameters &quot; &lt;&lt; std::endl;<br>    std::cerr &lt;&lt; &quot;Usage: &quot; &lt;&lt; argv[0];<br>    std::cerr &lt;&lt; &quot; fixedImageFile  movingImageFile &quot;;<br>
    std::cerr &lt;&lt; &quot; outputImagefile translationInTextFileFormat &quot;;<br>    std::cerr &lt;&lt; &quot; [differenceBeforeRegistration] [differenceAfterRegistration] &quot;;<br>    std::cerr &lt;&lt; &quot; [step length] &quot;&lt;&lt; std::endl;<br>
    std::cerr &lt;&lt; std::endl;<br>    return 1;<br>    }<br>  <br>  const    unsigned int    Dimension = 3;<br>  typedef  float           PixelType;<br><br>  typedef itk::Image&lt; PixelType, Dimension &gt;  FixedImageType;<br>
  typedef itk::Image&lt; PixelType, Dimension &gt;  MovingImageType;<br><br><br>  // Software Guide : BeginCodeSnippet<br>  typedef itk::VersorRigid3DTransform&lt; double &gt; TransformType;<br>  // Software Guide : EndCodeSnippet<br>
<br><br><br>  typedef itk::VersorRigid3DTransformOptimizer           OptimizerType;<br><br>  /*<br>  MeanSquaresImageToImageMetric<br>  MattesMutualInformationImageToImageMetric<br>  GradientDifferenceImageToImageMetric<br>
  */<br>  typedef itk::MattesMutualInformationImageToImageMetric&lt; <br>                                          FixedImageType, <br>                                          MovingImageType &gt;    MetricType;<br><br>  /*<br>
  LinearInterpolateImageFunction<br>  BSplineInterpolateImageFunction<br>  */<br>  typedef itk::LinearInterpolateImageFunction&lt; <br>                                    MovingImageType,<br>                                    double          &gt;    InterpolatorType;<br>
<br><br>  typedef itk::ImageRegistrationMethod&lt; <br>                                    FixedImageType, <br>                                    MovingImageType &gt;    RegistrationType;<br><br>  MetricType::Pointer         metric        = MetricType::New();<br>
  OptimizerType::Pointer      optimizer     = OptimizerType::New();<br>  InterpolatorType::Pointer   interpolator  = InterpolatorType::New();<br>  RegistrationType::Pointer   registration  = RegistrationType::New();<br>  <br>
<br>  registration-&gt;SetMetric(        metric        );<br>  registration-&gt;SetOptimizer(     optimizer     );<br>  registration-&gt;SetInterpolator(  interpolator  );<br><br><br>  // Software Guide : BeginCodeSnippet<br>
  TransformType::Pointer  transform = TransformType::New();<br>  registration-&gt;SetTransform( transform );<br>  // Software Guide : EndCodeSnippet<br><br>  typedef itk::ImageFileReader&lt; FixedImageType  &gt; FixedImageReaderType;<br>
  typedef itk::ImageFileReader&lt; MovingImageType &gt; MovingImageReaderType;<br><br>  FixedImageReaderType::Pointer  fixedImageReader  = FixedImageReaderType::New();<br>  MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();<br>
<br>  fixedImageReader-&gt;SetFileName(  argv[1] );<br>  movingImageReader-&gt;SetFileName( argv[2] );<br><br>  // ************************************************************************************************************<br>
<br>  // MattesMutualInformationImageToImageMetric<br>  metric-&gt;UseAllPixelsOn();<br>  //metric-&gt;SetNumberOfSpatialSamples( 100000 ); // default 100000<br>  // This is the number of image samples used to calculate the joint probability distribution. The number<br>
  //   of spatial samples is clamped to be a minimum of 1. Default value is 50.<br>  metric-&gt;ComputeGradientOn(); // If true, gradient value is computed.  Default value is true.<br>  // Select whether the metric will be computed using all the pixels on the fixed image region, or only<br>
  //   using a set of randomly selected pixels.<br>  metric-&gt;SetNumberOfHistogramBins( 50 ); // Number of bins to used in the histogram. Typical value is 50.<br><br>  // GradientDifferenceImageToImageMetric<br>  //metric-&gt;ComputeGradientOn(); // If true, gradient value is computed.  Default value is true.<br>
<br>  //interpolator-&gt;SetSplineOrder( 3 ); // default (if not specified) is 3<br>  // ************************************************************************************************************<br><br>  registration-&gt;SetFixedImage(    fixedImageReader-&gt;GetOutput()    );<br>
  registration-&gt;SetMovingImage(   movingImageReader-&gt;GetOutput()   );<br>  fixedImageReader-&gt;Update();<br><br>  registration-&gt;SetFixedImageRegion( <br>     fixedImageReader-&gt;GetOutput()-&gt;GetBufferedRegion() );<br>
<br><br>  // Software Guide : BeginCodeSnippet<br>  typedef itk::CenteredTransformInitializer&lt; TransformType, <br>                                             FixedImageType, <br>                                             MovingImageType <br>
                                                 &gt;  TransformInitializerType;<br><br>  TransformInitializerType::Pointer initializer = <br>                                          TransformInitializerType::New();<br>  // Software Guide : EndCodeSnippet<br>
<br><br><br>  // Software Guide : BeginCodeSnippet<br>  initializer-&gt;SetTransform(   transform );<br>  initializer-&gt;SetFixedImage(  fixedImageReader-&gt;GetOutput() );<br>  initializer-&gt;SetMovingImage( movingImageReader-&gt;GetOutput() );<br>
  // Software Guide : EndCodeSnippet<br><br><br>  // Software Guide : BeginCodeSnippet<br>  initializer-&gt;MomentsOn();<br>  // Software Guide : EndCodeSnippet<br><br><br>  // Software Guide : BeginCodeSnippet<br>  initializer-&gt;InitializeTransform();<br>
  // Software Guide : EndCodeSnippet<br><br>  // Software Guide : BeginCodeSnippet<br>  typedef TransformType::VersorType  VersorType;<br>  typedef VersorType::VectorType     VectorType;<br><br>  VersorType     rotation;<br>
  VectorType     axis;<br>  <br>  axis[0] = 0.0;<br>  axis[1] = 0.0;<br>  axis[2] = 0.1;<br><br>  const double angle = 0;<br><br>  rotation.Set(  axis, angle  );<br><br>  transform-&gt;SetRotation( rotation );<br><br>  // Software Guide : EndCodeSnippet<br>
<br><br>  //  Software Guide : BeginLatex<br>  //  <br>  //  We now pass the parameters of the current transform as the initial<br>  //  parameters to be used when the registration process starts. <br>  //<br>  //  Software Guide : EndLatex <br>
<br>  // Software Guide : BeginCodeSnippet<br>  registration-&gt;SetInitialTransformParameters( transform-&gt;GetParameters() );<br>  // Software Guide : EndCodeSnippet<br><br>  typedef OptimizerType::ScalesType       OptimizerScalesType;<br>
  OptimizerScalesType optimizerScales( transform-&gt;GetNumberOfParameters() );<br>  const double translationScale = 1.0 / 100000.0;<br><br>  optimizerScales[0] = 505;<br>  optimizerScales[1] = 505;<br>  optimizerScales[2] = 505;<br>
  optimizerScales[3] = translationScale;<br>  optimizerScales[4] = translationScale;<br>  optimizerScales[5] = translationScale;<br><br>  optimizer-&gt;SetScales( optimizerScales );<br><br>  double steplength = 0.1; // 0.35 -&gt; 0.1 ------------------------------------------------------------------<br>
<br>  if( argc &gt; 7 )<br>    {<br>    steplength = atof( argv[7] );<br>    }<br><br>  optimizer-&gt;SetMaximumStepLength( steplength  ); <br>  optimizer-&gt;SetMinimumStepLength( 0.0001 );<br><br>  double iteration_number= 300; // ------------------------------------------------------------------------<br>
<br>  if( argc &gt; 8 )<br>    {<br>    iteration_number= atof( argv[8] );<br>    }<br><br><br><br>  optimizer-&gt;SetNumberOfIterations( iteration_number);<br><br><br>  // Create the Command observer and register it with the optimizer.<br>
  //<br>  CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();<br>  optimizer-&gt;AddObserver( itk::IterationEvent(), observer );<br><br><br>  try <br>    {<br>    registration-&gt;StartRegistration();<br>
    } <br>  catch( itk::ExceptionObject &amp; err ) <br>    { <br>    std::cerr &lt;&lt; &quot;ExceptionObject caught !&quot; &lt;&lt; std::endl; <br>    std::cerr &lt;&lt; err &lt;&lt; std::endl; <br>    return -1;<br>    } <br>
  <br>  OptimizerType::ParametersType finalParameters = <br>                    registration-&gt;GetLastTransformParameters();<br><br><br>  const double versorX              = finalParameters[0];<br>  const double versorY              = finalParameters[1];<br>
  const double versorZ              = finalParameters[2];<br>  const double finalTranslationX    = finalParameters[3];<br>  const double finalTranslationY    = finalParameters[4];<br>  const double finalTranslationZ    = finalParameters[5];<br>
  const unsigned int numberOfIterations = optimizer-&gt;GetCurrentIteration();<br>  const double bestValue = optimizer-&gt;GetValue();<br><br>  // Print out results<br>  //<br>  std::cout &lt;&lt; std::endl &lt;&lt; std::endl;<br>
  std::cout &lt;&lt; &quot;Result = &quot; &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; versor X      = &quot; &lt;&lt; versorX  &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; versor Y      = &quot; &lt;&lt; versorY  &lt;&lt; std::endl;<br>
  std::cout &lt;&lt; &quot; versor Z      = &quot; &lt;&lt; versorZ  &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; Translation X = &quot; &lt;&lt; finalTranslationX  &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; Translation Y = &quot; &lt;&lt; finalTranslationY  &lt;&lt; std::endl;<br>
  std::cout &lt;&lt; &quot; Translation Z = &quot; &lt;&lt; finalTranslationZ  &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; Iterations    = &quot; &lt;&lt; numberOfIterations &lt;&lt; std::endl;<br>  std::cout &lt;&lt; &quot; Metric value  = &quot; &lt;&lt; bestValue          &lt;&lt; std::endl;<br>
<br>  // ------------------------------------------------------------------------------------------------<br>  std::ofstream translationFile (argv[4]); // set translation text file<br>  translationFile &lt;&lt; finalTranslationX &lt;&lt; &quot; &quot; &lt;&lt; finalTranslationY &lt;&lt; &quot; &quot; &lt;&lt; finalTranslationZ &lt;&lt; &quot;\n&quot;;<br>
  translationFile.close(); // close translation text file<br>  // ------------------------------------------------------------------------------------------------<br><br>  // Software Guide : BeginCodeSnippet<br>  transform-&gt;SetParameters( finalParameters );<br>
<br>  TransformType::MatrixType matrix = transform-&gt;GetRotationMatrix();<br>  TransformType::OffsetType offset = transform-&gt;GetOffset();<br><br>  std::cout &lt;&lt; &quot;Matrix = &quot; &lt;&lt; std::endl &lt;&lt; matrix &lt;&lt; std::endl;<br>
  std::cout &lt;&lt; &quot;Offset = &quot; &lt;&lt; std::endl &lt;&lt; offset &lt;&lt; std::endl;<br>  // Software Guide : EndCodeSnippet<br><br><br>  typedef itk::ResampleImageFilter&lt; <br>                            MovingImageType, <br>
                            FixedImageType &gt;    ResampleFilterType;<br><br>  TransformType::Pointer finalTransform = TransformType::New();<br><br>  finalTransform-&gt;SetCenter( transform-&gt;GetCenter() );<br><br>  finalTransform-&gt;SetParameters( finalParameters );<br>
<br>  ResampleFilterType::Pointer resampler = ResampleFilterType::New();<br><br>  resampler-&gt;SetTransform( finalTransform );<br>  resampler-&gt;SetInput( movingImageReader-&gt;GetOutput() );<br><br>  FixedImageType::Pointer fixedImage = fixedImageReader-&gt;GetOutput();<br>
<br>  resampler-&gt;SetSize(    fixedImage-&gt;GetLargestPossibleRegion().GetSize() );<br>  resampler-&gt;SetOutputOrigin(  fixedImage-&gt;GetOrigin() );<br>  resampler-&gt;SetOutputSpacing( fixedImage-&gt;GetSpacing() );<br>
  resampler-&gt;SetDefaultPixelValue( 0 );<br>  <br>  typedef  float  OutputPixelType;<br><br>  typedef itk::Image&lt; OutputPixelType, Dimension &gt; OutputImageType;<br>  <br>  typedef itk::CastImageFilter&lt; <br>                        FixedImageType,<br>
                        OutputImageType &gt; CastFilterType;<br>                    <br>  typedef itk::ImageFileWriter&lt; OutputImageType &gt;  WriterType;<br><br><br>  WriterType::Pointer      writer =  WriterType::New();<br>
  CastFilterType::Pointer  caster =  CastFilterType::New();<br><br><br>  writer-&gt;SetFileName( argv[3] );<br><br><br>  caster-&gt;SetInput( resampler-&gt;GetOutput() );<br>  writer-&gt;SetInput( caster-&gt;GetOutput()   );<br>
  writer-&gt;Update();<br><br><br>  typedef itk::SubtractImageFilter&lt; <br>                                  FixedImageType, <br>                                  FixedImageType, <br>                                  FixedImageType &gt; DifferenceFilterType;<br>
<br>  DifferenceFilterType::Pointer difference = DifferenceFilterType::New();<br><br><br>  typedef itk::RescaleIntensityImageFilter&lt; <br>                                  FixedImageType, <br>                                  OutputImageType &gt;   RescalerType;<br>
<br>  RescalerType::Pointer intensityRescaler = RescalerType::New();<br>  <br>  intensityRescaler-&gt;SetInput( difference-&gt;GetOutput() );<br>  intensityRescaler-&gt;SetOutputMinimum(   0 );<br>  intensityRescaler-&gt;SetOutputMaximum( 255 );<br>
<br>  difference-&gt;SetInput1( fixedImageReader-&gt;GetOutput() );<br>  difference-&gt;SetInput2( resampler-&gt;GetOutput() );<br><br>  resampler-&gt;SetDefaultPixelValue( 0 );<br><br>  WriterType::Pointer writer2 = WriterType::New();<br>
  writer2-&gt;SetInput( intensityRescaler-&gt;GetOutput() );  <br>  <br><br>  // Compute the difference image between the <br>  // fixed and resampled moving image.<br>  if( argc &gt; 6 )<br>    {<br>    writer2-&gt;SetFileName( argv[6] );<br>
    writer2-&gt;Update();<br>    }<br><br><br>  typedef itk::IdentityTransform&lt; double, Dimension &gt; IdentityTransformType;<br>  IdentityTransformType::Pointer identity = IdentityTransformType::New();<br><br>  // Compute the difference image between the <br>
  // fixed and moving image before registration.<br>  if( argc &gt; 5 )<br>    {<br>    resampler-&gt;SetTransform( identity );<br>    writer2-&gt;SetFileName( argv[5] );<br>    writer2-&gt;Update();<br>    }<br><br>  return 0;<br>
}<br><br><div class="gmail_quote">On Wed, Mar 23, 2011 at 8:10 PM, Tim Bhatnagar <span dir="ltr">&lt;<a href="mailto:tim.bhatnagar@gmail.com">tim.bhatnagar@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hello all,<br><br>I am using a somewhat modified (and I&#39;m not entirely certain of the modifications as I have inherited this program from a colleague) version of VersorRigid3DTransform as a first step in a rigid-then-non-rigid registration algorithm (the non-rigid portion is accomplished with 3D B-spline deformable registration). The two image sets I have are MR slices (48 slices per condition) of a live tissue before and after a relatively large deformation. I&#39;ve segmented only the tissue of interest from the images.<br>

<br>After my first attempts with the &#39;Rigid&#39; aspect of this algorithm, I am receiving an output image with all pixel values of &#39;0&#39;. I do receive real values for the translation vector, but my rotation matrix is essentially an identity matrix (which could be feasible, as I&#39;m not certain how much rotation is going on during the deformation). Regardless, the aforementioned colleague indicated that a &#39;zeroed&#39; output image is signifying a registration failure.<br>

<br>Can anyone give me some sort of indication of the limits of this rigid registration program? If my deformation is too large or affine, should I be using a different registration program before the &#39;non-rigid&#39; part of the algorithm?<br>

<br>My downfall is that I am really not well-versed in c++ or much of the fundamental workings of ITK, but it seems to be a very powerful tool and very much appropriate for my study. I am in the process of &#39;beefing-up&#39; on my understanding of the ITK environment, but in the meantime I would greatly appreciate being able to move past this hurdle.<br>

<br>I can supply code if needed as well as any other pertinent info deemed necessary. I am using the 3.20 ITK release.<br><br>Thanks so much in advance,<br clear="all"><br>-- <br><font color="#888888">Tim Bhatnagar<br>
</font></blockquote></div><br><br clear="all"><br>-- <br>Tim Bhatnagar<br>