contrib/rpl/rgrl/rgrl_feature_face_pt.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 #include "rgrl_feature_face_pt.h"
00004 #include <rgrl/rgrl_transformation.h>
00005 #include <vnl/algo/vnl_svd.h>
00006 #include <vnl/vnl_math.h>
00007 
00008 #include <vcl_cassert.h>
00009 #include <rgrl/rgrl_util.h>
00010 #include <rgrl/rgrl_cast.h>
00011 
00012 
00013 rgrl_feature_face_pt ::
00014 rgrl_feature_face_pt( vnl_vector< double > const& location,
00015                       vnl_vector< double > const& normal )
00016   : rgrl_feature( location ), normal_( normal ),
00017     subspace_cached_( false )
00018 {
00019   normal_.normalize();
00020 }
00021 
00022 //  private constructor for transformed face points
00023 rgrl_feature_face_pt ::
00024 rgrl_feature_face_pt()
00025   : subspace_cached_( false )
00026 {
00027 }
00028 
00029 vnl_matrix<double> const&
00030 rgrl_feature_face_pt ::
00031 error_projector() const
00032 {
00033   if(scale_ == 0){
00034     WarningMacro( "The scale is zero." );
00035   }
00036   if( !err_proj_.size() ) {
00037     err_proj_ = outer_product( normal_, normal_ ) ;
00038     err_proj_ /= vnl_math_sqr( scale_ );
00039   }
00040   
00041   return err_proj_;
00042 }
00043 
00044 vnl_matrix<double> const&
00045 rgrl_feature_face_pt ::
00046 error_projector_sqrt() const
00047 {
00048   if(scale_ == 0){
00049     WarningMacro( "The scale is zero." );
00050   }
00051   if( !err_proj_sqrt_.size() ) {
00052     err_proj_sqrt_ = outer_product( normal_, normal_ ) ;
00053     err_proj_sqrt_ /= scale_;
00054   }
00055   
00056   return err_proj_sqrt_;
00057 }
00058 
00059 unsigned int
00060 rgrl_feature_face_pt::
00061 num_constraints() const
00062 {
00063   return 1;
00064 }
00065 
00066 vnl_vector<double> const&
00067 rgrl_feature_face_pt :: normal() const
00068 {
00069   return normal_;
00070 }
00071 
00072 vnl_matrix<double> const&
00073 rgrl_feature_face_pt ::
00074 tangent_subspace()
00075 {
00076   if ( subspace_cached_ )
00077     return tangent_subspace_;
00078 
00079   vnl_matrix<double> one_row( 1, this -> normal_.size() );
00080   one_row.set_row( 0, this -> normal_ );
00081   vnl_svd<double> normal_svd( one_row );
00082   tangent_subspace_ = normal_svd.nullspace();
00083   assert( tangent_subspace_ . columns() == this -> normal_ . size() - 1 );
00084   subspace_cached_ = true;
00085   return tangent_subspace_;
00086 }
00087 
00088 rgrl_feature_sptr
00089 rgrl_feature_face_pt ::
00090 transform( rgrl_transformation const& xform ) const
00091 {
00092   rgrl_feature_face_pt* face_ptr = new rgrl_feature_face_pt();
00093 
00094   // Capture the allocation into a smart pointer for exception safety.
00095   rgrl_feature_sptr result_sptr = face_ptr;
00096 
00097   xform.map_location( this->location_, face_ptr->location_ );
00098   xform.map_normal( this->location_, this->normal_, face_ptr->normal_ );
00099 
00100   // it is not clear what's meaning of the scale of corner and face points
00101   // It certainly does not represent the physical scale and is related to 
00102   // the sharpness of the edge.
00103 #if 0
00104   // transform scale
00105   if ( this->scale_ > 0.0 )
00106     face_ptr->scale_ = this->transform_scale( xform );
00107 #else
00108   // NOTE:
00109   // Because the scaling factors is computed using PCA,
00110   // it is invariant to rotation.  As a result,
00111   // the scaling factors are not with respect to x, y, or z anymore.
00112   // If there is different scaling on x, y, (or z) axis,
00113   // the scale of the mapped face point can be  different
00114   // depending on the orientation.
00115 
00116   // Current solution is to approximate this by transforming
00117   // a vector whose magnitude is the original scale.
00118   // the after scale is the magnitude of the transformed vector as
00119 
00120   vnl_vector<double> loc(normal_), xformed_loc(face_ptr->location_.size());
00121   loc *= scale_;
00122   loc += location_;
00123 
00124   // map the end point
00125   xform.map_location( loc, xformed_loc );
00126 
00127   // subtract the starting point
00128   xformed_loc -= face_ptr->location_;
00129 
00130   face_ptr->scale_ = xformed_loc.magnitude();
00131 #endif
00132 
00133   return result_sptr;
00134 }
00135 
00136 double
00137 rgrl_feature_face_pt::
00138 transform_scale( rgrl_transformation const& xform ) const
00139 {
00140   assert( !"should not use this function. The reason is above in the transform() function." );
00141 
00142   // transform scale
00143   vnl_vector<double> const& scaling = xform.scaling_factors();
00144   const unsigned dim = this->location_.size();
00145   double scale = 0.0;
00146 
00147   if ( this->scale_ > 0.0 && scaling.size() == dim ) {
00148     //use the scaling factor projected onto normal direction
00149     // CAUTION: it can become negative if use dot product
00150     // SOLUTION: use the sum of product of ABSOLUTE value of normal
00151 
00152     scale = 0.0;
00153     for ( unsigned i=0; i<normal_.size(); ++i )
00154       scale += vcl_abs(normal_[i]) * scaling[i];
00155     scale *= this->scale_;
00156 
00157   } else if ( this-> scale_ > 0.0 ) {
00158     WarningMacro( "This feature has non-zero scale value, but transformation has no scaling factors."
00159                   << "The scale of transformed features is NOT set." );
00160   }
00161 
00162   return scale;
00163 }
00164 
00165 
00166 //:  Compute the signature weight between two features.
00167 double
00168 rgrl_feature_face_pt ::
00169 absolute_signature_weight( rgrl_feature_sptr other ) const
00170 {
00171   //if other is invalid
00172   if ( !other )  return 0.0;
00173 
00174   rgrl_feature_face_pt* face_ptr = rgrl_cast<rgrl_feature_face_pt*>(other);
00175   assert( face_ptr );
00176   double dir_wgt = vcl_abs( dot_product( this->normal_, face_ptr->normal_ ) );
00177 
00178   double scale_wgt = 1;
00179   if ( this->scale_ && face_ptr->scale_ ) {
00180     if ( this->scale_ >= face_ptr->scale_ )
00181       scale_wgt = face_ptr->scale_ / this->scale_;
00182     else
00183       scale_wgt = this->scale_ / face_ptr->scale_;
00184     // the weight change is too gradual, make it more steep
00185     // scale_wgt = scale_wgt * scale_wgt;
00186   }
00187 
00188   return  dir_wgt* vcl_sqrt(scale_wgt);
00189 }
00190 
00191 //:  Compute the signature error vector between two features.
00192 vnl_vector<double> 
00193 rgrl_feature_face_pt::
00194 signature_error_vector( rgrl_feature const& other ) const
00195 {
00196   if( !other.is_type( rgrl_feature_face_pt::type_id() ) ) 
00197     return vnl_vector<double>();
00198   
00199   // cast it to face point type
00200   rgrl_feature_face_pt const& other_face_pt = static_cast<rgrl_feature_face_pt const&>(other);
00201   
00202   // compute cos between normals 
00203   const double dot = dot_product( this->normal_, other_face_pt.normal_ );
00204   const double half_pi = vnl_math::pi / 2.0;
00205   double ang = vcl_acos( dot );
00206 
00207   // make it between [-pi/2, pi/2]
00208   if( ang > half_pi )  ang -= vnl_math::pi;
00209     
00210   vnl_vector<double> error_vec(1, ang);
00211   return error_vec;
00212   
00213 }
00214 
00215 //:  the dimensions of the signature error vector.
00216 unsigned 
00217 rgrl_feature_face_pt::
00218 signature_error_dimension( const vcl_type_info& other_feature_type ) const
00219 {
00220   if( other_feature_type == rgrl_feature_face_pt::type_id() )
00221     return 1; 
00222   else
00223     return 0;
00224 }
00225 
00226 //: write out feature
00227 void
00228 rgrl_feature_face_pt::
00229 write( vcl_ostream& os ) const
00230 {
00231   // tag
00232   os << "FACE\n"
00233   // dimension
00234      << location_.size() << '\n'
00235   // atributes
00236      << location_ << "    " << scale_ << '\n'
00237      << normal_  << vcl_endl;
00238 }
00239 
00240 //: read in feature
00241 bool
00242 rgrl_feature_face_pt::
00243 read( vcl_istream& is, bool skip_tag )
00244 {
00245   if ( !skip_tag ) {
00246 
00247     // skip empty lines
00248     rgrl_util_skip_empty_lines( is );
00249 
00250     vcl_string str;
00251     vcl_getline( is, str );
00252 
00253     // The token should appear at the beginning of line
00254     if ( str.find( "FACE" ) != 0 ) {
00255       WarningMacro( "The tag is not FACE. reading is aborted.\n" );
00256       return false;
00257     }
00258   }
00259 
00260   // get dim
00261   int dim=-1;
00262   is >> dim;
00263 
00264   if ( !is || dim<=0 )
00265     return false;    // cannot get dimension
00266 
00267   // get location
00268   location_.set_size( dim );
00269   is >> location_;
00270   if ( !is )
00271     return false;   // cannot read location
00272 
00273   // get scale
00274   is >> scale_;
00275   if ( !is )
00276     return false;   // cannot read scale
00277 
00278   // get normal
00279   normal_.set_size( dim );
00280   is >> normal_;
00281   if ( !is )
00282     return false;
00283 
00284   //reset flag
00285   subspace_cached_ = false;
00286 
00287   return true;
00288 }
00289 
00290 rgrl_feature_sptr
00291 rgrl_feature_face_pt::
00292 clone() const
00293 {
00294   return new rgrl_feature_face_pt(*this);
00295 }