<br>Hi Sharath,<br><br><br>0) It is great that you have verified the Initialization<br><br><br>1) Translation initialization is "usually" enough...<br> but only if the rotation and scaling misalignments<br> are small....<br>
<br> A typical registration will not be able to correct <br> for more than a 30 degrees rotation, or a scaling<br> beyond a factor of 1.5.<br><br> So, please provide all the initialization that you can.<br>
<br> You may want to consider the use of the <br> <br> LandmarkBasedTransformInitializer<br><br><br>2) If you results start diverging from the expected answer<br> in the very first iterations, then you should suspect:<br>
<br> a) Incorrect balance of the rotation vs translation<br> values in the parameter scaling array<br><br> or<br><br> b) Your step lenghts are too large in the optimizer<br>
<br> or<br><br> c) You may have set the Optimizer to Maximize, when<br> the Metric needs to be Minimized (or the other way<br> around).<br><br> <br>3) You are correct that if the Registration is walking in the<br>
right direction, the Joint histograms should be getting <br> more concentrated in the diagonal...<br><br> BUT ONLY IF<br><br> you are working with two images of the same modality.<br><br> Otherwise, if the images are of different modality, the<br>
histogram will never be concentrated in the diagonal.<br><br><br>4) Unfortunately we don't have much material written on<br> how to analyze the histograms.<br><br> I will suggest that you save them as images using the<br>
Histogram to Image filter, and then load them as a <br> series of 2D+T images into VV<br><br> <a href="http://www.creatis.insa-lyon.fr/rio/vv">http://www.creatis.insa-lyon.fr/rio/vv</a><br><br> so that you can play them as an animation.<br>
<br><br>5) The typical use of the vtkRegistrationMonitor will be:<br><br> #include "vtkRegistrationMonitor.h"<br> #include "vtkKWImage.h"<br> #include "vtkContourFilter.h"<br> #include "vtkImageData.h"<br>
<br> vtkRegistrationMonitor monitor;<br><br> vtkSmartPointer< vtkKWImage > fixedKWImage = vtkSmartPointer< vtkKWImage >::New();<br> vtkSmartPointer< vtkKWImage > movingKWImage = vtkSmartPointer< vtkKWImage >::New();<br>
<br> fixedKWImage->SetITKImageBase( const_cast<FixedImageType *>( fixedImage ) );<br> movingKWImage->SetITKImageBase( const_cast<MovingImageType *>( movingImage ) );<br><br> vtkSmartPointer< vtkContourFilter > fixedContour = vtkSmartPointer< vtkContourFilter >::New();<br>
vtkSmartPointer< vtkContourFilter > movingContour = vtkSmartPointer< vtkContourFilter >::New();<br><br> fixedContour->SetInput( fixedKWImage->GetVTKImage() );<br> movingContour->SetInput( movingKWImage->GetVTKImage() );<br>
<br> fixedContour->SetValue( 0, 200.0 ); // level for iso-contour (DEPENDS on your data)<br> movingContour->SetValue( 0, 200.0 ); // level for iso-contour (DEPENDS on your data)<br><br> monitor.SetFixedSurface( fixedContour->GetOutput() );<br>
monitor.SetMovingSurface( movingContour->GetOutput() );<br><br> monitor.SetNumberOfIterationPerUpdate( 1 ); (RECONSIDER CHANGING...)<br><br> std::string screenshotDirectory = argv[7];<br> itksys::SystemTools::MakeDirectory( screenshotDirectory.c_str() );<br>
<br> std::cout << screenshotDirectory << std::endl; <br><br> monitor.SetScreenshotOutputDirectory( screenshotDirectory.c_str() );<br> monitor.SetScreenshotBaseName( "registrationScreenshot" );<br>
<br> monitor.Observe( optimizer, rigidTransform );<br><br><br>You will find the vtkKWImage classes also in <br><br> InsightApplications/Auxiliary/vtk<br><br><br>---<br><br> Regards,<br><br><br> Luis<br><br><br>----------------------------------------------------------------------<br>
<div class="gmail_quote">On Thu, Jul 2, 2009 at 3:01 PM, Sharath Venkatesha <span dir="ltr"><<a href="mailto:sharath20284@yahoo.com">sharath20284@yahoo.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Hi,<br>
<br>
Thanks for the all the help and information provided in the earlier mails.<br>
<br>
I have ensured that I am using correct initialization ( translation only) and correct values of optimizer scales.<br>
<br>
*** Is it sufficient if I provide initialization parameters for translation (approx values) only? It is difficult for me estimate the scale and rotation parameters.<br>
<br>
I am using MutualInformationHistogramImageToImageMetric +<br>
MultiResolutionImageRegistrationMethod + AffineTransform +<br>
RegularStepGradientDescentOptimizer/GradientDescentOptimizer<br>
<br>
I am having problem with tuning of parameters (MaxStepSize and MinStepSize for RegularStepGradientDescentOptimizer, and LearningRate for GradientDescentOptimizer) . My results start diverging off the correct route in the first few iterations itself.<br>
<br>
I have looked into<br>
(1) Plotting of joint histograms (section 8.5.3 of ITK manual)<br>
(2) vtkRegistrationMonitor<br>
<br>
<br>
I am having trouble interpreting the results of the joint histograms.I understand that with correct parameters for registration, I should get a histogram which has highest density only along the diagonal. I have the outputs of the JointHistograms after very iteration for very level , and finding hard to follow the changes.<br>
<br>
*** Is there is a defined procedure for understanding the results?<br>
<br>
Can you please point me to where I can get more information on (1) and (2) ?<br>
<br>
Thanks,<br>
Sharath Venkatesha<br>
<br>
<br>
------------------------------<br>
Luis wrote:<br>
<br>
<br>
Hi Sharath,<br>
<br>
0) Whenever you get the exception saying that too many points<br>
mapped outside of the moving image, it means that the<br>
current Transform is such that when mapping the moving image<br>
into the Fixed image coordinate system the overlap between<br>
the two image is so small that it is unlikely that the<br>
registration will recover in further iterations.<br>
<br>
This is typically due to:<br>
<br>
<br>
A) Poor initilization of the Transform<br>
<br>
B) Poor selection of Scaling parameters<br>
(the array that normalizes the dynamic<br>
range of the different Transform parameters,<br>
e.g. radians versus millimeters)<br>
<br>
C) Optimizers that are set to perform jumps<br>
that are too large, and bring the Transform<br>
out of the range of the image.<br>
<br>
1) You want to check this potential suspects in order.<br>
<br>
That is.<br>
<br>
First, verify that the initial transform<br>
is reasonably placing the Moving image on top of the<br>
Fixed image. You can do this by using the Resample<br>
image filter, passing the moving image as input,<br>
using the initial transform as Transform, and using<br>
the Fixed image as reference. Then compare the<br>
fixed image to the resampled moving image.<br>
<br>
If the initial image looks ok,<br>
then you want to check the values of the ParameterScaling.<br>
It should be such that when you look at the Transform<br>
parameters at ever iteration (using an Observer), the<br>
values should change from iteration to iteration, according<br>
to the expected dynamic range.<br>
<br>
For example, transform parameters that correspond to rotations<br>
should change by increments smaller than 0.01 (since they are<br>
measured in Radians). While transform parameters that correspond<br>
to translations should change at increments of 1 ~ 10<br>
<br>
<br>
Finally, you should identify the parameter of the optimzer<br>
that is responsible for selecting the size of jumps that<br>
are performed in the parameteric space. (e.g. as you have<br>
done for the learning rate in the GradientDescent optimizer).<br>
<br>
You want to reduce the size of that jump, until you get the<br>
Transform to have small increments at every iteration.<br>
<br>
<br>
2) These parameters must be set up for every "family" of<br>
registration problems. That is, the parameters that may be<br>
good for registering a T1 to T2 MRI brain images, may not be<br>
appropriate for registering a confocal microscopy image to<br>
another.<br>
<br>
However, once you fine tune the paramters for a pair of<br>
T1-T2 images, it is likely that the same set of parameters<br>
will work for another pair of the same type.<br>
<br>
There is a need for a "smart layer" above the registration<br>
framework, that could take away from the user the burden<br>
of finding proper parameter settings....<br>
<br>
any ideas are welcome :-)<br>
<br>
<br>
3) Visual monitoring of the registraiton process<br>
will help to make the fine-tunning process less<br>
frustrating.<br>
<br>
You may want to give it a try at the VTK helper<br>
classes:<br>
<br>
InsightApplications/Auxiliary/vtk/<br>
vtkRegistrationMonitor.h<br>
vtkRegistrationMonitor.cxx<br>
<br>
they will display renderings from iso-surfaces<br>
at every iteration of the registration process.<br>
<br>
This is usually very informative...<br>
<br>
<br>
<br>
Regards,<br>
<br>
<br>
Luis<br>
<br>
<br>
--------------<br>
sharath v wrote:<br>
> Hi,<br>
><br>
> Thanks for the help. Changing the learning parameter worked...<br>
><br>
><br>
For Viola MI + Affine and with learning rate of 0.01 and 100<br>
iterations, I get good results on BrainProtonDensitySliceR10X13Y17<br>
image. Whereas on the BrainProtonDensitySliceR10X13Y17S12 image, it<br>
requires atleast 200 iterations to give correct results.<br>
><br>
><br>
I want to use an optimizer which has a stopping value (i.e not fixed<br>
number of iterations) like Amoeba/Evolutionary/GradientDescentStep<br>
><br>
> I tried using the Amoeba optimizer with the following<br>
><br>
> OptimizerType::ParametersType simplexDelta( transform->GetNumberOfParameters() );<br>
> simplexDelta.Fill( 5.0 );<br>
> optimizer->AutomaticInitialSimplexOff();<br>
> optimizer->SetInitialSimplexDelta( simplexDelta );<br>
> optimizer->SetParametersConvergenceTolerance( 0.01 ); // quarter pixel<br>
> optimizer->SetFunctionConvergenceTolerance(0.001); // 0.1%<br>
> optimizer->SetMaximumNumberOfIterations( 200 );<br>
><br>
><br>
but I get an exception that sampled point mapped to outside of the<br>
moving image, after 6-7 iterations. Similar issue happens for<br>
OnePlusOne optimizer with<br>
><br>
> typedef itk::Statistics::NormalVariateGenerator GeneratorType;<br>
> GeneratorType::Pointer generator = GeneratorType::New();<br>
> generator->Initialize(12345);<br>
> optimizer->SetNormalVariateGenerator( generator );<br>
> optimizer->Initialize( 10 );<br>
> optimizer->SetEpsilon( 1.0 );<br>
> optimizer->SetMaximumIteration( 4000 );<br>
><br>
> Can you please let me know what values need to be used?<br>
><br>
> And is there a way to make the registration process partially independent of these parameters?<br>
><br>
> Thanks,<br>
> Sharath<br>
<br>
<br>
<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>
Please keep messages on-topic and check the ITK FAQ at: <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>
</blockquote></div><br>