Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include "cmtkSplineWarpXform.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 
00037 namespace
00038 cmtk
00039 {
00040 
00043 
00044 bool
00045 SplineWarpXform::ApplyInverse
00046 ( const Self::SpaceVectorType& v, Self::SpaceVectorType& u, const Types::Coordinate accuracy ) const
00047 {
00048   u = v;
00049   return this->ApplyInverseInPlace( u, accuracy );
00050 }
00051 
00052 bool
00053 SplineWarpXform::ApplyInverseInPlace 
00054 ( Self::SpaceVectorType& v, const Types::Coordinate accuracy ) const
00055 {
00056   Self::SpaceVectorType u;
00057   this->FindClosestControlPoint( v, u );
00058   return this->ApplyInverseInPlaceWithInitial( v, u, accuracy );
00059 }
00060 
00061 void
00062 SplineWarpXform::FindClosestControlPoint
00063 ( const Self::SpaceVectorType& v, Self::SpaceVectorType& cp ) const
00064 {
00065   
00066   Types::Coordinate closestDistance = FLT_MAX;
00067   Types::Coordinate idx[3];
00068   for ( int dim = 0; dim < 3; ++dim ) 
00069     idx[dim] = 0.5 * this->m_Dims[dim];
00070 
00071   for ( Types::Coordinate step = 0.25 * MathUtil::Min( 3, idx ); step > 0.01; step *= 0.5 )
00072     {
00073     bool improved = true;
00074     while ( improved ) 
00075       {
00076       improved = false;
00077       int closestDim = 0, closestDir = 0;
00078       
00079       for ( int dim = 0; dim < 3; ++dim ) 
00080         {
00081         for ( int dir = -1; dir < 2; dir +=2 )
00082           {
00083           const Types::Coordinate oldIdx = idx[dim];
00084           idx[dim] += dir * step;
00085           if ( (idx[dim] > 0) && (idx[dim] <= this->m_Dims[dim]-2) ) 
00086             {
00087             this->GetOriginalControlPointPosition( cp, idx[0], idx[1], idx[2] );
00088             this->ApplyInPlace( cp );
00089             cp -= v;
00090             const Types::Coordinate distance = cp.RootSumOfSquares();
00091             if ( distance < closestDistance ) 
00092               {
00093               closestDistance = distance;
00094               closestDim = dim;
00095               closestDir = dir;
00096               improved = true;
00097               } 
00098             }
00099           idx[dim] = oldIdx;
00100           }
00101         }
00102       
00103       if ( improved )
00104         {
00105         idx[closestDim] += closestDir * step;
00106         }
00107       }
00108     }
00109   
00110   assert( (idx[0] <= this->m_Dims[0]-1) && (idx[1] <= this->m_Dims[1]-1 ) && (idx[2] <= this->m_Dims[2]-1) );
00111   assert( idx[0] >= 0 && idx[1] >= 0 && idx[2] >= 0 );
00112 
00113   this->GetOriginalControlPointPosition( cp, idx[0], idx[1], idx[2] );
00114 }
00115 
00116 bool
00117 SplineWarpXform::ApplyInverseInPlaceWithInitial
00118 ( Self::SpaceVectorType& target, const Self::SpaceVectorType& initial, const Types::Coordinate accuracy ) 
00119   const
00120 {
00121   Self::SpaceVectorType u( initial );
00122 
00123   
00124   for ( int dim = 0; dim < 3; ++dim )
00125     {
00126     u[dim] = std::max<Types::Coordinate>( 0, std::min<Types::Coordinate>( u[dim], this->Domain[dim] ) );
00127     }
00128 
00129   Self::SpaceVectorType vu( initial ), delta;
00130   this->ApplyInPlace( vu );
00131   ((delta = vu) -= target);
00132 
00133   Types::Coordinate error = delta.RootSumOfSquares();
00134 
00135   Types::Coordinate step = 1.0;
00136   while ( ( error > accuracy) && (step > 0.001) ) 
00137     {
00138     
00139     CoordinateMatrix3x3 J;
00140     this->GetJacobian( u, J );
00141     J.Invert3x3();
00142     J.GetTranspose().Multiply( delta );
00143     
00144     
00145     (vu = u) -= (delta *= step);
00146     
00147     
00148     if ( !this->InDomain( vu ) ) 
00149       {
00150       
00151       for ( int dim = 0; dim < 3; ++dim )
00152         {
00153         vu[dim] = std::max<Types::Coordinate>( 0, std::min<Types::Coordinate>( vu[dim], this->Domain[dim] ) );
00154         }
00155       }
00156     
00157     Self::SpaceVectorType uNext( vu );
00158     this->ApplyInPlace( vu );
00159     
00160     (delta = vu) -= target;
00161     if ( error > delta.RootSumOfSquares() ) 
00162       {
00163       error = delta.RootSumOfSquares();
00164       u = uNext;
00165       } 
00166     else
00167       {
00168       step *= 0.5;
00169       }
00170     }
00171 
00172   target = u;
00173   return !(error > accuracy);
00174 }
00175 
00176 }