<br><div class="gmail_quote"><br>Hi there,<br>I am trying to register two 2-D images,<br>using the NormalizedMutualInformationMetric (NMI), but I have terrible results.<br>I have modified the ImageRegistration7.cxx example, in order to use this metric.<br>

My questions are:<br>1.Does NMI Metric works only with&nbsp; itkOnePlusOneEvolutionaryOptimizer as shown in example 14?<br>2.Beside the number of histogram bins, is there any other parameter of the NMI,that could be modified,<br>

in order to get better results?<br>3.Does the images need to be preprocessed (normalizedImageFilter , and Smoothed (GaussianImageFilter)),<br>before entering the registration process?<br>Thanks in advance<br>Giorgos<br><br>

<br>/*========================================================================*/<br><br>#include &quot;itkImageRegistrationMethod.h&quot;<br>#include &quot;itkNormalizedMutualInformationHistogramImageToImageMetric.h&quot;<br>

#include &quot;itkLinearInterpolateImageFunction.h&quot;<br>#include &quot;itkRegularStepGradientDescentOptimizer.h&quot;<br>#include &quot;itkImage.h&quot;<br><br>#include &quot;itkCenteredTransformInitializer.h&quot;<br>

#include &quot;itkCenteredSimilarity2DTransform.h&quot;<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;itkIdentityTransform.h&quot;<br><br><br>#include &quot;itkMeanSquaresImageToImageMetric.h&quot;<br>
#include &quot;itkCorrelationCoefficientHistogramImageToImageMetric.h&quot;<br>
<br><br>#include &quot;itkTranslationTransform.h&quot;<br>#include &quot;itkNearestNeighborInterpolateImageFunction.h&quot;<br>#include &quot;itkCheckerBoardImageFilter.h&quot;<br><br>//<br>#include &quot;itkCommand.h&quot;<br>

class CommandIterationUpdate : public itk::Command <br>{<br>public:<br>&nbsp; typedef&nbsp; CommandIterationUpdate&nbsp;&nbsp; Self;<br>&nbsp; typedef&nbsp; itk::Command&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Superclass;<br>&nbsp; typedef itk::SmartPointer&lt;Self&gt;&nbsp; Pointer;<br>
&nbsp; itkNewMacro( Self );<br>
protected:<br>&nbsp; CommandIterationUpdate() {m_LastMetricValue = 0;};<br>public:<br>&nbsp; typedef itk::RegularStepGradientDescentOptimizer&nbsp;&nbsp;&nbsp;&nbsp; OptimizerType;<br>&nbsp; typedef&nbsp;&nbsp; const OptimizerType&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp; OptimizerPointer;<br><br>&nbsp; void Execute(itk::Object *caller, const itk::EventObject &amp; event)<br>

&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Execute( (const itk::Object *)caller, event);<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp; void Execute(const itk::Object * object, const itk::EventObject &amp; event)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OptimizerPointer optimizer = <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dynamic_cast&lt; OptimizerPointer &gt;( object );<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( ! itk::IterationEvent().CheckEvent( &amp;event ) )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; double currentValue = optimizer-&gt;GetValue();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if( fabs( m_LastMetricValue - currentValue ) &gt; 1e-4 )<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; optimizer-&gt;GetCurrentIteration() &lt;&lt; &quot;&nbsp;&nbsp; &quot;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; optimizer-&gt;GetValue() &lt;&lt; &quot;&nbsp;&nbsp; &quot;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; optimizer-&gt;GetCurrentPosition() &lt;&lt; std::endl;<br>

&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; m_LastMetricValue = currentValue;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private:<br>&nbsp; double m_LastMetricValue;<br>};<br><br><br>int main( int argc, char *argv[] )<br>{<br>&nbsp; if( argc &lt; 4 )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot;Missing Parameters &quot; &lt;&lt; std::endl;<br>

&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot;Usage: &quot; &lt;&lt; argv[0];<br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot; fixedImageFile&nbsp; movingImageFile &quot;;<br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot; outputImagefile&nbsp; [differenceBeforeRegistration] &quot;;<br>

&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot; [differenceAfterRegistration] [Checkerboard Image]&quot;;<br><br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot; [initialScaling] [initialAngle] &quot;;<br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot; [steplength] &quot;;<br>

&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; std::endl;<br>&nbsp;&nbsp;&nbsp; return EXIT_FAILURE;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; <br>&nbsp; const&nbsp;&nbsp;&nbsp; unsigned int&nbsp;&nbsp;&nbsp; Dimension = 2;<br>&nbsp; typedef&nbsp; float&nbsp;&nbsp; PixelType;<br>&nbsp; typedef&nbsp; float&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InternalPixelType;<br>&nbsp; <br>&nbsp;<br>&nbsp; typedef itk::Image&lt; PixelType, Dimension &gt;&nbsp; FixedImageType;<br>

&nbsp; typedef itk::Image&lt; PixelType, Dimension &gt;&nbsp; MovingImageType;<br><br>/// reading the images<br><br>&nbsp; typedef itk::ImageFileReader&lt; FixedImageType&nbsp; &gt; FixedImageReaderType;<br>&nbsp; typedef itk::ImageFileReader&lt; MovingImageType &gt; MovingImageReaderType;<br>

<br>&nbsp; FixedImageReaderType::Pointer&nbsp; fixedImageReader&nbsp; = FixedImageReaderType::New();<br>&nbsp; MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();<br><br>&nbsp; fixedImageReader-&gt;SetFileName(&nbsp; argv[1] );<br>

&nbsp; movingImageReader-&gt;SetFileName( argv[2] );<br><br>&nbsp; typedef itk::CenteredSimilarity2DTransform&lt; double &gt; TransformType;<br>&nbsp;<br>&nbsp; typedef itk::RegularStepGradientDescentOptimizer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OptimizerType;<br>&nbsp; typedef itk::NormalizedMutualInformationHistogramImageToImageMetric&lt; InternalImageType, InternalImageType&gt;<br>

&nbsp;&nbsp;&nbsp; MetricType;<br>&nbsp; typedef itk:: LinearInterpolateImageFunction&lt; InternalImageType, double &gt;<br>&nbsp;&nbsp;&nbsp; InterpolatorType;<br>&nbsp; typedef itk::ImageRegistrationMethod&lt; InternalImageType, InternalImageType &gt;<br>&nbsp;&nbsp;&nbsp; RegistrationType;<br>

<br>&nbsp; MetricType::Pointer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metric&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = MetricType::New();<br>&nbsp; OptimizerType::Pointer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; optimizer&nbsp;&nbsp;&nbsp;&nbsp; = OptimizerType::New();<br>&nbsp; InterpolatorType::Pointer&nbsp;&nbsp; interpolator&nbsp; = InterpolatorType::New();<br>&nbsp; RegistrationType::Pointer&nbsp;&nbsp; registration&nbsp; = RegistrationType::New();<br>

<br>&nbsp; registration-&gt;SetMetric(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; metric&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; );<br>&nbsp; registration-&gt;SetOptimizer(&nbsp;&nbsp;&nbsp;&nbsp; optimizer&nbsp;&nbsp;&nbsp;&nbsp; );<br>&nbsp; registration-&gt;SetInterpolator(&nbsp; interpolator&nbsp; );<br><br>&nbsp; TransformType::Pointer&nbsp; transform = TransformType::New();<br>

&nbsp; registration-&gt;SetTransform( transform );<br><br><br><br>&nbsp; /////NORMALIZED MI SETTINGS<br>&nbsp;&nbsp; unsigned int numberOfHistogramBins;<br>&nbsp; std::cout&lt;&lt; &quot; Enter Number of Histogram Bins : &quot; ;<br>&nbsp; std::cin &gt;&gt; numberOfHistogramBins; <br>

&nbsp; std::cout&lt;&lt;std::endl;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; /*if( argc &gt; 4 )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; numberOfHistogramBins = atoi( argv[4] );<br>&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; &quot;Using &quot; &lt;&lt; numberOfHistogramBins &lt;&lt; &quot; Histogram bins&quot; &lt;&lt; std::endl;<br>

&nbsp;&nbsp;&nbsp; }*/<br>&nbsp;&nbsp;&nbsp; MetricType::HistogramType::SizeType histogramSize;<br>&nbsp; histogramSize[0] = numberOfHistogramBins;<br>&nbsp; histogramSize[1] = numberOfHistogramBins;<br>&nbsp; metric-&gt;SetHistogramSize( histogramSize );<br>&nbsp;<br><br>

&nbsp; const unsigned int numberOfParameters = transform-&gt;GetNumberOfParameters();<br><br>&nbsp; typedef MetricType::ScalesType ScalesType;<br>&nbsp; ScalesType scales( numberOfParameters );<br><br>&nbsp; scales.Fill( 1.0 );<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; metric-&gt;SetDerivativeStepLengthScales(scales);<br>

&nbsp; <br>//////<br>///// SETTING THE IMAGES FOR THE REGISTRATION PROCESS<br><br>&nbsp; registration-&gt;SetFixedImage(&nbsp;&nbsp;&nbsp; fixedImageReader-&gt;GetOutput()&nbsp;&nbsp;&nbsp; );<br>&nbsp; registration-&gt;SetMovingImage(&nbsp;&nbsp; movingImageReader-&gt;GetOutput()&nbsp;&nbsp; );<br>

&nbsp; <br>&nbsp; fixedImageReader-&gt;Update();<br>&nbsp; FixedImageType::RegionType fixedImageRegion =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fixedImageReader-&gt;GetOutput()-&gt;GetBufferedRegion();<br>&nbsp; registration-&gt;SetFixedImageRegion( fixedImageRegion );<br>

<br><br>&nbsp; typedef itk::CenteredTransformInitializer&lt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TransformType, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FixedImageType, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MovingImageType &gt;&nbsp; TransformInitializerType;<br>

<br>&nbsp; TransformInitializerType::Pointer initializer = TransformInitializerType::New();<br><br>&nbsp; initializer-&gt;SetTransform(&nbsp;&nbsp; transform );<br><br>&nbsp; initializer-&gt;SetFixedImage(&nbsp; fixedImageReader-&gt;GetOutput() );<br>

&nbsp; initializer-&gt;SetMovingImage( movingImageReader-&gt;GetOutput() );<br><br>&nbsp; initializer-&gt;GeometryOn();<br><br>&nbsp; initializer-&gt;InitializeTransform();<br><br>// REMAINING TRANSFORM PARAMETERS<br>&nbsp; double initialScale = 1.0;<br>

<br>&nbsp; if( argc &gt; 7 )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; initialScale =&nbsp; atof( argv[7] );<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp; double initialAngle = 0.0;<br><br>&nbsp; if( argc &gt; 8 )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; initialAngle =&nbsp; atof( argv[8] );<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp; // Software Guide : BeginCodeSnippet<br>

&nbsp; transform-&gt;SetScale( initialScale );<br>&nbsp; transform-&gt;SetAngle( initialAngle );<br>&nbsp; // Software Guide : EndCodeSnippet<br><br>&nbsp; registration-&gt;SetInitialTransformParameters( transform-&gt;GetParameters() );<br>
&nbsp; <br>
&nbsp; typedef OptimizerType::ScalesType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OptimizerScalesType;<br>&nbsp; OptimizerScalesType optimizerScales( transform-&gt;GetNumberOfParameters() );<br>&nbsp; const double translationScale = 1.0 / 100.0;<br><br>&nbsp; optimizerScales[0] = 10.0;<br>

&nbsp; optimizerScales[1] =&nbsp; 1.0;<br>&nbsp; optimizerScales[2] =&nbsp; translationScale;<br>&nbsp; optimizerScales[3] =&nbsp; translationScale;<br>&nbsp; optimizerScales[4] =&nbsp; translationScale;<br>&nbsp; optimizerScales[5] =&nbsp; translationScale;<br><br>&nbsp; optimizer-&gt;SetScales( optimizerScales );<br>

<br><br>&nbsp; double steplength = 1.0;<br>&nbsp; <br>&nbsp; if( argc &gt; 9 )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; steplength = atof( argv[9] );<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp; // Software Guide : BeginCodeSnippet<br>&nbsp; optimizer-&gt;SetMaximumStepLength( steplength ); <br>

&nbsp; optimizer-&gt;SetMinimumStepLength( 0.0001 );<br>&nbsp; optimizer-&gt;SetNumberOfIterations( 500 );<br>&nbsp; // Software Guide : EndCodeSnippet<br><br><br>&nbsp; // Create the Command observer and register it with the optimizer.<br>
&nbsp; //<br>
&nbsp; CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();<br>&nbsp; optimizer-&gt;AddObserver( itk::IterationEvent(), observer );<br><br><br>&nbsp; try <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; registration-&gt;StartRegistration(); <br>
&nbsp;&nbsp;&nbsp; } <br>
&nbsp; catch( itk::ExceptionObject &amp; err ) <br>&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; &quot;ExceptionObject caught !&quot; &lt;&lt; std::endl; <br>&nbsp;&nbsp;&nbsp; std::cerr &lt;&lt; err &lt;&lt; std::endl; <br>&nbsp;&nbsp;&nbsp; return EXIT_FAILURE;<br>&nbsp;&nbsp;&nbsp; } <br>

&nbsp; <br>&nbsp; OptimizerType::ParametersType finalParameters = <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; registration-&gt;GetLastTransformParameters();<br><br><br>&nbsp; const double finalScale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = finalParameters[0];<br>&nbsp; const double finalAngle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = finalParameters[1];<br>

&nbsp; const double finalRotationCenterX = finalParameters[2];<br>&nbsp; const double finalRotationCenterY = finalParameters[3];<br>&nbsp; const double finalTranslationX&nbsp;&nbsp;&nbsp; = finalParameters[4];<br>&nbsp; const double finalTranslationY&nbsp;&nbsp;&nbsp; = finalParameters[5];<br>

<br>&nbsp; const unsigned int numberOfIterations = optimizer-&gt;GetCurrentIteration();<br><br>&nbsp; const double bestValue = optimizer-&gt;GetValue();<br><br><br>&nbsp; // Print out results<br>&nbsp; //<br>&nbsp; const double finalAngleInDegrees = finalAngle * 45.0 / atan(1.0);<br>

<br>&nbsp; std::cout &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot;Result = &quot; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Scale&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot; &lt;&lt; finalScale&nbsp; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Angle (radians) &quot; &lt;&lt; finalAngle&nbsp; &lt;&lt; std::endl;<br>

&nbsp; std::cout &lt;&lt; &quot; Angle (degrees) &quot; &lt;&lt; finalAngleInDegrees&nbsp; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Center X&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot; &lt;&lt; finalRotationCenterX&nbsp; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Center Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = &quot; &lt;&lt; finalRotationCenterY&nbsp; &lt;&lt; std::endl;<br>

&nbsp; std::cout &lt;&lt; &quot; Translation X = &quot; &lt;&lt; finalTranslationX&nbsp; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Translation Y = &quot; &lt;&lt; finalTranslationY&nbsp; &lt;&lt; std::endl;<br>&nbsp; std::cout &lt;&lt; &quot; Iterations&nbsp;&nbsp;&nbsp; = &quot; &lt;&lt; numberOfIterations &lt;&lt; std::endl;<br>

&nbsp; std::cout &lt;&lt; &quot; Metric value&nbsp; = &quot; &lt;&lt; bestValue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt; std::endl;<br><br><br>&nbsp;...........................<br>............................<br><br>&nbsp; return EXIT_SUCCESS;<br>
}<br><br><br><br>
</div><br>