[Insight-users] MultiResMIRegistration - QuaternionRigid 2 Affine
(3)
Luis Ibanez
luis.ibanez at kitware.com
Mon, 22 Mar 2004 18:11:43 -0500
Hi Christos,
You are right, I overlooked the fact that you are using
the code of the MultiResMIRegistration application, and
this application already takes care of repositioning the
image origins. So, you don't really need the CenteredAffine
transform or the CenteredTransformInitializer in this case.
If you already managed to register for translation and
orientation, what you can do now is to take the resulting
parameters of your current registration and multiply all
the components in the Matrix (not in the translation vector)
with a values representing the expected scaling. Notice
that the transform is the one mapping coordinates from the
fixed image (MRI) to the moving image (your OT). So you
probably want to multiply by a value such as 0.8 or 0.7.
Also, in order to disable the translations you can use a
translation scaling vector with large values for the
components of the translation vector (components 10, 11
and 12). You could set them to 10.0 for example. This
will result in those components being attenuated during
the optimization cycle.
Note that you could also (in this second run), replace the
AffineTransform with the ScaleTransform and focus exclusively
in scaling the image. For this purpose it may be more convenient
to use the resampled moving image resulting from the current
registration in which you already succeed in correcting for
translation and rotation.
When optimizing for scaling you have to keep in mind that
learning rates result in values being added to the scaling
parameters (not multiplied with them), so you don't want
to use any large step like "1.0" which in terms of scaling
means that you can initialize with scaling 1.0, and in the
next iteration try: 1.0 + 1.0 = 2.0 as scale factor, which
be too much of a sudden change.
Regards,
Luis
----------------------------
Christos Panagiotou wrote:
> Dear Luis
>
> In your previous response you ve suggested that i should use the
> centered affine transform for
> centering both volumes. As i said i try to modify the
> MultiResMIRegistration application
> which computes a pre-transform based on permutation and flipping input
> from the user...
> It also incorporates the use of a centerer which does the centering of
> the volumes before the
> actual registration begins. So i dont see the reason to use the centered
> affine as i dont want to
> explicitly set the center of rotation etc.
>
> Luis, I ve got the registration working... the volumes seem preety well
> aligned. What I haven't
> really managed to achieve is a substantial scaling effect in the moving
> volume (100x120x138).
> For example if i set by guess the initial parameters of the transform
> either i get a better feel that the volume has
> been scaled. If I leave this in the application, the affine
> transformation (using the info from the metric and the
> actions of the optimizer) cannot rescale automaticaly the volume so it
> would match the fixed one?
>
> Both volumes incorporate scull of the head which the metric should
> definately detect as mutual information due
> to the amount of similarity. Do i have explicitly to do something or is
> it just a matter of initial parameters, learning rates,
> standard deviations and other tunning parameters?
>
> Thanks again
> Christos
>
> Luis Ibanez wrote:
>
>>
>> Hi Christos,
>>
>> I was *not* suggesting you to change the values of
>> pixel spacing. On the contrary, what you want to do
>> is to make sure that your images have the correct
>> values of pixel spacing. The number on my previous
>> email were purely figurative, and were only there
>> for the sake of presenting an example.
>>
>>
>> *Do not change the values of pixel spacing*.
>>
>> Just, be aware of what they are and consider this
>> information when you attempt to initialize and drive
>> the registration process.
>>
>> You will get the translation for centering both
>> volumes from the CenteredTransformInitializer.
>>
>> --
>>
>> Before you go further, Please *stop* programming,
>> get some coffee and start reading the SoftwareGuide.
>>
>> http://www.itk.org/ItkSoftwareGuide.pdf
>>
>> That will save you from wasting time and going through
>> unnecessary suffering.
>>
>> The answer to your question about reslicing is described
>> in detail on the SoftwareGuide. Please read the section
>> on the ResampleImageFilter:
>>
>> Section 6.7.1, pdf-page 199.
>>
>>
>> You may want to run the associated examples
>> available in:
>>
>> Insight/Examples/Filtering
>>
>>
>> Then read the Registration chapter:
>>
>> Chapter 8, pdf-page 241.
>>
>>
>> in particular, Centered Transforms are
>> discussed in:
>>
>>
>> Section 8.5, pdf-page 263.
>>
>>
>>
>> Almost all the examples on image registration
>> show how to resample the moving image using
>> the resulting transform. This code is
>> available in
>>
>>
>> Insight/Examples/Registration
>>
>>
>>
>>
>>
>> Regards,
>>
>>
>>
>> Luis
>>
>>
>>
>> --------------------------
>> Christos Panagiotou wrote:
>>
>>> Dear Luis
>>>
>>> I see what you mean...
>>> The MRI volume has 256 X 256 x 136 slices... and in the header file
>>> its said that the voxel spacing is 1.0x1.0x1.0 mm
>>>
>>> The OT volume does not provide info about its spacing however
>>> i was adviced to place it in 1.0x1.0x1.0 as well..
>>>
>>> What i dont get is that if i set the spacing of the MRI volume to
>>> 0.5x0.5x1.0
>>> am I not going to alter its information by "compressing" it on x and y?
>>>
>>> What I was expecting was to center both volumes and using information
>>> from the metric (MI image2image metric) the moving volume would expand
>>> accordingly to x y z to until convergence or until iterations have
>>> reached an end...
>>>
>>> What I mean is by changing the voxel spacing in only 2 axis I would
>>> force a change to the aspect ratio of the volume.
>>> If I do this then the moving image would register to a volume that
>>> does not correspond to reality
>>> I thought I could leave this part to the metric to decide how it can
>>> change the aspect ratio of the moving volume
>>> accordingly, to fit the fixed volume.
>>>
>>> Please enlighten me :)
>>> I see what you mean however i ll try to do this and see the results!
>>>
>>> thanks for your help - much appreciated
>>>
>>> p.s. luis, one more question, how could i reslice the volumes so i
>>> could see the achieved registration in 2D slices?
>>> lets say, after the registration when both have reached a similar
>>> size, to be able and change both of them
>>> to similar dimensions (i.e. 256x256x136 with 1.0mm spacing in all
>>> directions)
>>>
>>>
>>>
>>> Luis Ibanez wrote:
>>>
>>>>
>>>> Hi Christos,
>>>>
>>>> Registration in ITK is done in Physical coordinates.
>>>> You must think in terms of millimeters instead of
>>>> thinking in terms of number of pixels. A pixel is
>>>> not a unit of measurement.
>>>>
>>>> The actual size of your images is computed by multiplying
>>>> the number of pixels along each side of the image by the
>>>> pixel spacing in millimeters.
>>>>
>>>> For example, your MRI image has number of pixels =
>>>>
>>>> 256 X 256 x 136
>>>>
>>>> and it should have pixel spacing of something like
>>>>
>>>> 0.5mm X 0.5mm X 1.0mm
>>>>
>>>> ( or probably you are lucky enough to have better
>>>> resolution that can match the pixel spacing of
>>>> the optical tomography volume.)
>>>>
>>>>
>>>> The physical extent of the MRI image is then:
>>>>
>>>> 128.0 mm X 128.0 mm X 136 mm
>>>>
>>>>
>>>> That's the dimension that you should have in mind when
>>>> reasoning about the relative size of the images.
>>>>
>>>> What is the pixel spacing of your optical tomography
>>>> image ?
>>>>
>>>> Please compute the physical extent of the OT image...
>>>>
>>>> What is the origin of the MRI image ?
>>>>
>>>> What is the origin of the OT image ?
>>>>
>>>>
>>>>
>>>> Note that if the pixel spacing of the OT image is
>>>> calibrated correctly, there is no reason why you
>>>> should be expecting any scaling. The pixel spacing
>>>> in the image should provide a natural scaling between
>>>> the image grid and the physical space.
>>>>
>>>>
>>>> Regarding the use of the GradientDescentOptimizer
>>>> versus the RegularStepGradientOptimizer, their
>>>> selection depends on how noisy the image metric
>>>> is. You cannot simply generalize a statement such
>>>> as "one is faster than the other". There are many
>>>> circumstances that will determine the performance
>>>> of each one.
>>>>
>>>>
>>>> You may find useful to look at the two following
>>>> presentations:
>>>>
>>>>
>>>> http://www.cs.rpi.edu/courses/spring04/imagereg/lecture07.ppt
>>>> http://www.cs.rpi.edu/courses/spring04/imagereg/lecture08.ppt
>>>>
>>>>
>>>>
>>>>
>>>> Regards,
>>>>
>>>>
>>>>
>>>> Luis
>>>>
>>>>
>>>>
>>>> ------------------------------------------------
>>>> Christos Panagiotou wrote:
>>>>
>>>>> guys
>>>>>
>>>>> i am sorry for writing the third consecutive email without waiting
>>>>> the answers for the other two...
>>>>> i need to ask something about scaling (not the translation scale
>>>>> factor) in the affine transformation.
>>>>>
>>>>> I register the two volumes from different modalities using the
>>>>> MultiResMIRegistration which has been altered
>>>>> and does not use quaternionRigidT but AffineT. Also the optimizer
>>>>> now is RegularStepGradientDescent.
>>>>>
>>>>> The first volume (MRI) is 256x256x136 and the second volume is
>>>>> 100x120x138 (Optical Tomography).
>>>>> After the registration completes the volumes seem aligned enough.
>>>>> Substantial translation has taken place however I dont see any
>>>>> substantial scaling of the smaller volume
>>>>> to reach at least a size similar to the fixed one. The output of
>>>>> the application is the following:
>>>>>
>>>>> Final parameters: [0.99324, 0.00293927, 0.00176662, 0.00253656,
>>>>> 0.998594, -0.000835126, 0.00168811, -0.00157159, 0.992728, 1.62397,
>>>>> 3.78007, 1.85686]
>>>>> Overall transform matrix:
>>>>> 0.00168811 -0.00157159 0.992728
>>>>> -0.99324 -0.00293927 -0.00176662
>>>>> 0.00253656 0.998594 -0.000835126
>>>>>
>>>>> Overall transform offset:
>>>>> -15.6672 185.008 -55.3077
>>>>>
>>>>> The code I use is the one found in the MIMRegistration.txx in the
>>>>> MultiResMiRegistration application
>>>>>
>>>>> // Default parameters
>>>>> m_NumberOfLevels = 1; //value from parameter file is 4
>>>>> m_TranslationScale = 1.0; //value from parameter file is around 300
>>>>> m_MovingImageStandardDeviation = 0.4;
>>>>> m_FixedImageStandardDeviation = 0.4;
>>>>> m_NumberOfSpatialSamples = 50;
>>>>>
>>>>> m_FixedImageShrinkFactors.Fill( 1 ); // shrink factor values come
>>>>> from parameter file - these are skipped
>>>>> m_MovingImageShrinkFactors.Fill( 1 );
>>>>>
>>>>> m_NumberOfIterations = UnsignedIntArray(1);
>>>>> //Set elements of the array to the specified value
>>>>> m_NumberOfIterations.Fill( 10 ); // from parameter file values are
>>>>> 2000 iterations per level
>>>>>
>>>>> m_LearningRates = DoubleArray(1);
>>>>> m_LearningRates.Fill( 1e-4 ); //updated from parameter file
>>>>>
>>>>> m_InitialParameters = ParametersType(m_Transform->GetParameters());
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> template <typename TFixedImage, typename TMovingImage>
>>>>> MIMRegistrator<TFixedImage,TMovingImage>
>>>>> ::~MIMRegistrator()
>>>>> {
>>>>> m_Registration->RemoveObserver( m_Tag );
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> template <typename TFixedImage, typename TMovingImage>
>>>>> void
>>>>> MIMRegistrator<TFixedImage,TMovingImage>
>>>>> ::Execute()
>>>>> {
>>>>>
>>>>> // Setup the optimizer
>>>>> typename OptimizerType::ScalesType scales(
>>>>> m_Transform->GetNumberOfParameters() );
>>>>> scales.Fill(1.0)
>>>>> for ( int j = 9; j < 12; j++ )
>>>>> {
>>>>> scales[j] = m_TranslationScale;
>>>>> }
>>>>>
>>>>> m_Optimizer->SetScales( scales );
>>>>> m_Optimizer->SetMaximumStepLength(1);
>>>>> m_Optimizer->SetMinimumStepLength(0.005 );
>>>>> m_Optimizer->MaximizeOn();
>>>>>
>>>>> // Setup the metric
>>>>> m_Metric->SetMovingImageStandardDeviation(
>>>>> m_MovingImageStandardDeviation );
>>>>> m_Metric->SetFixedImageStandardDeviation(
>>>>> m_FixedImageStandardDeviation );
>>>>> m_Metric->SetNumberOfSpatialSamples( m_NumberOfSpatialSamples );
>>>>>
>>>>> // Setup the image pyramids
>>>>> m_FixedImagePyramid->SetNumberOfLevels( m_NumberOfLevels );
>>>>> m_FixedImagePyramid->SetStartingShrinkFactors(
>>>>> m_FixedImageShrinkFactors.GetDataPointer() );
>>>>>
>>>>> m_MovingImagePyramid->SetNumberOfLevels( m_NumberOfLevels );
>>>>> m_MovingImagePyramid->SetStartingShrinkFactors(
>>>>> m_MovingImageShrinkFactors.GetDataPointer() );
>>>>>
>>>>> // Setup the registrator
>>>>> m_Registration->SetFixedImage( m_FixedImage );
>>>>> m_Registration->SetMovingImage( m_MovingImage );
>>>>> m_Registration->SetNumberOfLevels( m_NumberOfLevels );
>>>>>
>>>>> m_Registration->SetInitialTransformParameters( m_InitialParameters );
>>>>>
>>>>> m_Registration->SetFixedImageRegion(
>>>>> m_FixedImage->GetBufferedRegion() );
>>>>>
>>>>> try
>>>>> {
>>>>> m_Registration->StartRegistration();
>>>>> }
>>>>> catch( itk::ExceptionObject & err )
>>>>> {
>>>>> std::cout << "Caught an exception: " << std::endl;
>>>>> std::cout << err << std::endl;
>>>>> throw err;
>>>>> }
>>>>>
>>>>> the weird thing is that i tried the method with both
>>>>> gradientdescent and regularstepgradientdescent with 2000plus number
>>>>> of iterations per level and
>>>>> the regularStepGradientDescentOptimizer was faster than the
>>>>> gradientDescent. I ve read in the mailing list that this is not the
>>>>> case. Probably I do something very wrong
>>>>>
>>>>> I would appreciate any help on how to increase or implement (if i
>>>>> forget something major here) the scaling of the moving image using
>>>>> the affine transform.
>>>>> Is it the AffineTransform::Scale() method? and if it is how can it
>>>>> be used?
>>>>>
>>>>> sorry for the number of emails and questions - i appreciate your
>>>>> tolerance!
>>>>> thanks
>>>>> chris
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> Insight-users mailing list
>>>>> Insight-users at itk.org
>>>>> http://www.itk.org/mailman/listinfo/insight-users
>>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>>
>>
>