[Insight-users] affine transform without scaling?

Darren Weber darren.weber.lists at gmail.com
Fri Nov 6 13:14:10 EST 2009


Hi Luis,

This is interesting and helpful, thank you!  For reference, your prior post
here is also helpful:
http://www.itk.org/pipermail/insight-users/2007-April/021781.html

In the present application, the inputs are 2D images (each image does have a
world-coordinate depth of 0.5 microns, but there are no more than 1 data
sample in that dimension; a fudge might be to replicate each slice to
provide 2 slices, or to use consecutive slices to create at least a minimal
3D volume of 2 slices, giving a 1.0 micron Z dim).  It may be useful to
constrain the transform to the 2D plane (a slightly less desirable solution
may be to extract only the 2D components from the final transform of the 3D
registration solution).

On further thought about my prior comments, the separation of affine
components requires more parameters for the registration method.  The
composition of the components in a registration optimization (using
itk::AffineTransform::ComputeMatrixParameters()) would solve the affine
transform without providing the optimized parameters for each of the
rotation, translation, skew, and scale components.

Kind regards,
Darren



On Fri, Nov 6, 2009 at 4:27 AM, Luis Ibanez <luis.ibanez at kitware.com> wrote:

> Hi Darren,
>
> The class
>
>            itkScaleSkewVersor3DTransform.h
>
> may be what you are looking for.
>
> However, please note that the separation of the terms may
> not be as mathematically clean as one would wish.
>
> Also, regarding the second point of your email, we could no
> generate compilation errors by using the ConceptChecking
> classes.
>
> They are defined in
>
>            Insight/Code/Common/itkConceptChecking.h
>
> See for example:
>
> "SameDimension" in line 535    and
> "SameDimensionOrMinusOne" in line 650
>
> For examples of their use, please see the file
>
>    Insight/Code/BasicFilters/itkOrientImageFilter.h
>
> for example:
>
>  itkConceptMacro(DimensionShouldBe3,
>
>  (Concept::SameDimension<itkGetStaticConstMacro(InputImageDimension),3>));
>
>
> Now that ... for the case that you mention, we may
> have to create a new concept, of the sort:
>
>      DimensionLargerThan...
>
>
>
>    Regards,
>
>
>          Luis
>
>
> --------------------------------------------------------------------
> On Mon, Nov 2, 2009 at 2:09 PM, Darren Weber
> <darren.weber.lists at gmail.com> wrote:
> >
> > Hi Luis et al.,
> >
> > In my understanding of itkAffineTransform, there is no (easy or direct)
> way
> > to separate out the rotation, scaling, and shearing components of the
> > transform, because we only have itkAffineTransform::GetMatrix().  In a
> prior
> > email of this thread, I had commented that rotation might be extracted
> from
> > the Rotate* methods, but that is not so (those methods are for pre/post
> > compositions).  If it were possible to get the rotation component (say 2D
> > transform, call this R), the following should provide a scaling component
> > (call this S; the following uses Matlab syntax):
> >
> > A = S * R;
> > S = [ a 0; 0 b ];
> > R = [ cos(theta)  -sin(theta);  sin(theta)  cos(theta)];
> > S = A * inv(R);
> > % where inv(R) = [ cos(theta)  sin(theta);  -sin(theta)  cos(theta)];
> >
> > Anyhow, has anyone tried to re-write itkAffineTransform.txx so that the
> > rotation, scaling, and shearing matrix are stored in separate private
> data
> > members?  (This is beyond my current abilities to create quickly with
> > confidence.)  If this is possible, it would provide the potential for
> > methods like GetRotation(), GetShearing(), GetScaling() and the
> equivalent
> > Set methods (which might become easier or clearer than the current
> methods
> > for Scale(), Rotate(), etc.).  If this were done, the
> > ComputeMatrixParameters() method may compose the private members for the
> > rotation, scaling, and shearing matrices (to provide the composition for
> > registration methods and thereby "decrease" the parameter dimension for
> > efficiency).  Does that make sense?  Is this a complex issue due to the
> > inheritance of itkAffineTransform from MatrixOffsetTransformBase?
> >
> > Also, what additional functionality does itkScalableAffineTransform
> provide
> > beyond itkAffineTransform::Scale()?
> >
> > Take care,
> > Darren
> >
> >
> >
> > BTW, at about line 196 of itkAffineTransform.txx (ITK 3.16.0; similarly
> for
> > Rotate3D method at 226), there is a TODO item:
> >
> > /** Compose with 2D rotation
> >  * \todo Find a way to generate a compile-time error
> >  * is this is used with NDimensions != 2. */
> > template<class TScalarType, unsigned int NDimensions>
> > void
> > AffineTransform<TScalarType, NDimensions>
> > ::Rotate2D(TScalarType angle, bool pre)
> >
> >
> > Would a change to the following provide the compile time error required?
> >
> > /** Compose with 2D rotation
> > template<class TScalarType, 2>
> > void
> > AffineTransform<TScalarType, 2>
> > ::Rotate2D(TScalarType angle, bool pre)
> >
> >
> >
> >
> >
> >
> >
> >
> >
> >
> > On Sun, Nov 1, 2009 at 3:35 PM, Luis Ibanez <luis.ibanez at kitware.com>
> wrote:
> >>
> >> Hi Darren,
> >>
> >> For an Affine transform in 2D, the GetParameters() will return an
> >> array with six elements, where the first four are the coefficients
> >> of the rotation (and scaling and shearing) matrix, and the last
> >> two elements are the components of the translation.
> >>
> >> This is described in the Doxygen documentation of this class:
> >>
> >>
> http://public.kitware.com/Insight/Doxygen/html/classitk_1_1AffineTransform.html
> >>
> >> <quote>
> >>
> >> "This class provides several methods for setting the matrix and vector
> >> defining the transform. To support the registration framework, the
> >> transform parameters can also be set as an Array<double> of size
> >> (NDimension + 1) * NDimension using method SetParameters(). The first
> >> (NDimension x NDimension) parameters defines the matrix in row-major
> >> order (where the column index varies the fastest). The last NDimension
> >> parameters defines the translation in each dimensions."
> >>
> >> </quote>
> >>
> >>
> >>      Regards
> >>
> >>
> >>             Luis
> >>
> >>
> >>
> >>
> ------------------------------------------------------------------------------
> >> On Fri, Oct 30, 2009 at 7:09 PM, Darren Weber
> >> <darren.weber.lists at gmail.com> wrote:
> >> >
> >> > For a 2D affine transform, what are the parameters returned by
> >> > GetParameters?
> >> >
> >> > Thanks,
> >> > Darren
> >> >
> >> >
> >> >
> >> >
> >> >
> >> >
> >> > On Mon, Oct 26, 2009 at 12:17 PM, Darren Weber
> >> > <darren.weber.lists at gmail.com> wrote:
> >> >>
> >> >>
> >> >> On Sun, Oct 25, 2009 at 2:50 PM, Richard Beare
> >> >> <richard.beare at gmail.com>
> >> >> wrote:
> >> >>>
> >> >>> Hi,
> >> >>>
> >> >>> My solution to a similar problem was to use the similarity transform
> >> >>> and throw away the scale component. In my data (marmoset brain
> >> >>> sections) there was enough change in size between adjacent slices to
> >> >>> make the more complex transform necessary. Without it the
> registration
> >> >>> had a range of equivalent and wrong solutions - consider registering
> >> >>> two discs of different sizes. Most metrics will consider all
> solutions
> >> >>> with the small one inside the big one as equivalent, but you're
> >> >>> probably going to want the one with the discs centres aligned.
> >> >>>
> >> >>
> >> >> I see, so the registration metrics worked better using the similarity
> >> >> transform than a rigid transform, but you get a rigid transform once
> >> >> you
> >> >> throw out the scale from the similarity transform.  The similarity
> >> >> transform
> >> >> is required for a more effective registration.  My problem is very
> >> >> similar,
> >> >> but using an affine transform (I do want to keep the shear transform
> >> >> component, which is not available in the similarity transform).
> >> >>
> >> >>
> >> >>>
> >> >>> So I can see a couple of options - try using the simularity
> transform
> >> >>> as your bulk transform and then turn of the scale later. (did you
> find
> >> >>> a nice way of composing bsplines?)
> >> >>
> >> >> There are some options to look at later for the bspline composition
> >> >> (see
> >> >> Luis' comments in the previous email thread;  I'm not clear that it's
> >> >> easily
> >> >> applied to my problem and I don't have time to look into the details
> >> >> right
> >> >> now).  The bspline is conditioned using an affine as the bulk
> >> >> transform, so
> >> >> the scale issue needs to be addressed in the affine (or other bulk
> >> >> transform
> >> >> and possibly again in the bspline too).  The affine itself is
> >> >> initialized
> >> >> using a centered transform (of some kind; probably a center of mass
> >> >> metric
> >> >> and a translation transform).
> >> >>
> >> >> typedef itk::CenteredTransformInitializer< TransformType,
> >> >> bwInputImageType, bwInputImageType > TransformInitializerType;
> >> >> TransformInitializerType::Pointer initializer =
> >> >> TransformInitializerType::New();
> >> >> initializer->SetTransform( affineTransform );
> >> >> initializer->SetFixedImage(  bwFixInfoFilter->GetOutput() );
> >> >> initializer->SetMovingImage( bwMovInfoFilter->GetOutput() );
> >> >> initializer->MomentsOn();
> >> >> initializer->InitializeTransform();
> >> >>
> >> >>
> >> >>
> >> >>>
> >> >>> Or
> >> >>>
> >> >>> There are ways of decomposing the affine transform matrix into
> shift,
> >> >>> rotation, shear and scale components - from memory the publications
> >> >>> relating to flirt (the fsl registration tool) discussed this, and it
> >> >>> is probably available elsewhere.
> >> >>>
> >> >>
> >> >> I've FLIRT many times in human brain imaging work, but I assume it
> will
> >> >> not work with the RGB images of the microscopy data (and I prefer to
> >> >> work
> >> >> with ITK on this project).  The approach that I've taken is partly
> >> >> based on
> >> >> prior experience with FLIRT and similar registration tools for brain
> >> >> imaging
> >> >> (fMRI), where a series of pair-wise transforms can be calculated in
> >> >> parallel
> >> >> and applied later using a composition.  I didn't anticipate the scale
> >> >> problem in the composition for the data in this project.  (Perhaps
> the
> >> >> FLIRT
> >> >> command line has tools for decomposition of the transform matrix, but
> I
> >> >> want
> >> >> to do this with ITK.)
> >> >>
> >> >> In previous work that required understanding a transform matrix, it
> >> >> appeared that there are no obligatory standards on how to shape the
> >> >> matrix
> >> >> (probably depends on whether the matrix is pre-multiplied or
> >> >> post-multiplied
> >> >> in specific applications).  The elements of the matrix should have a
> >> >> known
> >> >> role in the affine transform, some for rotation, translation, etc.
> The
> >> >> specifics of the implementation in ITK are important (the
> registration
> >> >> provides a transform from fixed-to-moving image).
> >> >>
> >> >> There are some general online resources on affine transform matrices:
> >> >> http://en.wikipedia.org/wiki/Affine_transformation
> >> >> http://mathworld.wolfram.com/AffineTransformation.html
> >> >>
> >> >> Some libraries use specific methods for each component: translation,
> >> >> rotation, shear, scale.
> >> >>
> >> >> For example, in java 1.2:
> >> >> http://www.glyphic.com/transform/imageonly/1intro.html
> >> >>
> >> >> Also here in the Apple core graphics lib, there are methods for each
> >> >> component of the transform:
> >> >>
> >> >>
> >> >>
> http://opensource.apple.com/source/WebCore/WebCore-4A102/platform/AffineTransform.h
> >> >> That is,
> >> >>
> >> >>     AffineTransform &scale(double sx, double sy);
> >> >>     AffineTransform &rotate(double d);
> >> >>     AffineTransform &translate(double tx, double ty);
> >> >>
> >> >>
> >> >>     AffineTransform &shear(double sx, double sy);
> >> >>
> >> >> In this page you can see a decomposition of a 2D affine matrix into
> the
> >> >> rotation, shear, scaling, and translation:
> >> >>
> >> >>
> >> >>
> http://www.gnome.org/~mathieu/libart/libart-affine-transformation-matrices.html<http://www.gnome.org/%7Emathieu/libart/libart-affine-transformation-matrices.html>
> >> >> Note the method to extract a scale factor, called
> >> >> art_affine_expansion().
> >> >> When the matrix is represented in it's component parts, it is trivial
> >> >> to
> >> >> "knock out" the scaling component by setting the diagonal elements of
> >> >> the
> >> >> scale matrix to 1.0.
> >> >>
> >> >> However, ITK doesn't appear to represent the matrix in component
> parts.
> >> >> My current project work is using 2D images and ITK 3.16,
> >> >> http://www.itk.org/Doxygen316/html/classitk_1_1AffineTransform.html
> >> >>
> >> >> There seem to be some specific methods to get/set the affine
> components
> >> >> (translation or offset, rotate2D, rotate3D, etc. - maybe no shear
> >> >> method?),
> >> >> but there are general get/set matrix methods, so perhaps it is
> possible
> >> >> to
> >> >> use something like:
> >> >>
> >> >> MatrixType thisMatrix = affineTFM->GetMatrix();
> >> >> // modify thisMatrix to remove scale component
> >> >> affineTFM->SetMatrix(thisMatrix);
> >> >>
> >> >>
> >> >> The trick is knowing which elements of the matrix contain the scale
> >> >> factor(s).  Perhaps it is the diagonal elements, as in:
> >> >>
> >> >>
> >> >>
> http://www.gnome.org/~mathieu/libart/libart-affine-transformation-matrices.html<http://www.gnome.org/%7Emathieu/libart/libart-affine-transformation-matrices.html>
> >> >>
> >> >> If so, the diagonal elements of the 'composed' matrix contain both
> >> >> rotation and scaling components.  Perhaps it is possible to isolate
> the
> >> >> scale component from the rotation component with some help from the
> ITK
> >> >> get/set rotation2D methods?  If that can be done, then it should be
> >> >> easy to
> >> >> replace the diagonal of the full affine matrix with just the diagonal
> >> >> elements from the rotation matrix, to effectively remove the scaling
> >> >> component from the diagonal of the 'composed' matrix (and leave
> >> >> everything
> >> >> else alone).
> >> >>
> >> >> Does that make sense?  Has anyone done this before?
> >> >>
> >> >> Best regards,
> >> >> Darren
> >> >>
> >> >>
> >> >>
> >> >>
> >> >>
> >> >>>
> >> >>> On Sun, Oct 25, 2009 at 2:16 PM, Darren Weber
> >> >>> <darren.weber.lists at gmail.com> wrote:
> >> >>> >
> >> >>> >
> >> >>> > On Sat, Oct 24, 2009 at 7:58 PM, Darren Weber
> >> >>> > <darren.weber.lists at gmail.com>
> >> >>> > wrote:
> >> >>> >>
> >> >>> >> Is there an easy way to turn off the scaling component of an
> affine
> >> >>> >> transform?
> >> >>> >>
> >> >>> >> Is there a method in itkAffineTransform to set the scale
> component
> >> >>> >> to
> >> >>> >> a
> >> >>> >> constant?
> >> >>> >>
> >> >>> >> Would you manually pull out the matrix, etc., modify it and then
> >> >>> >> reset
> >> >>> >> it
> >> >>> >> in the itkAffineTransform?
> >> >>> >>
> >> >>> >> TIA,
> >> >>> >> Darren
> >> >>> >>
> >> >>> >
> >> >>> > PS,  Maybe a geometric problem can help (or obscure) the problem.
> >> >>> > Imagine a
> >> >>> > series of conic sections, starting at the tip of a cone and
> working
> >> >>> > down
> >> >>> > toward the base.  Each of these 2D conic sections needs to be
> >> >>> > registered
> >> >>> > into a 3D volume to recreate the cone.  If each section were a
> >> >>> > "pure"
> >> >>> > section taken along the axis from the tip to the center of the
> base,
> >> >>> > this
> >> >>> > would be fairly trivial as a rigid-body registration (probably no
> >> >>> > registration at all is required, just a known sequence of slices).
> >> >>> > However,
> >> >>> > assume each section has an unknown deformation (but the series of
> >> >>> > sections
> >> >>> > is given in a known order).  If the affine registration starts at
> >> >>> > the
> >> >>> > tip
> >> >>> > (img001) and propagates all the way to the base (img100), the
> final
> >> >>> > diameter
> >> >>> > of the base section will be decreased to about the same diameter
> as
> >> >>> > the
> >> >>> > tip.
> >> >>> >
> >> >>> > The real problem is a series of microscopy images for a worm,
> which
> >> >>> > has
> >> >>> > a
> >> >>> > smaller diameter at the head and tail than in the body.
> >> >>> >
> >> >>> >
> >> >>> > _____________________________________
> >> >>> > Powered by www.kitware.com
> >> >>> >
> >> >>> > Visit other Kitware open-source projects at
> >> >>> > http://www.kitware.com/opensource/opensource.html
> >> >>> >
> >> >>> > Please keep messages on-topic and check the ITK FAQ at:
> >> >>> > http://www.itk.org/Wiki/ITK_FAQ
> >> >>> >
> >> >>> > Follow this link to subscribe/unsubscribe:
> >> >>> > http://www.itk.org/mailman/listinfo/insight-users
> >> >>> >
> >> >>> >
> >> >>
> >> >
> >> >
> >> > _____________________________________
> >> > Powered by www.kitware.com
> >> >
> >> > Visit other Kitware open-source projects at
> >> > http://www.kitware.com/opensource/opensource.html
> >> >
> >> > Kitware offers ITK Training Courses, for more information visit:
> >> > http://www.kitware.com/products/protraining.html
> >> >
> >> > Please keep messages on-topic and check the ITK FAQ at:
> >> > http://www.itk.org/Wiki/ITK_FAQ
> >> >
> >> > Follow this link to subscribe/unsubscribe:
> >> > http://www.itk.org/mailman/listinfo/insight-users
> >> >
> >> >
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.itk.org/pipermail/insight-users/attachments/20091106/8f3df55f/attachment-0001.htm>


More information about the Insight-users mailing list