[Insight-users] Re: MultResMIRegistration using CT and US
Luis Ibanez
luis.ibanez@kitware.com
Wed, 15 May 2002 10:10:14 -0400
Hi Jon,
A) About starting the registration with an
initial "offset", this can easily be done
with the method:
SetInitialTransformParameters();
This methods receives an itkArray with the set of
values that define the initial transformation applied
to the moving image. This is like serializing the
values that fully define a transform. For the particular
case of the itkAffineTransform, the parameters are arranged
as follows:
1) the matrix is stored line by line in the array
2) the offset of the transform (translation component)
is put at the end of the array of parameters.
You may see the details on :
Insight/Code/Common/itkAffineTransform.txx: line 578
in the "GetParameters()" method, as well as line 611
in the "SetParameters()" method.
B) About getting feedback from the execution
of the registration method:
ITK has a mechanism for communicating with other
pieces of software. It is based on the
Command/Observer design pattern. It similar to
the concept of Observers in Java.
You can use this mechanism in order to get
information about the progresion of the registration
method. (and about the state of any ITK filter too)
Here is a brief description of how it
works:
1) There is a hierarchy of ITK "Events"
that you can find defined in :
Insight/Code/Common/itkEventObject.h
in particular after line 132.
2) itkObjects can send these events in
order to notify others about their
internal state. For example, every
ITK filter sends a "StartEvent" when
it starts excecution. They also send
"UpdateProgress" events every once in
a while so you can for example update
a progress bar in a GUI. (an example
of this can be seen in:
http://www.itk.org/HTML/GaussianFilter.htm
3) In order to catch this events you can
setup "Observers" which in ITK have
been defined following the "Command"
design pattern. Observers register
themselves with an itkObject and declare
its interest on being notified when a
particular event happens. Given that
events are organized in a hierarchy,
an observer can register for a particular
event in the hierarchy and it will be
notified for this event and all of its
subclasses. (pretty much as Exceptions
work in C++ and Java).
4) The Event that you may be interested on
is the "IterationEvent". This event is
sent by Optimizers at each iteration.
The execution of the registration method
is driven by its optimizer.
5) By writing a customized observer/command
class and registering with the Registration
method class you can make sure that a method
or function that you define will be called
at each iteration. In this function you
may want to query the Registration method
and for example print data to the standard
output, write it to a file or update a GUI.
6) For the MultiResolution registration example
that you are using now, you will see that
an Observer is defined in the file:
Insight/Examples/MultiResMiRegistration/Common
MIMRegistrator.txx
It is in line: 57
typename CommandType::Pointer command = CommandType::New();
a callback function is attached to this command in line 58:
command->SetCallbackFunction( this, &Self::StartNewLevel );
In this particular case, the callback can be a member method
of a class.
There is a variety of Command classes that you may use.
They are defined in: Insight/Common/itkCommand.h
Some of them execute actions themselves, others are intended
to delegate execution to C++ methods, others allow you to
call plain C functions.
7) In the case of the example, you will find that
the command is delegating to the C++ method:
StartNewLevel() implemented in line : 179.
So, If you want more information about the state
of the Registration, you can modify this method,
or create your own customized Command class.
8) Note that because this is the Multiresolution
Registration method, an Iteration of this class
corresponds to a full execution of a registration
for one level of the pyramid. That may be too
high level for what you are trying to do now,
which is figure out good values for the learning
rates.
9) You may want to go a level lower and get the optimizer
that is used by the registration method. Plug an
observer to the "IterationEvent" on this optimizer
and define a callback that will print the status of
the optimizer. You can see examples of this in the
Testing directory:
Insight/Testing/Code/Algorithms/itkImageRegistrationTest_*.cxx
a Command helper class is defined in:
Insight/Testing/Code/Algorithms/itkCommandIterationUpdate.h
10) In order to get the current optimizer from inside the
MIMRegistrator.txx file you can do something like add
around line 60 the following code:
m_Registration->GetOptimizer()->AddObserver(
IterationEvent(),myCommand);
And declare "myCommand" like in the itkCommandIterationUpdate.h used
in Testing.
This combination will print to std::cout the values of the
transform parameter at each iteration of the optimizer.
By following the progression of these values you can figure
out the appropriated values for the LearnigRates.
Please let us know if you encounter any problem,
Thanks
Luis
==================================
Jon Harald Kaspersen wrote:
> Hi again Luis,
>
> Thanks for making things a lot clearer !!
>
> I have no problem with copying these mails to the user list.
>
> I have started the iterative procedure to find a set of parameters that
> suits my data.
> Some additional questions comes to my mind.
>
> 1. Does the standard output give any information about how much the
> source data moves between iterations or levels ? I guess that little
> movement between iterations means that the data is quite close, or a
> good registration has been found ?
>
> 2. My data is from the abdomen (in fact from patients with abdominal
> aortic aneurysms). The CT scan covers a much bigger part of the body
> than the US. Is there a way to "offset" the US, a sort of a starting
> point for the iteration ? I could of cause just use the overlapping data
> regions in the axial direction and cut away the CT data that is not
> covered by the US.
>
> Regards
> Jon