contrib/rpl/rgrl/rgrl_feature_face_region.cxx
Go to the documentation of this file.
00001 
00002 #include "rgrl_feature_face_region.h"
00003 #include <rgrl/rgrl_transformation.h>
00004 #include <vnl/algo/vnl_svd.h>
00005 // not used? #include <vcl_iostream.h>
00006 #include <vcl_cassert.h>
00007 #include <rgrl/rgrl_cast.h>
00008 #include <rgrl/rgrl_util.h>
00009 
00010 rgrl_feature_face_region ::
00011 rgrl_feature_face_region( vnl_vector< double > const& location,
00012                           vnl_vector< double > const& normal )
00013   : rgrl_feature_face_pt( location, normal ),
00014     thickness_( 0.0 ), radius_( 0.0 )
00015 {
00016 }
00017 
00018 
00019 rgrl_feature_face_region ::
00020 rgrl_feature_face_region( vnl_vector< double > const& location,
00021                           vnl_vector< double > const& normal,
00022                           double thickness,
00023                           double radius )
00024   : rgrl_feature_face_pt( location, normal ),
00025     thickness_( thickness ), radius_( radius )
00026 {
00027 }
00028 
00029 
00030 //  private constructor for transformed face points
00031 rgrl_feature_face_region ::
00032 rgrl_feature_face_region()
00033   : rgrl_feature_face_pt(),
00034     thickness_( 0 ), radius_( 0 )
00035 {
00036 }
00037 
00038 unsigned int
00039 rgrl_feature_face_region::
00040 num_constraints() const
00041 {
00042   return 1;
00043 }
00044 
00045 rgrl_feature_sptr
00046 rgrl_feature_face_region::
00047 transform( rgrl_transformation const& xform ) const
00048 {
00049   rgrl_feature_face_region* face_ptr = new rgrl_feature_face_region();
00050 
00051   // Capture the allocation into a smart pointer for exception safety.
00052   rgrl_feature_sptr result_sptr = face_ptr;
00053 
00054   xform.map_location( this->location_, face_ptr->location_ );
00055   xform.map_normal( this->location_, this->normal_, face_ptr->normal_ );
00056 
00057   face_ptr->err_proj_ = outer_product( face_ptr->normal_, face_ptr->normal_ );
00058   face_ptr->thickness_ = this->thickness_;
00059   face_ptr->radius_ = this->radius_;
00060   return result_sptr;
00061 }
00062 
00063 
00064 rgrl_feature_sptr
00065 rgrl_feature_face_region ::
00066 transform_region( rgrl_transformation const& xform ) const
00067 {
00068   //  Transform the location and direction, and form the new error projector.
00069   rgrl_feature_sptr result_sptr = this -> transform( xform );
00070 
00071   //  Cast down the pointer so that we can get / set the specific variables.
00072   rgrl_feature_face_region * face_ptr
00073     = rgrl_cast<rgrl_feature_face_region *> ( result_sptr );
00074 
00075   //  Determine the thickness along the normal direction.  Map a point
00076   //  that is half thickness units from the mapped center location
00077   //  along normal direction and compute the double distance between
00078   //  this point and the mapped location.
00079 
00080   vnl_vector< double > end_point( this -> location_ . size() );
00081   xform . map_location( this -> location_ + this->thickness_ / 2.0
00082                        * this -> normal_, end_point );
00083   face_ptr -> thickness_ = ( end_point - face_ptr -> location_) . magnitude() * 2.0;
00084 
00085   //  The radius is tougher.  First, find the basis of the subspace of
00086   //  tangent vectors from the null space of the single row matrix
00087   //  containing just the normal direction.
00088 
00089   vnl_matrix<double> one_row( 1, this -> normal_.size() );
00090   one_row.set_row( 0, this -> normal_ );
00091   vnl_svd<double> normal_svd( one_row );
00092   vnl_matrix<double> nullspace = normal_svd.nullspace();
00093   assert( nullspace . columns() == this -> normal_ . size() - 1 );
00094 
00095   //  Now, for each basis vector, map a point radius units away from
00096   //  the location along the vector.  Compute the distance of the
00097   //  resulting point from the mapped location.  Average these to
00098   //  come up with the radius.
00099 
00100   vnl_vector< double > point_along_dir( this->location_.size() );
00101   double sum_radii = 0;
00102 
00103   double this_radius = this->radius_; // Work-around for Borland C++ 5.
00104   for ( unsigned int i=0; i+1 < this -> location_ . size(); ++i )
00105   {
00106     point_along_dir = this -> location();
00107     point_along_dir += this_radius * nullspace . get_column( i );
00108     xform . map_location( point_along_dir, end_point );
00109     sum_radii += ( end_point - face_ptr -> location_ ) . magnitude();
00110   }
00111 
00112   face_ptr -> radius_ = sum_radii / ( this -> location_ . size() - 1 );
00113 
00114   return result_sptr;
00115 }
00116 
00117 
00118 // Return region(neighboring) pixels in "pixel" coordinates.
00119 void
00120 rgrl_feature_face_region ::
00121 generate_pixel_coordinates( vnl_vector< double > const& spacing_ratio )
00122 {
00123   //  Create the oriented rectangular solid.  Form the set of
00124   //  orthogonal directions and radii.  The directions are combined
00125   //  from the normal direction and the basis for the tangent
00126   //  subspace.  The first radius is half the fatness of the region.
00127   //  The others are all equal to the radius of the trace region.
00128 
00129   unsigned int dim = this -> location_ . size();
00130   vnl_matrix< double > tangents = this -> tangent_subspace();
00131   vcl_vector< vnl_vector<double> > directions;
00132   directions.reserve( dim );
00133 //    directions.push_back( this -> normal_ );
00134 
00135   // compute in the pixel coordinates
00136   // convert the location to the pixel coordinates
00137   vnl_vector< double > location_in_pixel( dim );
00138   vnl_vector< double > radii_in_pixel( dim );
00139   vnl_vector< double > directions_in_pixel( dim );
00140 
00141   vnl_vector< double > direction_in_pixel( dim );
00142   for ( unsigned int i = 0; i < dim; ++i )
00143   {
00144     direction_in_pixel[ i ] = this->normal_[ i ] / spacing_ratio[ i ];
00145     location_in_pixel[ i ] = this->location_[ i ] / spacing_ratio[ i ];
00146   }
00147   directions.push_back( direction_in_pixel );
00148 
00149   radii_in_pixel[ 0 ] = this -> thickness_ / spacing_ratio[ 0 ] / 2.0;
00150   for ( unsigned int i = 0; i < dim-1; ++i )
00151   {
00152     direction_in_pixel = tangents.get_column( i );
00153     for ( unsigned j = 0; j < dim; ++j )
00154     {
00155       direction_in_pixel[ j ] /= spacing_ratio[ j ];
00156     }
00157     directions.push_back( direction_in_pixel );
00158     radii_in_pixel[ i+1 ] = this -> radius_ / spacing_ratio[ i+1 ];
00159   }
00160 
00161   //  Call the utility function to extract the pixel locations,
00162   //  record the caching and return the vector.
00163 
00164   rgrl_util_extract_region_locations( location_in_pixel, directions,
00165                                       radii_in_pixel, pixel_coordinates_ );
00166 
00167   pixel_coordinates_cached_ = true;
00168 }
00169 
00170 rgrl_feature_sptr
00171 rgrl_feature_face_region::clone() const
00172 {
00173   return new rgrl_feature_face_region(*this);
00174 }
00175 
00176 #if 0 // Keep this for mapping --- move to different code
00177 
00178 void
00179 rgrl_feature_face_region :: set_tangents()
00180 {
00181   vnl_matrix<double> one_row( 1, normal_.size() );
00182   one_row.set_row( 0, normal_ );
00183   vnl_svd<double> normal_svd( one_row );
00184 
00185   tangent_directions_.clear();
00186   for ( unsigned int i=1; i<normal_.size(); ++i )
00187   {
00188     tangent_directions_.push_back( normal_svd.V().get_column( i ) );
00189   }
00190 }
00191 
00192 #endif // 0