Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
shot_common.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id: shot_common.hpp 4702 2012-02-23 09:39:33Z gedikli $
00035  */
00036 
00037 #ifndef PCL_FEATURES_IMPL_SHOT_COMMON_H_
00038 #define PCL_FEATURES_IMPL_SHOT_COMMON_H_
00039 
00040 #include <utility>
00041 
00042 // Useful constants.
00043 #define PST_PI 3.1415926535897932384626433832795
00044 #define PST_RAD_45 0.78539816339744830961566084581988
00045 #define PST_RAD_90 1.5707963267948966192313216916398
00046 #define PST_RAD_135 2.3561944901923449288469825374596
00047 #define PST_RAD_180 PST_PI
00048 #define PST_RAD_360 6.283185307179586476925286766558
00049 #define PST_RAD_PI_7_8 2.7488935718910690836548129603691
00050 
00051 const double zeroDoubleEps15 = 1E-15;
00052 const float zeroFloatEps8 = 1E-8f;
00053 
00055 // Compute a local Reference Frame for a 3D feature; the output is stored in the "rf" vector
00056 template <typename PointInT> float
00057 pcl::getLocalRF (const pcl::PointCloud<PointInT> &cloud, 
00058                  const double search_radius, 
00059                  const Eigen::Vector4f & central_point, 
00060                  const std::vector<int> &indices, 
00061                  const std::vector<float> &dists, 
00062   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf)
00063 {
00064   if (rf.size () != 3)
00065     rf.resize (3);
00066 
00067   // Allocate enough space
00068   Eigen::Vector4d *vij = new Eigen::Vector4d[indices.size ()];
00069 
00070   Eigen::Matrix3d cov_m = Eigen::Matrix3d::Zero ();
00071 
00072   double distance = 0.0;
00073   double sum = 0.0;
00074 
00075   int valid_nn_points = 0;
00076 
00077   for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00078   {
00079     /*if (indices[i_idx] == index)
00080       continue;*/
00081 
00082     Eigen::Vector4f pt = cloud.points[indices[i_idx]].getVector4fMap (); 
00083     pt[3] = 0;
00084 
00085   if (pt == central_point)
00086     continue;
00087 
00088     // Difference between current point and origin
00089     vij[valid_nn_points] = (pt - central_point).cast<double> ();
00090     vij[valid_nn_points][3] = 0;
00091 
00092     distance = search_radius - sqrt (dists[i_idx]);
00093 
00094     // Multiply vij * vij'
00095     cov_m += distance * (vij[valid_nn_points].head<3> () * vij[valid_nn_points].head<3> ().transpose ());
00096 
00097     sum += distance;
00098     valid_nn_points++;
00099   }
00100 
00101   if (valid_nn_points < 5)
00102   {
00103     PCL_ERROR ("[pcl::%s::getSHOTLocalRF] Warning! Neighborhood has less than 5 vertexes. Aborting Local RF computation of feature point (%lf, %lf, %lf)\n", "SHOT", central_point[0], central_point[1], central_point[2]);
00104     rf[0].setZero ();
00105     rf[1].setZero ();
00106     rf[2].setZero ();
00107 
00108     rf[0][0] = 1;
00109     rf[1][1] = 1;
00110     rf[2][2] = 1;
00111 
00112     delete [] vij;
00113 
00114     return (std::numeric_limits<float>::max ());
00115   }
00116 
00117   cov_m /= sum;
00118 
00119   Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver (cov_m);
00120 
00121   // Disambiguation
00122  
00123   Eigen::Vector3d v1c = solver.eigenvectors ().col (0);
00124   Eigen::Vector3d v2c = solver.eigenvectors ().col (1);
00125   Eigen::Vector3d v3c = solver.eigenvectors ().col (2);
00126 
00127   double e1c = solver.eigenvalues ()[0];
00128   double e2c = solver.eigenvalues ()[1];
00129   double e3c = solver.eigenvalues ()[2];
00130 
00131   if(!pcl_isfinite(e1c) || !pcl_isfinite(e2c) || !pcl_isfinite(e3c)){
00132     PCL_ERROR ("[pcl::%s::getSHOTLocalRF] Warning! Eigenvectors are NaN. Aborting Local RF computation of feature point (%lf, %lf, %lf)\n", "SHOT", central_point[0], central_point[1], central_point[2]);
00133     rf[0].setZero ();
00134     rf[1].setZero ();
00135     rf[2].setZero ();
00136 
00137     rf[0][0] = 1;
00138     rf[1][1] = 1;
00139     rf[2][2] = 1;
00140 
00141     delete [] vij;
00142 
00143     return (std::numeric_limits<float>::max ());
00144   }
00145 
00146   Eigen::Vector4d v1 = Eigen::Vector4d::Zero ();
00147   Eigen::Vector4d v3 = Eigen::Vector4d::Zero ();
00148 
00149   if (e1c > e2c)
00150   {
00151     if (e1c > e3c) // v1c > max(v2c,v3c)
00152     {
00153       v1.head<3> () = v1c;
00154 
00155       if (e2c > e3c)  // v1c > v2c > v3c
00156         v3.head<3> () = v3c;
00157       else // v1c > v3c > v2c
00158         v3.head<3> () = v2c;
00159     }
00160     else // v3c > v1c > v2c
00161     {
00162       v1.head<3> () = v3c;
00163       v3.head<3> () = v2c;
00164     }
00165   }
00166   else
00167   {
00168     if (e2c > e3c) // v2c > max(v1c,v3c)
00169     {
00170       v1.head<3> () = v2c;
00171 
00172       if (e1c > e3c)  // v2c > v1c > v3c
00173         v3.head<3> () = v3c;
00174       else // v2c > v3c > v1c
00175         v3.head<3> () = v1c;
00176     }
00177     else // v3c > v2c > v1c
00178     {
00179       v1.head<3> () = v3c;
00180       v3.head<3> () = v1c;
00181     }
00182   }
00183 
00184   int plusNormal = 0, plusTangentDirection1=0;
00185   for (int ne = 0; ne < valid_nn_points; ne++)
00186   {
00187     double dp = vij[ne].dot (v1);
00188     if (dp >= 0)
00189       plusTangentDirection1++;
00190 
00191     dp = vij[ne].dot (v3);
00192     if (dp >= 0)
00193       plusNormal++;
00194   }
00195 
00196   //TANGENT
00197   if( abs ( plusTangentDirection1 - valid_nn_points + plusTangentDirection1 )  > 0 ) 
00198   {
00199     if (plusTangentDirection1 < valid_nn_points - plusTangentDirection1)
00200       v1 *= - 1;
00201   }
00202   else
00203   {
00204     plusTangentDirection1=0;
00205     int points = 5; 
00206     int medianIndex = valid_nn_points/2;
00207 
00208     for (int i = -points/2; i <= points/2; i++)
00209       if ( vij[medianIndex- i ].dot (v1) > 0)
00210         plusTangentDirection1 ++; 
00211     
00212     if (plusTangentDirection1 < points/2+1)
00213       v1 *= - 1;
00214   }
00215 
00216   //Normal
00217   if( abs ( plusNormal - valid_nn_points + plusNormal )  > 0 ) 
00218   {
00219     if (plusNormal < valid_nn_points - plusNormal)
00220       v3 *= - 1;
00221   }
00222   else 
00223   {
00224     plusNormal = 0;
00225     int points = 5; //std::min(valid_nn_points*2/2+1, 11);
00226     //std::cout << points << std::endl;
00227     int medianIndex = valid_nn_points/2;
00228 
00229     for (int i = -points/2; i <= points/2; i++)
00230       if ( vij[medianIndex- i ].dot (v3) > 0)
00231         plusNormal ++;  
00232   
00233     if (plusNormal < points/2+1)
00234       v3 *= - 1;
00235   }
00236 
00237 
00238 
00239   rf[0] = v1.cast<float>();
00240   rf[2] = v3.cast<float>();
00241   rf[1] = rf[2].cross3 (rf[0]);
00242   rf[0][3] = 0; rf[1][3] = 0; rf[2][3] = 0;
00243 
00244   delete [] vij;
00245 
00246   return (0.0f);
00247 }
00248 
00249 #endif    // PCL_FEATURES_IMPL_SHOT_COMMON_H_
00250