[Insight-users] Fine-registration gone wrong
Luis Ibanez
luis.ibanez at kitware.com
Sat, 21 Feb 2004 13:03:42 -0500
Hi Jeroen,
Thanks for sending such a detailed
description of your problem.
The first thing that you may want to
look at is the definition of the metric.
You are acquiring RGB images but when
reading you are converting them to
Grayscale, since into the code the
image type is being declared as:
itk::Image< float, 2 >
This means that at this moment you are
not taking advantage of the color
information available in your images.
ITK doesn't have image metrics specific
for RGB images, but nothing prevents you
from creating one.
If you consider that the graylevel version
of the images still contains enough information
for performing the registration you can simply
continue this way and start looking at the
registration parameters. Otherwise you can
implement a metric that takes advantage of the
particular characteristics of your images.
--
Can you describe in more detail the image
acquisition process from the microscope ?
The multiple images that you have are
associated to stacked layers of tissue,
like in confocal microscopy ?
Or are they intended to be placed one besides
the others in order to form a planar mosaic ?
(like in stitching...).
We see microscopy as an important application
field for ITK and we are quite interesting in
expanding support for the various microscopy
modalities that are in widely used today.
Please let us know about the geometrical
configuration of your images.
Thanks
Luis
---------------------
vanderLaak J. wrote:
> Hi all,
> Currently I'm trying to register a set of 50 images which were taken by
> transmitted light microscopy from serial histological sections
> (immunohistochemically stained for bloodvessels, without any
> counterstain). Sections were manually 'optically' (using the microscope
> stage) aligned as much as possible (including rotation). The result of
> this is a set of RGB images showing only the vascular wall in brown,
> which are already pretty well registered. I would like to have ITK do a
> fine-registration, preferably an affine-transform, to account for small
> stretches in the tissue. I tried various registration metrics,
> transforms and interpolators, and came up with the routine below, which
> produces good results for a number of the images. However, in some cases
> unpredictable (to me, at least ;-) behaviour occurs: although images are
> pretty close to good alignment the routine doesn't converge and produces
> results that are way off (I could send examples of these, but don't want
> to burden this list too much). Below is the code-fragment, and part of
> the output of the registration which produces incorrect results. My
> questions: is it possible to put a limit to the registration paramaters
> (e.g. x translation no more than 20 pixels). Does anyone have a clue
> what's wrong with my code (or images)? How does the registration deal
> with RGB images? Can I detect the procedure going wrong, in order to
> (worst case) keep the manual registration and continue registration with
> the next images? In the output I often see that the last metric value is
> not the smallest, why doesn't the registration process take the set of
> parameters with lowest (highest) metric????
> Regards,
> Jeroen
>
> Code:
> const unsigned int Dimension = 2;
> typedef float PixelType;
>
> typedef itk::Image< PixelType, Dimension > FixedImageType;
> typedef itk::Image< PixelType, Dimension > MovingImageType;
> typedef itk::CenteredAffineTransform< double, Dimension >
> TransformType;
> typedef itk::RegularStepGradientDescentOptimizer OptimizerType;
> typedef itk::NormalizedCorrelationImageToImageMetric< FixedImageType,
> MovingImageType > MetricType;
> typedef itk:: BSplineInterpolateImageFunction<MovingImageType,double>
> InterpolatorType;
> typedef itk::ImageRegistrationMethod<FixedImageType,MovingImageType >
> RegistrationType;
>
> MetricType::Pointer metric = MetricType::New();
> OptimizerType::Pointer optimizer = OptimizerType::New();
> InterpolatorType::Pointer interpolator = InterpolatorType::New();
> RegistrationType::Pointer registration = RegistrationType::New();
>
> registration->SetMetric( metric );
> registration->SetOptimizer( optimizer );
> registration->SetInterpolator( interpolator );
>
> TransformType::Pointer transform = TransformType::New();
> registration->SetTransform(transform);
>
> typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
> typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
> FixedImageReaderType::Pointer fixedImageReader =
> FixedImageReaderType::New();
> MovingImageReaderType::Pointer movingImageReader =
> MovingImageReaderType::New();
>
> fixedImageReader->SetFileName( argv[1] );
> movingImageReader->SetFileName( argv[2] );
>
> registration->SetFixedImage(fixedImageReader->GetOutput());
> registration->SetMovingImage(movingImageReader->GetOutput());
> fixedImageReader->Update();
>
> registration->SetFixedImageRegion(
> fixedImageReader->GetOutput()->GetBufferedRegion() );
>
> typedef itk::CenteredTransformInitializer<TransformType,
> FixedImageType,MovingImageType > TransformInitializerType;
> TransformInitializerType::Pointer initializer =
> TransformInitializerType::New();
>
> initializer->SetTransform(transform);
> initializer->SetFixedImage(fixedImageReader->GetOutput());
> initializer->SetMovingImage(movingImageReader->GetOutput());
> initializer->MomentsOn();
> initializer->InitializeTransform();
>
> std::cout << "Initial Transform Parameters " << std::endl;
> std::cout << transform->GetParameters() << std::endl;
>
> registration->SetInitialTransformParameters(
> transform->GetParameters() );
>
> typedef OptimizerType::ScalesType OptimizerScalesType;
> OptimizerScalesType optimizerScales(transform->GetNumberOfParameters()
> );
> const double translationScale = 1.0 / 1000.0;
>
> optimizerScales[0] = 1.0;
> optimizerScales[1] = 1.0;
> optimizerScales[2] = 1.0;
> optimizerScales[3] = 1.0;
> optimizerScales[4] = translationScale;
> optimizerScales[5] = translationScale;
> optimizerScales[6] = translationScale;
> optimizerScales[7] = translationScale;
>
> optimizer->SetScales( optimizerScales );
>
> optimizer->SetMaximumStepLength( .1 );
> optimizer->SetMinimumStepLength( 0.001 );
> optimizer->SetNumberOfIterations( 400 );
> optimizer->MinimizeOn();
>
> CommandIterationUpdate::Pointer observer =
> CommandIterationUpdate::New();
> optimizer->AddObserver( itk::IterationEvent(), observer );
>
> try
> { registration->StartRegistration(); }
> catch( itk::ExceptionObject & err )
> { std::cerr << "ExceptionObject caught !" << std::endl;
> std::cerr << err << std::endl;
> return -1; }
>
> OptimizerType::ParametersType finalParameters =
> registration->GetLastTransformParameters();
>
> const double finalRotationCenterX = finalParameters[4];
> const double finalRotationCenterY = finalParameters[5];
> const double finalTranslationX = finalParameters[6];
> const double finalTranslationY = finalParameters[7];
>
> const unsigned int numberOfIterations =
> optimizer->GetCurrentIteration();
> const double bestValue = optimizer->GetValue();
>
> std::cout << "Result = " << std::endl;
> std::cout << " Center X = " << finalRotationCenterX <<
> std::endl;
> std::cout << " Center Y = " << finalRotationCenterY <<
> std::endl;
> std::cout << " Translation X = " << finalTranslationX << std::endl;
> std::cout << " Translation Y = " << finalTranslationY << std::endl;
> std::cout << " Iterations = " << numberOfIterations << std::endl;
> std::cout << " Metric value = " << bestValue << std::endl;
>
>
> Ouput:
> Initial Transform Parameters
> [1, 0, 0, 1, 385.213, 286.714, 0.907753, -0.0524303]
> 0 -0.981916 [1.03616, -0.0124404, 0.00123626, 1.02807, 385.213,
> 286.714, 0.927529, 0.0333425]
> 1 -0.977545 [1.00046, 0.0363107, 0.00624682, 1.0067, 385.211,
> 286.713, 0.988304, 0.0799002]
> 2 -0.977815 [0.999092, 0.00879042, -0.00218918, 1.011, 385.21,
> 286.714, 0.953614, 0.10103]
> 3 -0.980874 [0.991963, -0.0173192, -0.00861846, 1.00402, 385.21,
> 286.715, 0.913292, 0.108212]
> 4 -0.980221 [0.995119, -0.0216787, -0.0217679, 0.994541, 385.21,
> 286.714, 0.877521, 0.0777477]
> 5 -0.980084 [1.00374, -0.0234345, -0.0352056, 0.987303, 385.209,
> 286.714, 0.868013, 0.0319443]
> 6 -0.979511 [1.00972, -0.0188327, -0.0443085, 0.979458, 385.207,
> 286.713, 0.865454, -0.015898]
> 7 -0.978891 [1.00964, -0.00596139, -0.048326, 0.971347, 385.205,
> 286.712, 0.871117, -0.0629617]
> ...
> 203 -0.969197 [1.4177, 0.383298, -0.0274694, 0.987543, 384.906,
> 286.44, 2.18153, -1.08256]
> 204 -0.969208 [1.41863, 0.383454, -0.0273697, 0.987456, 384.907,
> 286.441, 2.18077, -1.08345]
> 205 -0.969217 [1.4199, 0.383883, -0.0268136, 0.987596, 384.907,
> 286.441, 2.18039, -1.0831]
> 206 -0.969232 [1.42031, 0.384117, -0.0273033, 0.987269, 384.907,
> 286.441, 2.18001, -1.08439]
> Result =
> Center X = 384.907
> Center Y = 286.441
> Translation X = 2.18001
> Translation Y = -1.08439
> Iterations = 208
> Metric value = -0.969233
> _______________________________________________
> Insight-users mailing list
> Insight-users at itk.org
> http://www.itk.org/mailman/listinfo/insight-users
>