[Insight-developers] OrientedImage and gradient calculations

Luis Ibanez luis.ibanez at kitware.com
Fri Mar 24 11:02:50 EST 2006


Jim, Stephen,

We should avoid using virtual functions for this
conversion because virtual functions do not get inlined.

The conversions between Indexes / Local Points / Physical Points
are critical for the performance of the registration framework.

These functions are called *millions of times* per iteration of
the registration optimizer.

Polymorphism at this point may be too costly and may hinder
what has been gained by the use of template meta programming.

I don't see too much of a problem in adding this operations
to a helper class that is friend of the Image. The helper class
would play about the same role as the ImageCalculators or the
TransformInitializers.


    Luis



--------------------------------------
Miller, James V (GE, Research) wrote:
> Stephen,
> 
> I think of it as follows:  the PixelContainer class is really the 
> data container. The Image places that container in context.
> 
> If we factored out these coordinate manipulations, 
> 
> 1) would Image still store spacing, origin, and directions?
> 2) could you write an algorithm (say a registration) abstractly
>     such that if an image did not have/use orientations (like 
>     Image does not) the (new) external transformation functions 
>     would take into account just spacing, and if an image did 
>     have/use orientations(like OrientedImage does) the (new)
>     external transformation functions would take
>     into account spacing, origin, and orientation?
> 
> 
> This actually brings up another issue.  Currently, the methods
> 
>     A) TransformPhysicalPointToContinuousIndex()
>     B) TransformContinuousIndexToPhysicalPoint()
> 
> are templated over the coordinate representation.  As such they
> are not virtual.  This means that if you have an OrientedImage
> cast back to an Image, and you run a registration on that Image, 
> the registration will NOT take into account orientation. This is
> probably not good. It is understandable how this design came about
> because at the time the decision was made to have the methods
> TransformPhysicalPointToContinuousIndex, we did not have the 
> subclass OrientedImage.
> 
> Unfortunately, I don't think we can have a virtual templated member
> function. We also cannot "untemplate" this method and provide
> overloaded versions (for double and float coordinate representations)
> since that may break backward compatibility.  Someone may have code
> like
> 
>   mImage->TransformPhysicalPointToContinuousIndex<float>(index, point);
> 
> which would not compile if we "untemplated" the code. I also don't
> know whether we could now provide untempleted overloaded versions
> like
> 
>   virtual void TransformPhysicalPointToContinuousIndex( const ContinuousIndex<float, VImageDimension>&,
>                                                 Point<float, VImageDimension>&) const;
>   virtual void TransformPhysicalPointToContinuousIndex( const ContinuousIndex<double, VImageDimension>&,
>                                                 Point<double, VImageDimension>&) const;
> 
> since these overloaded versions probably conflict with the templated member
> function versions.  We could test this.
> 
> We could perhaps add new methods with slightly different names that do what we want 
> in term of polymorphism and change the implementations of the templated member function 
> versions to call the new virtual function versions.
> 
> Jim
> 
> 
> 
> -----Original Message-----
> From: Stephen R. Aylward [mailto:Stephen.Aylward at Kitware.com]
> Sent: Thursday, March 23, 2006 7:48 PM
> To: Luis Ibanez
> Cc: Miller, James V (GE, Research); Blezek, Daniel J (GE, Research);
> Insight-developers (E-mail)
> Subject: Re: [Insight-developers] OrientedImage and gradient
> calculations
> 
> 
> 
> I see the convenience of the transform in the image...and we've already 
> headed down that road with point transforms....but doesn't "proper" c++ 
> programming style suggest keeping itk::Image as a data container and 
> putting functions in appropriate classes?
> 
> Stephen
> 
> Luis Ibanez wrote:
> 
>>Hi Jim,
>>
>>
>>Adding a TransformIndexGradientToPhysicalGradient() to the itk::Image
>>sounds like a good idea. It sounds better than correcting inside
>>the filters because Gradient operations can be useful in the local
>>coordinate system for the purpose of performing operations such as
>>segmentation and feature detection.
>>
>>
>>The Image gradient that is computed by the Image Metrics is
>>produced by the GradientRecursiveGaussianImageFilter. This
>>filter already takes into account the image spacing. So the
>>proposed Image method
>>
>>      TransformIndexGradientToPhysicalGradient()
>>
>>doesn't need to apply any spacing correction... However, other gradient
>>filters may not be taking the spacing into account (something to double
>>check...).
>>
>>
>>As Jim pointed out, this problem will apply to all other filters
>>that compute gradients in the image, or higher order derivatives.
>>
>>
>>In the most generic case we should use a Metric Tensor for mapping
>>the derivatives from one space into the other. The reason why the
>>Tensor notation may be more appropriate is that for higher order
>>derivatives the Tensor has to be applied multiple times.
>>
>>Derivatives are covariant tensors, therefore a Gradient, is a
>>Tensor of covariant rank one, while a Hessian is a Tensor of
>>covariant rank two.
>>
>>The MetricTensor that maps the image space into the world
>>coordinates space can be obtained as the inverse of the matrix
>>used in the itkImageTransformHelper.
>>
>>In the particular case of the GradientRecursiveGaussianImageFilter,
>>we only need the correction of the orientation, so the matrix
>>that will be useful is the m_Direction matrix instead of the
>>m_IndexToPhysicalPoint matrix which also contains the scaling
>>corrections for pixel spacing.
>>
>>One way of avoiding the ambiguity and potential bugs of use,
>>is to provide two new methods along the lines of what Jim
>>suggested:
>>
>>  A) TransformIndexGradientToPhysicalGradient()
>>  B) TransformLocalGradientToPhysicalGradient()
>>
>>The first one will use a matrix that involves both rotation
>>and pixel spacing, while the second use a matrix that involves
>>only rotations. We probably want to add also the inverse methods:
>>
>>  C) TransformPhysicalGradientToIndexGradient()
>>  D) TransformPhysicalGradientToLocalGradient()
>>
>>and eventually:
>>
>>  E) TransformLocalGradientToIndexGradient()
>>  F) TransformIndexGradientToLocalGradient()
>>
>>although for these four methods we could wait until we see
>>a real need for them...
>>
>>
>>
>>I would suggest to add only the two methods (A) and (B)
>>as Jim proposed.
>>
>>
>>
>>   Luis
>>
>>
>>
>>Thanks Dan for
>>
>>
>>
>>       "using your deductive powers to
>>        figure out an extremely vexing ITK bug".
>>
>>
>>
>>
>>==================
>>Peter Cech wrote:
>>
>>
>>>On Fri, Mar 17, 2006 at 09:49:17 -0500, Miller, James V (GE, Research) 
>>>wrote:
>>>
>>>
>>>>Dan Blezek stumbled across the following problem:
>>>>
>>>>In the registration framework, the metrics use the image gradient in 
>>>>the calculation of the derivative of the metric wrt to the parameters 
>>>>of the transformation.  The image gradients are calculated taking 
>>>>into account the image spacing to provide a gradient in physical space.
>>>>
>>>>When an OrientedImage is used, these gradient calculations are not 
>>>>truly in physical space since gradients are not reoriented into the 
>>>>physical coordinate frame.  This affects the registration because the 
>>>>mapping of positions does take into account orientation but the image 
>>>>gradients, and hence the derivative of the metric wrt the parameters, 
>>>>does not.  In Dan's test case, when the derivative of the metric 
>>>>should force the transformation to move the image up, it ends up 
>>>>moving the image down.
>>>>
>>>>One solution would be to add methods to image like:
>>>>
>>>> template<class TCoordRep>
>>>> void TransformIndexGradientToPhysicalGradient(
>>>>                     const IndexType & index,
>>>>                     CovariantVector<TCoordRep, VImageDimension>& 
>>>>gradient) const
>>>>
>>>>which would convert a gradient computed in index space (without 
>>>>taking into account spacing or orientation) to a gradient computed in 
>>>>physical space.
>>>>
>>>>In Image, this method would merely apply the spacing scale factors.  
>>>>In OrientedImage, this method would apply the spacing scale factors 
>>>>and the orientation matrix.  Anywhere gradients are calculated, we 
>>>>would have to make an extra function call to convert the gradients 
>>>>into physical space.
>>>>
>>>>We may also need methods for transforming higher order derivatives 
>>>>(and cross-derivatives).
>>>
>>>
>>>
>>>Definitely. I just realized, that I recently witnessed the behavior when
>>>displaying eigenvectors of hessian. I thought it was off because the
>>>scale did not fit well for the structure...
>>>
>>>
>>>
>>>>Alternatively, wherever gradients are calculated, we could check 
>>>>whether we are operating on an Image or an OrientedImage and reorient 
>>>>the gradients as necessary there.
>>>
>>>
>>>
>>>If we stay consistent with current Index to Point behavior (1) of Image,
>>>a simple pass-through implementation will do.
>>>
>>>(1) It assumes origin is in the same orientation as the Image.
>>>
>>>Regards,
>>>Peter
>>>_______________________________________________
>>>Insight-developers mailing list
>>>Insight-developers at itk.org
>>>http://www.itk.org/mailman/listinfo/insight-developers
>>>
>>>
>>
>>_______________________________________________
>>Insight-developers mailing list
>>Insight-developers at itk.org
>>http://www.itk.org/mailman/listinfo/insight-developers
>>
> 
> 



More information about the Insight-developers mailing list