|
|
Line 49: |
Line 49: |
| In particular, look at lectures 8 and 9. | | In particular, look at lectures 8 and 9. |
|
| |
|
| [...] It is not productive to fight with the registration + optimization | | [...] It is not productive to fight with the registration optimization |
| until you find a way of generating relatively smooth Metric plots. | | until you find a way of generating relatively smooth Metric plots. |
| Note that this is just an exercise on learning how to tune the | | Note that this is just an exercise on learning how to tune the |
Line 96: |
Line 96: |
| movingReader->Update(); | | movingReader->Update(); |
| } | | } |
| catch( itk::ExceptionObject & excep ) | | catch( itk::ExceptionObject |
| {
| |
| std::cerr << "Exception catched !" << std::endl;
| |
| std::cerr << excep << std::endl;
| |
| }
| |
| | |
| | |
| typedef itk::MattesMutualInformationImageToImageMetric< ImageType, ImageType > MetricType;
| |
| | |
| MetricType::Pointer metric = MetricType::New();
| |
| | |
| | |
| | |
| typedef itk::TranslationTransform< double, Dimension > TransformType;
| |
| | |
| TransformType::Pointer transform = TransformType::New();
| |
| | |
| | |
| | |
| typedef itk::LinearInterpolateImageFunction<
| |
| ImageType, double > InterpolatorType;
| |
| | |
| InterpolatorType::Pointer interpolator = InterpolatorType::New();
| |
| | |
| | |
| metric->SetInterpolator( interpolator );
| |
| metric->SetTransform( transform );
| |
| | |
| metric->SetNumberOfHistogramBins( 20 );
| |
| metric->SetNumberOfSpatialSamples( 10000 );
| |
| | |
| transform->SetIdentity();
| |
| | |
| ImageType::ConstPointer fixedImage = fixedReader->GetOutput();
| |
| ImageType::ConstPointer movingImage = movingReader->GetOutput();
| |
| | |
| metric->SetFixedImage( fixedImage );
| |
| metric->SetMovingImage( movingImage );
| |
| | |
| metric->SetFixedImageRegion( fixedImage->GetBufferedRegion() );
| |
| | |
| try
| |
| {
| |
| metric->Initialize();
| |
| }
| |
| catch( itk::ExceptionObject & excep )
| |
| {
| |
| std::cerr << "Exception catched !" << std::endl;
| |
| std::cerr << excep << std::endl;
| |
| return -1;
| |
| }
| |
| | |
| | |
| MetricType::TransformParametersType displacement( Dimension );
| |
| | |
| int rangex = 50;
| |
| int rangey = 50;
| |
| | |
| for( int dx = -rangex; dx <= rangex; dx++ )
| |
| {
| |
| for( int dy = -rangey; dy <= rangey; dy++ )
| |
| {
| |
| displacement[0] = dx;
| |
| displacement[1] = dy;
| |
| const double value = metric->GetValue( displacement );
| |
| | |
| std::cout << dx << " " << dy << " " << value << std::endl;
| |
| }
| |
| }
| |
| | |
| std::cout << std::endl;
| |
| | |
| | |
| return 0;
| |
| }</pre>
| |
| | |
| | |
| http://public.kitware.com/pipermail/insight-users/2004-April/008043.html
| |
| | |
| | |
| | |
| | |
| <b><u>Optimizer->SetScales()</u></b>
| |
| | |
| | |
| The rule of thumb is to figure out how much each one of those
| |
| parameters will change for your registration, and then rescale
| |
| that range to [-1:1].
| |
| | |
| | |
| | |
| <u>In the case that you know the anticipated range of translations and rotations,</u>
| |
| | |
| | |
| "[...]if you are doing 2D rigid you will have a 2D transform with
| |
| three parameters:
| |
| | |
| Tx translation in millimeters along X
| |
| Ty translation in millimeters along Y
| |
| R rotation in radians
| |
| | |
| and you anticipate that your images need a correction of the
| |
| order of 10 to 50 millimeters in translation and 0.01 to 0.1
| |
| radians in rotation, then you should put scales:
| |
| | |
| scale[0] = 1/50; scale for Tx
| |
| scale[1] = 1/50; scale for Ty
| |
| scale[2] = 1/0.1; scale for Rotation
| |
| | |
| Of course, those will be just "good values to start with".
| |
| You will still need to refine them according to the behavior
| |
| of the optimizer."
| |
| | |
| http://public.kitware.com/pipermail/insight-users/2005-April/012896.html
| |
| | |
| | |
| | |
| <u>In the case that you do not know the anticipated range of translations and rotations,</u>
| |
| | |
| | |
| "[...]the recommendation for the scaling of translation parameters versus
| |
| rotation parameter is to use a factor proportional to the diagonal
| |
| length of the image.
| |
| | |
| For your case the, you have 100 pixels with 1 mm / pixel, therefore the
| |
| physical extent of your image is
| |
| | |
| 100mm X 100mm X 100mm
| |
| | |
| The diagonal the image bounding box is
| |
| | |
| sqrt(3) * 100 mm
| |
| | |
| which is about
| |
| | |
| 173.2
| |
| | |
| and extra factor of 10X is usually useful, so you should probably try a
| |
| factor of
| |
| | |
| 1.0 / ( 10 x 173.2 ) = 1.0 / 1732.0
| |
| | |
| You could use this same factor for the three components
| |
| of the translation or you could estimate independent
| |
| factor for each component in the way it is done in the
| |
| VolView plugin.
| |
| | |
| Note that this factors are not expected to be computed precisely. Their
| |
| purpose is simply to bring the rotational and translational parameters
| |
| to a similar numerical scale.
| |
| | |
| By default, they are quite disproportionate since rotation
| |
| are in radians, therefore in a range about -1:1, while translations are
| |
| in millimeters, and for an image of 100mm you probably can expect
| |
| translations as large as 50mm."
| |
| | |
| http://public.kitware.com/pipermail/insight-users/2004-July/009558.html
| |
| | |
| | |
| | |
| In short,
| |
| | |
| | |
| "[...]for an 3D AffineTransform, you get 12 parameters: the
| |
| first 9 are the coefficients of the matrix (representing
| |
| rotation, scale and shearing) the last 3 are the components
| |
| of a translation vector. You want then to provide an
| |
| array of 12 values with the first 9 being =1.0 and the last
| |
| three being on the range of 1.0 / the image size (in millimeters)."
| |
| | |
| http://public.kitware.com/pipermail/insight-users/2002-October/001400.html
| |
| | |
| | |
| | |
| <b><u>itk::RegularStepGradientDescentOptimizer->SetMaximumStepLength()</u></b>
| |
| | |
| <b><u>itk::RegularStepGradientDescentOptimizer->SetMinimumStepLength()</u></b>
| |
| | |
| | |
| "[...]There is no magic recipe for selecting one. You probably
| |
| want to start experimenting with a small value (e.g. 0.01)
| |
| and plot the metric evaluations during the registration
| |
| process. If you observe that the metric values are fairly
| |
| monotonic, that means that you can safely increment the
| |
| step length. Such an increment has the advantage of reducing
| |
| the time required to reach an extrema of the cost function
| |
| (the image metric in this case). You could restart the
| |
| registration with larger values of the step length, as long
| |
| as you don't observe a noisy and/or erratic behavior on the
| |
| Metric values.
| |
| | |
| Step length issues are discussed in the course material
| |
| from the "Image Registration Techniques" course at RPI.
| |
| | |
| http://www.cs.rpi.edu/courses/spring04/imagereg/
| |
| | |
| for example in lecture 9:
| |
| | |
| http://www.cs.rpi.edu/courses/spring04/imagereg/lecture09.ppt"
| |
| | |
| | |
| http://public.kitware.com/pipermail/insight-users/2004-July/009558.html
| |
| | |
| | |
| | |
| | |
| == Use Cases ==
| |
| | |
| | |
| === CT-MRI Brain Registration ===
| |
| | |
| | |
| | |
| === PET-CT Registration ===
| |
| | |
| | |
| | |
| {{ITK/Template/Footer}}
| |
Image Registration Components
Image Similarity Metrics
Transforms
Optimizers
Interpolators
Tuning Parameters
Optimizers
"[...] In order to get some insight on how to tune the parameters
for your optimization, probably the best thing to do is to
study the characteristics of the Metric when computed over
your images. Please find attached a small program that allows
you to explore the values of the metric using a translation
transform. You want to plot these values in order to get a
feeling on the level of noise of the Metric, the presence
of local minima, and the overall reproducibility of the Metric
function itself. (you will have to convert the dimension
to 3D, since the example was configured for 2D)
Please run this program first using the *same* input image
as fixed and moving images, and let the translation be
evaluated for a range that is close to 1/2 of the image extent
(physical extent in millimeters).
Plot the values using your favorite plotting program. (anything
from GNUPlot to Excel).
For examples on how these plot will look like, please take
a look at the course in Image Registration:
http://www.cs.rpi.edu/courses/spring04/imagereg/
In particular, look at lectures 8 and 9.
[...] It is not productive to fight with the registration optimization
until you find a way of generating relatively smooth Metric plots.
Note that this is just an exercise on learning how to tune the
parameters. Once you figure out the parameters, you will not need
to plot the Metric anymore.
Make sure that origin and spacing are correctly set in your images
before you start computing all these metric plots."
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkMattesMutualInformationImageToImageMetric.h"
#include "itkTranslationTransform.h"
#include "itkLinearInterpolateImageFunction.h"
int main( int argc, char * argv[] )
{
if( argc < 3 )
{
std::cerr << "Usage: " << std::endl;
std::cerr << argv[0] << " fixedImage movingImage" << std::endl;
return 1;
}
const unsigned int Dimension = 2;
typedef unsigned char PixelType;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::Image< PixelType, Dimension > ImageType;
typedef itk::ImageFileReader< ImageType > ReaderType;
ReaderType::Pointer fixedReader = ReaderType::New();
ReaderType::Pointer movingReader = ReaderType::New();
fixedReader->SetFileName( argv[ 1 ] );
movingReader->SetFileName( argv[ 2 ] );
try
{
fixedReader->Update();
movingReader->Update();
}
catch( itk::ExceptionObject