<div><br></div><div>FYI, here's a snip from the "rotation loop" (see ImageRegistration6.cxx for the rest):</div><div><br></div><div><br></div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> // The registration fails when the angle of rotation is large, so we need a</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> // loop to evaluate a range of angles to find one that will work well.</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> double angleInDegrees[] = { 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0 };</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> double angleInRadians, bestAngleInRadians;</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> unsigned int bestIterations = 0;</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> TransformType::Pointer rigid2DFinalTransform = TransformType::New();</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><div> OptimizerType::MeasureType bestMetric = 0.0;</div><div><br></div></span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large; "> for( unsigned int i = 0; i < 19; i++ )</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> {</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> angleInRadians = angleInDegrees[i] * vnl_math::pi / 180.0;</span></font></div><div>
<font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> std::cout</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "Loop " << i << ", trying:" << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "angleInDegrees = " << angleInDegrees[i] << " degrees " << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "angleInRadians = " << angleInRadians << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << std::endl;</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> initializer->InitializeTransform();</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> rigid2DTransform->SetAngle( angleInRadians );</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> registration->SetInitialTransformParameters( rigid2DTransform->GetParameters() );</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> try </span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> { </span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> registration->StartRegistration(); </span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> if( VERBOSE )</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> {</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> std::cout << std::endl</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << optim << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << std::endl;</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> }</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> } </span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> catch( itk::ExceptionObject & err ) </span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> { </span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> std::cerr << "ExceptionObject caught !" << std::endl; </span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> std::cerr << err << std::endl; </span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> return EXIT_FAILURE;</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> } </span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br>
</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> // Check the metric and store the best angle</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> if( i == 0 )</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> bestMetric = optim->GetValue();</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> if( bestMetric > optim->GetValue() )</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> {</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> bestMetric = optim->GetValue();</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> bestIterations = optim->GetCurrentIteration();</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> bestAngleInRadians = angleInRadians;</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> // ** Set the final rigid2DTransform **</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> rigid2DFinalTransform->SetParameters( registration->GetLastTransformParameters() );</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> rigid2DFinalTransform->SetFixedParameters( rigid2DTransform->GetFixedParameters() );</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> }</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> std::cout</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << std::endl</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "After loop " << i << ", metrics are:" << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "angleInDegrees = " << angleInDegrees[i] << " degrees " << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "angleInRadians = " << angleInRadians << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "bestMetric = " << bestMetric << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << "currentMetric = " << optim->GetValue() << std::endl</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> << std::endl;</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> }</span></font></div>
<div><br></div><div><br></div><div><br></div><div>Best, </div><div>Darren</div><div><br></div><div><br></div></div><div><br></div><div><br></div><div><br></div><br><br><div class="gmail_quote">On Mon, Mar 8, 2010 at 11:14 AM, Darren Weber <span dir="ltr"><<a href="mailto:darren.weber.lists@gmail.com">darren.weber.lists@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div><br></div><div>Hi Luis et al.,</div><div><br></div><div>Thanks for considering this and offering suggestions.</div>
<div><br></div><div>There are thousands of images to register. It's possible to manually note approximate initialization values for the rotation of all the images. However, it may be easier (perhaps not quicker) to create a "rotation loop" that:</div>
<div><br></div><div> (a) sets a rotation value between 0 to pi (stepping 15 degrees),</div><div><br></div><div> (b) calls the registration method, then</div><div><br></div><div> (c) checks the metric for the lowest value (for mean sq metric) to identify and store the rotation that provides the "best" registration.</div>
<div><br></div><div>The extra "rotation" loop means running the registration N times (say 13 times for 0:15:180 [in Octave syntax]) and there may be a final run with the "best" rotation value.</div><div>
<br></div><div>Is this reasonable? Is there are better way to do this?</div><div><br></div>As a novice with optimization, I'm surprised that some kind of quick estimate for the full range of rotations is not built into the optimization routine or the registration method.<div>
<br></div><div>Take care,</div><div>Darren</div><div><div></div><div class="h5"><div><br></div><div><br></div><div><br><br><div class="gmail_quote">On Sat, Mar 6, 2010 at 3:58 PM, Luis Ibanez <span dir="ltr"><<a href="mailto:luis.ibanez@kitware.com" target="_blank">luis.ibanez@kitware.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Darren,<br>
<br>
<br>
Thanks for posting all the source code and images that<br>
reproduce the problem that you are observing.<br>
<br>
<br>
As Richard pointed out, the registration process must be<br>
initialized properly.<br>
<br>
<br>
It is very unlikely that an optimization process will manage<br>
to register two images that are 140 degrees off, as the ones<br>
that you kindly posted.<br>
<br>
<br>
So you should:<br>
<br>
1) Initialize the Transform with an angle close to 140 degrees.<br>
<br>
2) Use the Rigid2DTransform instead of the<br>
CenteredRigid2DTransform (this later one is deprecated)<br>
<br>
3) Remove all the Change image filters that you have in your<br>
code. They shouldn't be necessary.<br>
<br>
<br>
Please find attached a simplified variation of the example:<br>
<br>
Insight/Examples/Registration/<br>
ImageRegistration6.cxx<br>
<br>
With this attached .cxx file,<br>
I manage to register your two images with the following output:<br>
<br>
Angle (radians) 2.45657<br>
Angle (degrees) 140.751<br>
Translation X = 1.67046<br>
Translation Y = -0.480926<br>
Iterations = 92<br>
Metric value = 6.19969e+07<br>
<br>
<br>
I ran it with the following set of command line arguments:<br>
<br>
ImageRegistration6<br>
<br>
section0004_w1.tif section0005_w1.tif 150.0 output.tiff<br>
<br>
<br>
Where "150.0" is the initial angle to set in the Transform.<br>
<br>
<br>
Please give it a try at this attached code and let us<br>
know if you find any problems.<br>
<br>
<br>
Thanks<br>
<br>
<br>
Luis<br>
<br>
<br>
--------------------------------------------------------------------------------------<br>
<div><div></div><div>On Fri, Mar 5, 2010 at 7:56 PM, Richard Beare <<a href="mailto:richard.beare@gmail.com" target="_blank">richard.beare@gmail.com</a>> wrote:<br>
> Good initialization is essential for all registration, with the<br>
> rotation component often the most critical. If the rotation is greater<br>
> than 15 degrees then you're probably going to have trouble.<br>
><br>
> If you're trying to build an automated process rather than a one off,<br>
> then here are some options.<br>
><br>
> Moments based initialization as a first step. This is good if the<br>
> scene is reasonably simple, or you have masks defining the regions of<br>
> interest. You can check how similar the major moments are. If they are<br>
> sufficiently dissimilar then the initialization is likely to be<br>
> accurate along the major axis, but potentially flipped. In this case<br>
> you need to try both options and select the one that gives the best<br>
> resulting cost. If the moments are similar then the initialization<br>
> will be unreliable and sensitive to small changes, so you need to try<br>
> a series of angles covering the entire 360 degrees and select the best<br>
> result as defined by your cost metric.<br>
><br>
> On Sat, Mar 6, 2010 at 11:45 AM, Darren Weber<br>
> <<a href="mailto:darren.weber.lists@gmail.com" target="_blank">darren.weber.lists@gmail.com</a>> wrote:<br>
>><br>
>> I've got a couple of images that clearly need nearly 180 degree rotation for<br>
>> registration, see:<br>
>> <a href="ftp://anonymous" target="_blank">ftp://anonymous</a>@<a href="http://ftp.buckinstitute.org/dweber/section0004_w1.tif" target="_blank">ftp.buckinstitute.org/dweber/section0004_w1.tif</a><br>
>> <a href="ftp://anonymous" target="_blank">ftp://anonymous</a>@<a href="http://ftp.buckinstitute.org/dweber/section0005_w1.tif" target="_blank">ftp.buckinstitute.org/dweber/section0005_w1.tif</a><br>
>> The registration fails to rotate the images into alignment. I'm using:<br>
>> // Registration components<br>
>> #include "itkImageRegistrationMethod.h"<br>
>> #include "itkMeanSquaresImageToImageMetric.h"<br>
>> #include "itkLinearInterpolateImageFunction.h"<br>
>> #include "itkRegularStepGradientDescentOptimizer.h"<br>
>> // Transforms<br>
>> #include "itkCenteredRigid2DTransform.h"<br>
>> #include "itkCenteredTransformInitializer.h"<br>
>><br>
>> What can I do about it? Have I selected the wrong transform for rotations?<br>
>> I've prepared a package of my test program and data for download here:<br>
>> <a href="ftp://anonymous" target="_blank">ftp://anonymous</a>@<a href="http://ftp.buckinstitute.org/dweber/itkRegistrationTest.tar.gz" target="_blank">ftp.buckinstitute.org/dweber/itkRegistrationTest.tar.gz</a><br>
>> The program is built against ITK 3.16 (and it uses Boost).<br>
>> TIA,<br>
>> Darren<br>
>><br>
>> _____________________________________<br>
>> Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
>><br>
>> Visit other Kitware open-source projects at<br>
>> <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
>><br>
>> Kitware offers ITK Training Courses, for more information visit:<br>
>> <a href="http://www.kitware.com/products/protraining.html" target="_blank">http://www.kitware.com/products/protraining.html</a><br>
>><br>
>> Please keep messages on-topic and check the ITK FAQ at:<br>
>> <a href="http://www.itk.org/Wiki/ITK_FAQ" target="_blank">http://www.itk.org/Wiki/ITK_FAQ</a><br>
>><br>
>> Follow this link to subscribe/unsubscribe:<br>
>> <a href="http://www.itk.org/mailman/listinfo/insight-users" target="_blank">http://www.itk.org/mailman/listinfo/insight-users</a><br>
>><br>
>><br>
> _____________________________________<br>
> Powered by <a href="http://www.kitware.com" target="_blank">www.kitware.com</a><br>
><br>
> Visit other Kitware open-source projects at<br>
> <a href="http://www.kitware.com/opensource/opensource.html" target="_blank">http://www.kitware.com/opensource/opensource.html</a><br>
><br>
> Kitware offers ITK Training Courses, for more information visit:<br>
> <a href="http://www.kitware.com/products/protraining.html" target="_blank">http://www.kitware.com/products/protraining.html</a><br>
><br>
> Please keep messages on-topic and check the ITK FAQ at:<br>
> <a href="http://www.itk.org/Wiki/ITK_FAQ" target="_blank">http://www.itk.org/Wiki/ITK_FAQ</a><br>
><br>
> Follow this link to subscribe/unsubscribe:<br>
> <a href="http://www.itk.org/mailman/listinfo/insight-users" target="_blank">http://www.itk.org/mailman/listinfo/insight-users</a><br>
><br>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br>