Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
shot.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  *
00037  */
00038 
00039 #ifndef PCL_FEATURES_IMPL_SHOT_H_
00040 #define PCL_FEATURES_IMPL_SHOT_H_
00041 
00042 #include "pcl/features/shot.h"
00043 #include "pcl/features/shot_common.h"
00044 #include <utility>
00045 
00047 
00054 inline bool
00055 areEquals (double val1, double val2, double zeroDoubleEps = zeroDoubleEps15)
00056 {
00057   return (fabs (val1 - val2)<zeroDoubleEps);
00058 };
00059 
00061 
00068 inline bool
00069 areEquals (float val1, float val2, float zeroFloatEps = zeroFloatEps8)
00070 {
00071   return (fabs (val1 - val2)<zeroFloatEps);
00072 }
00073 
00075 template <typename PointNT, typename PointOutT> float
00076 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::sRGB_LUT[256] = {- 1};
00077 
00079 template <typename PointNT, typename PointOutT> float
00080 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::sXYZ_LUT[4000] = {- 1};
00081 
00083 template <typename PointNT, typename PointOutT> void
00084 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::RGB2CIELAB (unsigned char R, unsigned char G,
00085                                                                         unsigned char B, float &L, float &A,
00086                                                                         float &B2)
00087 {
00088   if (sRGB_LUT[0] < 0)
00089   {
00090     for (int i = 0; i < 256; i++)
00091     {
00092       float f = i / 255.0f;
00093       if (f > 0.04045)
00094         sRGB_LUT[i] = (float)pow ((f + 0.055) / 1.055, 2.4);
00095       else
00096         sRGB_LUT[i] = f / 12.92;
00097     }
00098 
00099     for (int i = 0; i < 4000; i++)
00100     {
00101       float f = i / 4000.0f;
00102       if (f > 0.008856)
00103         sXYZ_LUT[i] = pow (f, (float)0.3333);
00104       else
00105         sXYZ_LUT[i] = (7.787 * f) + (16.0 / 116.0);
00106     }
00107   }
00108 
00109   float fr = sRGB_LUT[R];
00110   float fg = sRGB_LUT[G];
00111   float fb = sRGB_LUT[B];
00112 
00113   // Use white = D65
00114   const float x = fr * 0.412453 + fg * 0.357580 + fb * 0.180423;
00115   const float y = fr * 0.212671 + fg * 0.715160 + fb * 0.072169;
00116   const float z = fr * 0.019334 + fg * 0.119193 + fb * 0.950227;
00117 
00118   float vx = x / 0.95047;
00119   float vy = y;
00120   float vz = z / 1.08883;
00121 
00122   vx = sXYZ_LUT[int(vx*4000)];
00123   vy = sXYZ_LUT[int(vy*4000)];
00124   vz = sXYZ_LUT[int(vz*4000)];
00125 
00126   L = 116.0 * vy - 16.0;
00127   if (L>100)
00128     L=100;
00129 
00130   A = 500.0 * (vx - vy);
00131   if (A>120)
00132     A=120;
00133   else if (A<- 120)
00134     A=- 120;
00135 
00136   B2 = 200.0 * (vy - vz);
00137   if (B2>120)
00138     B2=120;
00139   else if (B2<- 120)
00140     B2=- 120;
00141 }
00142 
00144 template <typename PointInT, typename PointNT, typename PointOutT> void
00145 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::createBinDistanceShape (
00146     int index,
00147     const std::vector<int> &indices, 
00148     const std::vector<float> &sqr_dists,
00149     const pcl::PointCloud<PointInT> &input,
00150     const pcl::PointCloud<PointNT> &normals,
00151     const pcl::PointCloud<PointInT> &surface,
00152     double search_radius,
00153     std::vector<double> &bin_distance_shape,
00154     std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf)
00155 {
00156   bin_distance_shape.resize (indices.size ());
00157 
00158   if (rf.size () != 3)
00159     rf.resize (3);
00160 
00161   Eigen::Vector4f central_point = input.points[index].getVector4fMap ();
00162   central_point[3] = 0;
00163   if (pcl::getLocalRF (surface, search_radius, central_point, indices, sqr_dists, rf))
00164     return;
00165 
00166   for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00167   {
00168     double cosineDesc = normals.points[indices[i_idx]].getNormalVector4fMap ().dot (rf[2]); //feat[i].rf[6]*normal[0] + feat[i].rf[7]*normal[1] + feat[i].rf[8]*normal[2];
00169 
00170     if (cosineDesc > 1.0)
00171       cosineDesc = 1.0;
00172     if (cosineDesc < - 1.0)
00173       cosineDesc = - 1.0;
00174 
00175     bin_distance_shape[i_idx] = ((1.0 + cosineDesc) * nr_shape_bins_) / 2;
00176   }
00177 }
00178 
00180 template <typename PointInT, typename PointNT, typename PointOutT> void
00181 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::normalizeHistogram (
00182     Eigen::VectorXf &shot, int desc_length)
00183 {
00184   double acc_norm = 0;
00185   for (int j = 0; j < desc_length; j++)
00186     acc_norm += shot[j] * shot[j];
00187   acc_norm = sqrt (acc_norm);
00188   for (int j = 0; j < desc_length; j++)
00189     shot[j] /= acc_norm;
00190 }
00191 
00193 template <typename PointInT, typename PointNT, typename PointOutT> void
00194 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::interpolateSingleChannel (
00195     const std::vector<int> &indices,
00196     const std::vector<float> &sqr_dists,
00197     const Eigen::Vector4f &central_point,
00198     const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf,
00199     std::vector<double> &binDistance,
00200     const int nr_bins,
00201     Eigen::VectorXf &shot)
00202 {
00203   if (rf.size () != 3)
00204   {
00205     PCL_ERROR ("[pcl::%s::interpolateSingleChannel] RF size different than 9! Aborting...\n");
00206     return;
00207   }
00208 
00209   for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00210   {
00211     Eigen::Vector4f delta = surface_->points[indices[i_idx]].getVector4fMap () - central_point;
00212   delta[3] = 0;
00213 
00214     // Compute the Euclidean norm
00215    double distance = sqrt (sqr_dists[i_idx]);
00216 
00217     if (areEquals (distance, 0.0))
00218       continue;
00219 
00220     double xInFeatRef = delta.dot (rf[0]); //(x * feat[i].rf[0] + y * feat[i].rf[1] + z * feat[i].rf[2]);
00221     double yInFeatRef = delta.dot (rf[1]); //(x * feat[i].rf[3] + y * feat[i].rf[4] + z * feat[i].rf[5]);
00222     double zInFeatRef = delta.dot (rf[2]); //(x * feat[i].rf[6] + y * feat[i].rf[7] + z * feat[i].rf[8]);
00223 
00224     // To avoid numerical problems afterwards
00225     if (fabs (yInFeatRef) < 1E-30)
00226       yInFeatRef  = 0;
00227     if (fabs (xInFeatRef) < 1E-30)
00228       xInFeatRef  = 0;
00229     if (fabs (zInFeatRef) < 1E-30)
00230       zInFeatRef  = 0;
00231 
00232 
00233     unsigned char bit4 = ((yInFeatRef > 0) || ((yInFeatRef == 0.0) && (xInFeatRef < 0))) ? 1 : 0;
00234     unsigned char bit3 = ((xInFeatRef > 0) || ((xInFeatRef == 0.0) && (yInFeatRef > 0))) ? !bit4 : bit4;
00235 
00236     assert (bit3 == 0 || bit3 == 1);
00237 
00238     int desc_index = (bit4<<3) + (bit3<<2);
00239 
00240     desc_index = desc_index << 1;
00241 
00242     if ((xInFeatRef * yInFeatRef > 0) || (xInFeatRef == 0.0))
00243       desc_index += (fabs (xInFeatRef) >= fabs (yInFeatRef)) ? 0 : 4;
00244     else
00245       desc_index += (fabs (xInFeatRef) > fabs (yInFeatRef)) ? 4 : 0;
00246 
00247     desc_index += zInFeatRef > 0 ? 1 : 0;
00248 
00249     // 2 RADII
00250     desc_index += (distance > radius1_2_) ? 2 : 0;
00251 
00252     int step_index = static_cast<int>(floor (binDistance[i_idx] +0.5));
00253     int volume_index = desc_index * (nr_bins+1);
00254 
00255     //Interpolation on the cosine (adjacent bins in the histogram)
00256     binDistance[i_idx] -= step_index;
00257     double intWeight = (1- fabs (binDistance[i_idx]));
00258 
00259     if (binDistance[i_idx] > 0)
00260       shot[volume_index + ((step_index+1) % nr_bins)] += binDistance[i_idx];
00261     else
00262       shot[volume_index + ((step_index - 1 + nr_bins) % nr_bins)] += - binDistance[i_idx];
00263 
00264     //Interpolation on the distance (adjacent husks)
00265    
00266     if (distance > radius1_2_)   //external sphere
00267     {
00268       double radiusDistance = (distance - radius3_4_) / radius1_2_;
00269 
00270       if (distance > radius3_4_) //most external sector, votes only for itself
00271         intWeight += 1 - radiusDistance;  //peso=1-d
00272       else  //3/4 of radius, votes also for the internal sphere
00273       {
00274         intWeight += 1 + radiusDistance;
00275         shot[(desc_index - 2) * (nr_bins+1) + step_index] -= radiusDistance;
00276       }
00277     }
00278     else    //internal sphere
00279     {
00280       double radiusDistance = (distance - radius1_4_) / radius1_2_;
00281 
00282       if (distance < radius1_4_) //most internal sector, votes only for itself
00283         intWeight += 1 + radiusDistance;  //weight=1-d
00284       else  //3/4 of radius, votes also for the external sphere
00285       {
00286         intWeight += 1 - radiusDistance;
00287         shot[(desc_index + 2) * (nr_bins+1) + step_index] += radiusDistance;
00288       }
00289     }
00290 
00291     //Interpolation on the inclination (adjacent vertical volumes)
00292     double inclinationCos = zInFeatRef / distance;
00293     if (inclinationCos < - 1.0)
00294       inclinationCos = - 1.0;
00295     if (inclinationCos > 1.0)
00296       inclinationCos = 1.0;
00297 
00298     double inclination = acos (inclinationCos);
00299 
00300     assert (inclination >= 0.0 && inclination <= PST_RAD_180);
00301 
00302     if (inclination > PST_RAD_90 || (fabs (inclination - PST_RAD_90) < 1e-30 && zInFeatRef <= 0))
00303     {
00304       double inclinationDistance = (inclination - PST_RAD_135) / PST_RAD_90;
00305       if (inclination > PST_RAD_135)
00306         intWeight += 1 - inclinationDistance;
00307       else
00308       {
00309         intWeight += 1 + inclinationDistance;
00310         assert ((desc_index + 1) * (nr_bins+1) + step_index >= 0 && (desc_index + 1) * (nr_bins+1) + step_index < descLength_);
00311         shot[(desc_index + 1) * (nr_bins+1) + step_index] -= inclinationDistance;
00312       }
00313     }
00314     else
00315     {
00316       double inclinationDistance = (inclination - PST_RAD_45) / PST_RAD_90;
00317       if (inclination < PST_RAD_45)
00318         intWeight += 1 + inclinationDistance;
00319       else
00320       {
00321         intWeight += 1 - inclinationDistance;
00322         assert ((desc_index - 1) * (nr_bins+1) + step_index >= 0 && (desc_index - 1) * (nr_bins+1) + step_index < descLength_);
00323         shot[(desc_index - 1) * (nr_bins+1) + step_index] += inclinationDistance;
00324       }
00325     }
00326 
00327     if (yInFeatRef != 0.0 || xInFeatRef != 0.0)
00328     {
00329       //Interpolation on the azimuth (adjacent horizontal volumes)
00330       double azimuth = atan2 (yInFeatRef, xInFeatRef);
00331 
00332       int sel = desc_index >> 2;
00333       double angularSectorSpan = PST_RAD_45;
00334       double angularSectorStart = - PST_RAD_PI_7_8;
00335 
00336       double azimuthDistance = (azimuth - (angularSectorStart + angularSectorSpan*sel)) / angularSectorSpan;
00337 
00338       assert ((azimuthDistance < 0.5 || areEquals (azimuthDistance, 0.5)) && (azimuthDistance > - 0.5 || areEquals (azimuthDistance, - 0.5)));
00339 
00340       azimuthDistance = (std::max)(- 0.5, std::min (azimuthDistance, 0.5));
00341 
00342       if (azimuthDistance > 0)
00343       {
00344         intWeight += 1 - azimuthDistance;
00345         int interp_index = (desc_index + 4) % maxAngularSectors_;
00346         assert (interp_index * (nr_bins+1) + step_index >= 0 && interp_index * (nr_bins+1) + step_index < descLength_);
00347         shot[interp_index * (nr_bins+1) + step_index] += azimuthDistance;
00348       }
00349       else
00350       {
00351         int interp_index = (desc_index - 4 + maxAngularSectors_) % maxAngularSectors_;
00352         assert (interp_index * (nr_bins+1) + step_index >= 0 && interp_index * (nr_bins+1) + step_index < descLength_);
00353         intWeight += 1 + azimuthDistance;
00354         shot[interp_index * (nr_bins+1) + step_index] -= azimuthDistance;
00355       }
00356 
00357     }
00358 
00359     assert (volume_index + step_index >= 0 &&  volume_index + step_index < descLength_);
00360     shot[volume_index + step_index] += intWeight;
00361   }
00362 }
00363 
00365 template <typename PointNT, typename PointOutT> void
00366 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::interpolateDoubleChannel (
00367   const std::vector<int> &indices, 
00368   const std::vector<float> &sqr_dists,
00369   const Eigen::Vector4f &central_point, 
00370   const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf,
00371   std::vector<double> &binDistanceShape,
00372   std::vector<double> &binDistanceColor, 
00373   const int nr_bins_shape, 
00374   const int nr_bins_color, 
00375   Eigen::VectorXf &shot)
00376 {
00377   if (rf.size () != 3)
00378   {
00379     PCL_ERROR ("[pcl::%s::interpolateDoubleChannel] RF size different than 9! Aborting...\n");
00380     return;
00381   }
00382 
00383   int shapeToColorStride = nr_grid_sector_*(nr_bins_shape+1);
00384 
00385   for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00386   {
00387     Eigen::Vector4f delta = surface_->points[indices[i_idx]].getVector4fMap () - central_point;
00388     delta[3] = 0;
00389 
00390     // Compute the Euclidean norm
00391     double distance = sqrt (sqr_dists[i_idx]);
00392 
00393     if (areEquals (distance, 0.0))
00394       continue;
00395 
00396     double xInFeatRef = delta.dot (rf[0]); //(x * feat[i].rf[0] + y * feat[i].rf[1] + z * feat[i].rf[2]);
00397     double yInFeatRef = delta.dot (rf[1]); //(x * feat[i].rf[3] + y * feat[i].rf[4] + z * feat[i].rf[5]);
00398     double zInFeatRef = delta.dot (rf[2]); //(x * feat[i].rf[6] + y * feat[i].rf[7] + z * feat[i].rf[8]);
00399 
00400     // To avoid numerical problems afterwards
00401     if (fabs (yInFeatRef) < 1E-30)
00402       yInFeatRef  = 0;
00403     if (fabs (xInFeatRef) < 1E-30)
00404       xInFeatRef  = 0;
00405     if (fabs (zInFeatRef) < 1E-30)
00406       zInFeatRef  = 0;
00407 
00408     unsigned char bit4 = ((yInFeatRef > 0) || ((yInFeatRef == 0.0) && (xInFeatRef < 0))) ? 1 : 0;
00409     unsigned char bit3 = ((xInFeatRef > 0) || ((xInFeatRef == 0.0) && (yInFeatRef > 0))) ? !bit4 : bit4;
00410 
00411     assert (bit3 == 0 || bit3 == 1);
00412 
00413     int desc_index = (bit4<<3) + (bit3<<2);
00414 
00415     desc_index = desc_index << 1;
00416 
00417     if ((xInFeatRef * yInFeatRef > 0) || (xInFeatRef == 0.0))
00418       desc_index += (fabs (xInFeatRef) >= fabs (yInFeatRef)) ? 0 : 4;
00419     else
00420       desc_index += (fabs (xInFeatRef) > fabs (yInFeatRef)) ? 4 : 0;
00421 
00422     desc_index += zInFeatRef > 0 ? 1 : 0;
00423 
00424     // 2 RADII
00425     desc_index += (distance > radius1_2_) ? 2 : 0;
00426 
00427     int step_index_shape = static_cast<int>(floor (binDistanceShape[i_idx] +0.5));
00428     int step_index_color = static_cast<int>(floor (binDistanceColor[i_idx] +0.5));
00429 
00430     int volume_index_shape = desc_index * (nr_bins_shape+1);
00431     int volume_index_color = shapeToColorStride + desc_index * (nr_bins_color+1);
00432 
00433     //Interpolation on the cosine (adjacent bins in the histrogram)
00434     binDistanceShape[i_idx] -= step_index_shape;
00435     binDistanceColor[i_idx] -= step_index_color;
00436 
00437     double intWeightShape = (1- fabs (binDistanceShape[i_idx]));
00438     double intWeightColor = (1- fabs (binDistanceColor[i_idx]));
00439 
00440     if (binDistanceShape[i_idx] > 0)
00441       shot[volume_index_shape + ((step_index_shape + 1) % nr_bins_shape)] += binDistanceShape[i_idx];
00442     else
00443       shot[volume_index_shape + ((step_index_shape - 1 + nr_bins_shape) % nr_bins_shape)] -= binDistanceShape[i_idx];
00444 
00445     if (binDistanceColor[i_idx] > 0)
00446       shot[volume_index_color + ((step_index_color+1) % nr_bins_color)] += binDistanceColor[i_idx];
00447     else
00448       shot[volume_index_color + ((step_index_color - 1 + nr_bins_color) % nr_bins_color)] -= binDistanceColor[i_idx];
00449 
00450     //Interpolation on the distance (adjacent husks)
00451    
00452     if (distance > radius1_2_)   //external sphere
00453     {
00454       double radiusDistance = (distance - radius3_4_) / radius1_2_;
00455 
00456       if (distance > radius3_4_) //most external sector, votes only for itself
00457       {
00458         intWeightShape += 1 - radiusDistance; //weight=1-d
00459         intWeightColor += 1 - radiusDistance; //weight=1-d
00460       }
00461       else  //3/4 of radius, votes also for the internal sphere
00462       {
00463         intWeightShape += 1 + radiusDistance;
00464         intWeightColor += 1 + radiusDistance;
00465         shot[(desc_index - 2) * (nr_bins_shape+1) + step_index_shape] -= radiusDistance;
00466         shot[shapeToColorStride + (desc_index - 2) * (nr_bins_color+1) + step_index_color] -= radiusDistance;
00467       }
00468     }
00469     else    //internal sphere
00470     {
00471       double radiusDistance = (distance - radius1_4_) / radius1_2_;
00472 
00473       if (distance < radius1_4_) //most internal sector, votes only for itself
00474       {
00475         intWeightShape += 1 + radiusDistance;
00476         intWeightColor += 1 + radiusDistance; //weight=1-d
00477       }
00478       else  //3/4 of radius, votes also for the external sphere
00479       {
00480         intWeightShape += 1 - radiusDistance; //weight=1-d
00481         intWeightColor += 1 - radiusDistance; //weight=1-d
00482         shot[(desc_index + 2) * (nr_bins_shape+1) + step_index_shape] += radiusDistance;
00483         shot[shapeToColorStride + (desc_index + 2) * (nr_bins_color+1) + step_index_color] += radiusDistance;
00484       }
00485     }
00486 
00487     //Interpolation on the inclination (adjacent vertical volumes)
00488     double inclinationCos = zInFeatRef / distance;
00489     if (inclinationCos < - 1.0)
00490       inclinationCos = - 1.0;
00491     if (inclinationCos > 1.0)
00492       inclinationCos = 1.0;
00493 
00494     double inclination = acos (inclinationCos);
00495 
00496     assert (inclination >= 0.0 && inclination <= PST_RAD_180);
00497 
00498     if (inclination > PST_RAD_90 || (fabs (inclination - PST_RAD_90) < 1e-30 && zInFeatRef <= 0))
00499     {
00500       double inclinationDistance = (inclination - PST_RAD_135) / PST_RAD_90;
00501       if (inclination > PST_RAD_135)
00502       {
00503         intWeightShape += 1 - inclinationDistance;
00504         intWeightColor += 1 - inclinationDistance;
00505       }
00506       else
00507       {
00508         intWeightShape += 1 + inclinationDistance;
00509         intWeightColor += 1 + inclinationDistance;
00510         assert ((desc_index + 1) * (nr_bins_shape+1) + step_index_shape >= 0 && (desc_index + 1) * (nr_bins_shape+1) + step_index_shape < descLength_);
00511         assert (shapeToColorStride + (desc_index + 1) * (nr_bins_color+ 1) + step_index_color >= 0 && shapeToColorStride + (desc_index + 1) * (nr_bins_color+1) + step_index_color < descLength_);
00512         shot[(desc_index + 1) * (nr_bins_shape+1) + step_index_shape] -= inclinationDistance;
00513         shot[shapeToColorStride + (desc_index + 1) * (nr_bins_color+1) + step_index_color] -= inclinationDistance;
00514       }
00515     }
00516     else
00517     {
00518       double inclinationDistance = (inclination - PST_RAD_45) / PST_RAD_90;
00519       if (inclination < PST_RAD_45)
00520       {
00521         intWeightShape += 1 + inclinationDistance;
00522         intWeightColor += 1 + inclinationDistance;
00523       }
00524       else
00525       {
00526         intWeightShape += 1 - inclinationDistance;
00527         intWeightColor += 1 - inclinationDistance;
00528         assert ((desc_index - 1) * (nr_bins_shape+1) + step_index_shape >= 0 && (desc_index - 1) * (nr_bins_shape+1) + step_index_shape < descLength_);
00529         assert (shapeToColorStride + (desc_index - 1) * (nr_bins_color+ 1) + step_index_color >= 0 && shapeToColorStride + (desc_index - 1) * (nr_bins_color+1) + step_index_color < descLength_);
00530         shot[(desc_index - 1) * (nr_bins_shape+1) + step_index_shape] += inclinationDistance;
00531         shot[shapeToColorStride + (desc_index - 1) * (nr_bins_color+1) + step_index_color] += inclinationDistance;
00532       }
00533     }
00534 
00535     if (yInFeatRef != 0.0 || xInFeatRef != 0.0)
00536     {
00537       //Interpolation on the azimuth (adjacent horizontal volumes)
00538       double azimuth = atan2 (yInFeatRef, xInFeatRef);
00539 
00540       int sel = desc_index >> 2;
00541       double angularSectorSpan = PST_RAD_45;
00542       double angularSectorStart = - PST_RAD_PI_7_8;
00543 
00544       double azimuthDistance = (azimuth - (angularSectorStart + angularSectorSpan*sel)) / angularSectorSpan;
00545       assert ((azimuthDistance < 0.5 || areEquals (azimuthDistance, 0.5)) && (azimuthDistance > - 0.5 || areEquals (azimuthDistance, - 0.5)));
00546       azimuthDistance = (std::max)(- 0.5, std::min (azimuthDistance, 0.5));
00547 
00548       if (azimuthDistance > 0)
00549       {
00550         intWeightShape += 1 - azimuthDistance;
00551         intWeightColor += 1 - azimuthDistance;
00552         int interp_index = (desc_index + 4) % maxAngularSectors_;
00553         assert (interp_index * (nr_bins_shape+1) + step_index_shape >= 0 && interp_index * (nr_bins_shape+1) + step_index_shape < descLength_);
00554         assert (shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color >= 0 && shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color < descLength_);
00555         shot[interp_index * (nr_bins_shape+1) + step_index_shape] += azimuthDistance;
00556         shot[shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color] += azimuthDistance;
00557       }
00558       else
00559       {
00560         int interp_index = (desc_index - 4 + maxAngularSectors_) % maxAngularSectors_;
00561         intWeightShape += 1 + azimuthDistance;
00562         intWeightColor += 1 + azimuthDistance;
00563         assert (interp_index * (nr_bins_shape+1) + step_index_shape >= 0 && interp_index * (nr_bins_shape+1) + step_index_shape < descLength_);
00564         assert (shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color >= 0 && shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color < descLength_);
00565         shot[interp_index * (nr_bins_shape+1) + step_index_shape] -= azimuthDistance;
00566         shot[shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color] -= azimuthDistance;
00567       }
00568     }
00569 
00570     assert (volume_index_shape + step_index_shape >= 0 &&  volume_index_shape + step_index_shape < descLength_);
00571     assert (volume_index_color + step_index_color >= 0 &&  volume_index_color + step_index_color < descLength_);
00572     shot[volume_index_shape + step_index_shape] += intWeightShape;
00573     shot[volume_index_color + step_index_color] += intWeightColor;
00574   }
00575 }
00576 
00577 
00579 template <typename PointNT, typename PointOutT> void
00580 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::computePointSHOT (
00581   const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot,
00582   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf)
00583 {
00584   if (rf.size () != 3)
00585     rf.resize (3);
00586 
00587   // Clear the resultant shot
00588   shot.setZero ();
00589   std::vector<double> binDistanceShape;
00590   std::vector<double> binDistanceColor;
00591   int nNeighbors = indices.size ();
00592   //Skip the current feature if the number of its neighbors is not sufficient for its description
00593   if (nNeighbors < 5)
00594   {
00595     PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index);
00596     return;
00597   }
00598 
00599   //Compute the local Reference Frame for the current 3D point
00600   Eigen::Vector4f central_point = input_->points[index].getVector4fMap ();
00601   central_point[3] = 0;
00602   if (pcl::getLocalRF (*surface_, search_radius_, central_point, indices, sqr_dists, rf))
00603     return;
00604 
00605   //If shape description is enabled, compute the bins activated by each neighbor of the current feature in the shape histogram
00606   if (b_describe_shape_)
00607   {
00608     binDistanceShape.resize (nNeighbors);
00609 
00610     for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00611     {
00612       double cosineDesc = normals_->points[indices[i_idx]].getNormalVector4fMap ().dot (rf[2]); //feat[i].rf[6]*normal[0] + feat[i].rf[7]*normal[1] + feat[i].rf[8]*normal[2];
00613 
00614       if (cosineDesc > 1.0)
00615         cosineDesc = 1.0;
00616       if (cosineDesc < - 1.0)
00617         cosineDesc = - 1.0;
00618 
00619       binDistanceShape[i_idx] = ((1.0 + cosineDesc) * nr_shape_bins_) / 2;
00620     }
00621   }
00622 
00623   //If color description is enabled, compute the bins activated by each neighbor of the current feature in the color histogram
00624   if (b_describe_color_)
00625   {
00626     binDistanceColor.resize (nNeighbors);
00627 
00628     unsigned char redRef = input_->points[index].rgba >> 16 & 0xFF;
00629     unsigned char greenRef = input_->points[index].rgba >> 8& 0xFF;
00630     unsigned char blueRef = input_->points[index].rgba & 0xFF;
00631 
00632     float LRef, aRef, bRef;
00633 
00634     RGB2CIELAB (redRef, greenRef, blueRef, LRef, aRef, bRef);
00635     LRef /= 100.0;
00636     aRef /= 120.0;
00637     bRef /= 120.0;    //normalized LAB components (0<L<1, -1<a<1, -1<b<1)
00638 
00639     for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx)
00640     {
00641       unsigned char red = surface_->points[indices[i_idx]].rgba >> 16 & 0xFF;
00642       unsigned char green = surface_->points[indices[i_idx]].rgba >> 8 & 0xFF;
00643       unsigned char blue = surface_->points[indices[i_idx]].rgba & 0xFF;
00644 
00645       float L, a, b;
00646 
00647       RGB2CIELAB (red, green, blue, L, a, b);
00648       L /= 100.0;
00649       a /= 120.0;
00650       b /= 120.0;   //normalized LAB components (0<L<1, -1<a<1, -1<b<1)
00651 
00652       double colorDistance = (fabs (LRef - L) + ((fabs (aRef - a) + fabs (bRef - b)) / 2)) /3;
00653 
00654       if (colorDistance > 1.0)
00655         colorDistance = 1.0;
00656       if (colorDistance < 0.0)
00657         colorDistance = 0.0;
00658 
00659       binDistanceColor[i_idx] = colorDistance * nr_color_bins_;
00660     }
00661   }
00662 
00663   //Apply quadrilinear interpolation on the activated bins in the shape and/or color histogram(s)
00664 
00665   if (b_describe_shape_ && b_describe_color_)
00666     interpolateDoubleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, binDistanceColor,
00667                               nr_shape_bins_, nr_color_bins_,
00668                               shot);
00669   else if (b_describe_color_)
00670     interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceColor, nr_color_bins_, shot);
00671   else
00672     interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot);
00673 
00674   // Normalize the final histogram
00675   this->normalizeHistogram (shot, descLength_);
00676 }
00677 
00678 
00680 template <typename PointInT, typename PointNT, typename PointOutT> void
00681 pcl::SHOTEstimation<PointInT, PointNT, PointOutT>::computePointSHOT (
00682   const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot,
00683   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf)
00684 {
00685   //Skip the current feature if the number of its neighbors is not sufficient for its description
00686   if (indices.size () < 5)
00687   {
00688     PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index);
00689     return;
00690   }
00691 
00692    // Clear the resultant shot
00693   std::vector<double> binDistanceShape;
00694   this->createBinDistanceShape (index, indices, sqr_dists, *input_, *normals_, *surface_, search_radius_, binDistanceShape, rf);
00695 
00696   // Interpolate
00697   shot.setZero ();
00698   interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot);
00699 
00700   // Normalize the final histogram
00701   this->normalizeHistogram (shot, descLength_);
00702 }
00703 
00704 
00706 template <typename PointInT, typename PointNT> void
00707 pcl::SHOTEstimation<PointInT, PointNT, Eigen::MatrixXf>::computePointSHOT (
00708   const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot,
00709   std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf)
00710 {
00711   //Skip the current feature if the number of its neighbors is not sufficient for its description
00712   if (indices.size () < 5)
00713   {
00714     PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index);
00715     return;
00716   }
00717 
00718    // Clear the resultant shot
00719   std::vector<double> binDistanceShape;
00720   this->createBinDistanceShape (index, indices, sqr_dists, *input_, *normals_, *surface_, search_radius_, binDistanceShape, rf);
00721 
00722   // Interpolate
00723   shot.setZero ();
00724   interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot);
00725 
00726   // Normalize the final histogram
00727   this->normalizeHistogram (shot, descLength_);
00728 }
00729 
00730 
00734 template <typename PointNT, typename PointOutT> void
00735 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
00736 {
00737   if (rf_.size () != 3)
00738     rf_.resize (3);
00739 
00740   // Compute the current length of the descriptor
00741   descLength_ = (b_describe_shape_) ? nr_grid_sector_*(nr_shape_bins_+1) : 0;
00742   descLength_ +=   (b_describe_color_) ? nr_grid_sector_*(nr_color_bins_+1) : 0;
00743 
00744   // Useful values
00745   sqradius_ = search_radius_*search_radius_;
00746   radius3_4_ = (search_radius_*3) / 4;
00747   radius1_4_ = search_radius_ / 4;
00748   radius1_2_ = search_radius_ / 2;
00749 
00750   shot_.setZero (descLength_);
00751   rf_[0].setZero ();
00752   rf_[1].setZero ();
00753   rf_[2].setZero ();
00754 
00755   if (output.points[0].descriptor.size () != (size_t)descLength_)
00756     for (size_t idx = 0; idx < indices_->size (); ++idx)
00757       output.points[idx].descriptor.resize (descLength_);
00758 //  if (output.points[0].size != (size_t)descLength_)
00759 //  {
00760 //    PCL_ERROR ("[pcl::%s::computeFeature] The desired descriptor size (%lu) does not match the output point type feature (%lu)! Aborting...\n", getClassName ().c_str (), descLength_, (unsigned long) output.points[0].size);
00761 //    return;
00762 //  }
00763 
00764   // Allocate enough space to hold the results
00765   // \note This resize is irrelevant for a radiusSearch ().
00766   std::vector<int> nn_indices (k_);
00767   std::vector<float> nn_dists (k_);
00768 
00769   output.is_dense = true;
00770   // Iterating over the entire index vector
00771   for (size_t idx = 0; idx < indices_->size (); ++idx)
00772   {
00773     if (!isFinite ((*input_)[(*indices_)[idx]]) ||
00774         this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
00775     {
00776       // Copy into the resultant cloud
00777       for (int d = 0; d < shot_.size (); ++d)
00778         output.points[idx].descriptor[d] = std::numeric_limits<float>::quiet_NaN ();
00779       for (int d = 0; d < 9; ++d)
00780         output.points[idx].rf[d] = std::numeric_limits<float>::quiet_NaN ();
00781 
00782       output.is_dense = false;
00783       continue;
00784      }
00785 
00786     // Compute the SHOT descriptor for the current 3D feature
00787     computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_);
00788 
00789     // Copy into the resultant cloud
00790     for (int d = 0; d < shot_.size (); ++d)
00791       output.points[idx].descriptor[d] = shot_[d];
00792     for (int d = 0; d < 9; ++d)
00793       output.points[idx].rf[d] = rf_[d/3][d%3];
00794   }
00795 }
00796 
00800 template <typename PointNT> void
00801 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, Eigen::MatrixXf>::computeFeature (pcl::PointCloud<Eigen::MatrixXf> &output)
00802 {
00803   if (rf_.size () != 3)
00804     rf_.resize (3);
00805 
00806   // Compute the current length of the descriptor
00807   descLength_ = (b_describe_shape_) ? nr_grid_sector_*(nr_shape_bins_+1) : 0;
00808   descLength_ +=   (b_describe_color_) ? nr_grid_sector_*(nr_color_bins_+1) : 0;
00809 
00810   // Useful values
00811   sqradius_ = search_radius_*search_radius_;
00812   radius3_4_ = (search_radius_*3) / 4;
00813   radius1_4_ = search_radius_ / 4;
00814   radius1_2_ = search_radius_ / 2;
00815 
00816   shot_.setZero (descLength_);
00817   rf_[0].setZero ();
00818   rf_[1].setZero ();
00819   rf_[2].setZero ();
00820 
00821   output.points.resize (indices_->size (), descLength_ + 9);
00822 
00823   // Allocate enough space to hold the results
00824   // \note This resize is irrelevant for a radiusSearch ().
00825   std::vector<int> nn_indices (k_);
00826   std::vector<float> nn_dists (k_);
00827 
00828   output.is_dense = true;
00829   // Iterating over the entire index vector
00830   for (size_t idx = 0; idx < indices_->size (); ++idx)
00831   {
00832     if (!isFinite ((*input_)[(*indices_)[idx]]) ||
00833         this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
00834     {
00835       output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
00836 
00837       output.is_dense = false;
00838       continue;
00839      }
00840 
00841     // Compute the SHOT descriptor for the current 3D feature
00842     this->computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_);
00843 
00844     // Copy into the resultant cloud
00845     for (int d = 0; d < shot_.size (); ++d)
00846       output.points (idx, d) = shot_[d];
00847     for (int d = 0; d < 9; ++d)
00848       output.points (idx, shot_.size () + d) = rf_[d/3][d%3];
00849   }
00850 }
00851 
00852 
00856 template <typename PointInT, typename PointNT, typename PointOutT> void
00857 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::computeFeature (pcl::PointCloud<PointOutT> &output)
00858 {
00859   if (rf_.size () != 3)
00860     rf_.resize (3);
00861 
00862   descLength_ = nr_grid_sector_ * (nr_shape_bins_+1);
00863 
00864   sqradius_ = search_radius_ * search_radius_;
00865   radius3_4_ = (search_radius_*3) / 4;
00866   radius1_4_ = search_radius_ / 4;
00867   radius1_2_ = search_radius_ / 2;
00868 
00869   shot_.setZero (descLength_);
00870   rf_[0].setZero ();
00871   rf_[1].setZero ();
00872   rf_[2].setZero ();
00873 
00874   if (output.points[0].descriptor.size () != (size_t)descLength_)
00875     for (size_t idx = 0; idx < indices_->size (); ++idx)
00876       output.points[idx].descriptor.resize (descLength_);
00877 //  if (output.points[0].size != (size_t)descLength_)
00878 //  {
00879 //    PCL_ERROR ("[pcl::%s::computeFeature] The desired descriptor size (%lu) does not match the output point type feature (%lu)! Aborting...\n", getClassName ().c_str (), descLength_, (unsigned long) output.points[0].size);
00880 //    return;
00881 //  }
00882 
00883   // Allocate enough space to hold the results
00884   // \note This resize is irrelevant for a radiusSearch ().
00885   std::vector<int> nn_indices (k_);
00886   std::vector<float> nn_dists (k_);
00887 
00888   output.is_dense = true;
00889   // Iterating over the entire index vector
00890   for (size_t idx = 0; idx < indices_->size (); ++idx)
00891   {
00892     if (!isFinite ((*input_)[(*indices_)[idx]]) ||
00893         this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
00894     {
00895       // Copy into the resultant cloud
00896       for (int d = 0; d < shot_.size (); ++d)
00897         output.points[idx].descriptor[d] = std::numeric_limits<float>::quiet_NaN ();
00898       for (int d = 0; d < 9; ++d)
00899         output.points[idx].rf[d] = std::numeric_limits<float>::quiet_NaN ();
00900 
00901       output.is_dense = false;
00902       continue;
00903      }
00904 
00905     // Estimate the SHOT at each patch
00906     computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_);
00907 
00908     // Copy into the resultant cloud
00909     for (int d = 0; d < shot_.size (); ++d)
00910       output.points[idx].descriptor[d] = shot_[d];
00911     for (int d = 0; d < 9; ++d)
00912       output.points[idx].rf[d] = rf_[d/3][d%3];
00913   }
00914 }
00915 
00919 template <typename PointInT, typename PointNT> void
00920 pcl::SHOTEstimationBase<PointInT, PointNT, Eigen::MatrixXf>::computeFeature (pcl::PointCloud<Eigen::MatrixXf> &output)
00921 {
00922   if (rf_.size () != 3)
00923     rf_.resize (3);
00924 
00925   descLength_ = nr_grid_sector_ * (nr_shape_bins_+1);
00926 
00927   sqradius_ = search_radius_ * search_radius_;
00928   radius3_4_ = (search_radius_*3) / 4;
00929   radius1_4_ = search_radius_ / 4;
00930   radius1_2_ = search_radius_ / 2;
00931 
00932   shot_.setZero (descLength_);
00933   rf_[0].setZero ();
00934   rf_[1].setZero ();
00935   rf_[2].setZero ();
00936 
00937   output.points.resize (indices_->size (), descLength_ + 9);
00938 
00939   // Allocate enough space to hold the results
00940   // \note This resize is irrelevant for a radiusSearch ().
00941   std::vector<int> nn_indices (k_);
00942   std::vector<float> nn_dists (k_);
00943 
00944   output.is_dense = true;
00945   // Iterating over the entire index vector
00946   for (size_t idx = 0; idx < indices_->size (); ++idx)
00947   {
00948     if (!isFinite ((*input_)[(*indices_)[idx]]) ||
00949         this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0)
00950     {
00951       output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ());
00952 
00953       output.is_dense = false;
00954       continue;
00955      }
00956 
00957     // Estimate the SHOT at each patch
00958     this->computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_);
00959 
00960     // Copy into the resultant cloud
00961     for (int d = 0; d < shot_.size (); ++d)
00962       output.points (idx, d) = shot_[d];
00963     for (int d = 0; d < 9; ++d)
00964       output.points (idx, shot_.size () + d) = rf_[d/3][d%3];
00965   }
00966 }
00967 
00968 #define PCL_INSTANTIATE_SHOTEstimationBase(T,NT,OutT) template class PCL_EXPORTS pcl::SHOTEstimationBase<T,NT,OutT>;
00969 #define PCL_INSTANTIATE_SHOTEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::SHOTEstimation<T,NT,OutT>;
00970 
00971 #endif    // PCL_FEATURES_IMPL_SHOT_H_
00972 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines