Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
harris_keypoint3D.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 #ifndef PCL_HARRIS_KEYPOINT_3D_IMPL_H_
00039 #define PCL_HARRIS_KEYPOINT_3D_IMPL_H_
00040 
00041 #include "pcl/keypoints/harris_keypoint3D.h"
00042 #include <pcl/common/io.h>
00043 #include <pcl/filters/passthrough.h>
00044 #include <pcl/filters/extract_indices.h>
00045 #include <pcl/features/normal_3d.h>
00046 #include <pcl/features/integral_image_normal.h>
00047 #include <pcl/common/time.h>
00048 #include <pcl/common/centroid.h>
00049 #ifdef __SSE__
00050 #include <xmmintrin.h>
00051 #endif
00052 
00054 template <typename PointInT, typename PointOutT, typename NormalT> void
00055 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setMethod (ResponseMethod method)
00056 {
00057   method_ = method;
00058 }
00059 
00061 template <typename PointInT, typename PointOutT, typename NormalT> void
00062 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setThreshold (float threshold)
00063 {
00064   threshold_= threshold;
00065 }
00066 
00068 template <typename PointInT, typename PointOutT, typename NormalT> void
00069 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setRadius (float radius)
00070 {
00071   search_radius_ = radius;
00072 }
00073 
00075 template <typename PointInT, typename PointOutT, typename NormalT> void
00076 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setRefine (bool do_refine)
00077 {
00078   refine_ = do_refine;
00079 }
00080 
00082 template <typename PointInT, typename PointOutT, typename NormalT> void
00083 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setNonMaxSupression (bool nonmax)
00084 {
00085   nonmax_ = nonmax;
00086 }
00087 
00089 template <typename PointInT, typename PointOutT, typename NormalT> void
00090 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::setNormals (boost::shared_ptr<pcl::PointCloud<NormalT> > normals ) const
00091 {
00092   normals_.reset (normals);
00093 }
00094 
00096 template <typename PointInT, typename PointOutT, typename NormalT> void
00097 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::calculateNormalCovar (const std::vector<int>& neighbors, float* coefficients) const
00098 {
00099   unsigned count = 0;
00100   // indices        0   1   2   3   4   5   6   7
00101   // coefficients: xx  xy  xz  ??  yx  yy  yz  ??
00102 #ifdef __SSE__
00103   // accumulator for xx, xy, xz
00104   __m128 vec1 = _mm_setzero_ps();
00105   // accumulator for yy, yz, zz
00106   __m128 vec2 = _mm_setzero_ps();
00107 
00108   __m128 norm1;
00109 
00110   __m128 norm2;
00111 
00112   float zz = 0;
00113 
00114   for (std::vector<int>::const_iterator iIt = neighbors.begin(); iIt != neighbors.end(); ++iIt)
00115   {
00116     if (pcl_isfinite (normals_->points[*iIt].normal_x))
00117     {
00118       // nx, ny, nz, h
00119       norm1 = _mm_load_ps (&(normals_->points[*iIt].normal_x));
00120 
00121       // nx, nx, nx, nx
00122       norm2 = _mm_set1_ps (normals_->points[*iIt].normal_x);
00123 
00124       // nx * nx, nx * ny, nx * nz, nx * h
00125       norm2 = _mm_mul_ps (norm1, norm2);
00126 
00127       // accumulate
00128       vec1 = _mm_add_ps (vec1, norm2);
00129 
00130       // ny, ny, ny, ny
00131       norm2 = _mm_set1_ps (normals_->points[*iIt].normal_y);
00132 
00133       // ny * nx, ny * ny, ny * nz, ny * h
00134       norm2 = _mm_mul_ps (norm1, norm2);
00135 
00136       // accumulate
00137       vec2 = _mm_add_ps (vec2, norm2);
00138 
00139       zz += normals_->points[*iIt].normal_z * normals_->points[*iIt].normal_z;
00140       ++count;
00141     }
00142   }
00143   if (count > 0)
00144   {
00145     norm2 = _mm_set1_ps (float(count));
00146     vec1 = _mm_div_ps (vec1, norm2);
00147     vec2 = _mm_div_ps (vec2, norm2);
00148     _mm_store_ps (coefficients, vec1);
00149     _mm_store_ps (coefficients + 4, vec2);
00150     coefficients [7] = zz / float(count);
00151   }
00152   else
00153     memset (coefficients, 0, sizeof (float) * 8);
00154 #else
00155   memset (coefficients, 0, sizeof (float) * 8);
00156   for (std::vector<int>::const_iterator iIt = neighbors.begin(); iIt != neighbors.end(); ++iIt)
00157   {
00158     if (pcl_isfinite (normals_->points[*iIt].normal_x))
00159     {
00160       coefficients[0] += normals_->points[*iIt].normal_x * normals_->points[*iIt].normal_x;
00161       coefficients[1] += normals_->points[*iIt].normal_x * normals_->points[*iIt].normal_y;
00162       coefficients[2] += normals_->points[*iIt].normal_x * normals_->points[*iIt].normal_z;
00163 
00164       coefficients[5] += normals_->points[*iIt].normal_y * normals_->points[*iIt].normal_y;
00165       coefficients[6] += normals_->points[*iIt].normal_y * normals_->points[*iIt].normal_z;
00166       coefficients[7] += normals_->points[*iIt].normal_z * normals_->points[*iIt].normal_z;
00167 
00168       ++count;
00169     }
00170   }
00171   if (count > 0)
00172   {
00173     float norm = 1.0 / float (count);
00174     coefficients[0] *= norm;
00175     coefficients[1] *= norm;
00176     coefficients[2] *= norm;
00177     coefficients[5] *= norm;
00178     coefficients[6] *= norm;
00179     coefficients[7] *= norm;
00180   }
00181 #endif
00182 }
00183 
00185 template <typename PointInT, typename PointOutT, typename NormalT> void
00186 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::detectKeypoints (PointCloudOut &output)
00187 {
00188   if (normals_->empty ())
00189   {
00190     normals_->reserve (surface_->size ());
00191     if (input_->height == 1 ) // not organized
00192     {
00193       pcl::NormalEstimation<PointInT, NormalT> normal_estimation;
00194       normal_estimation.setInputCloud(surface_);
00195       normal_estimation.setRadiusSearch(search_radius_);
00196       normal_estimation.compute (*normals_);
00197     }
00198     else
00199     {
00200       IntegralImageNormalEstimation<PointInT, NormalT> normal_estimation;
00201       normal_estimation.setNormalEstimationMethod (pcl::IntegralImageNormalEstimation<PointInT, NormalT>::SIMPLE_3D_GRADIENT);
00202       normal_estimation.setInputCloud(surface_);
00203       normal_estimation.setNormalSmoothingSize (5.0);
00204       normal_estimation.compute (*normals_);
00205     }
00206   }
00207 
00208   boost::shared_ptr<pcl::PointCloud<PointOutT> > response (new pcl::PointCloud<PointOutT> ());
00209 
00210   response->points.reserve (input_->points.size());
00211 
00212   switch (method_)
00213   {
00214     case HARRIS:
00215       responseHarris(*response);
00216       break;
00217     case NOBLE:
00218       responseNoble(*response);
00219       break;
00220     case LOWE:
00221       responseLowe(*response);
00222       break;
00223     case CURVATURE:
00224       responseCurvature(*response);
00225       break;
00226     case TOMASI:
00227       responseTomasi(*response);
00228       break;
00229   }
00230 
00231   if (!nonmax_)
00232     output = *response;
00233   else
00234   {
00235     output.points.clear ();
00236     output.points.reserve (response->points.size());
00237     std::vector<int> nn_indices;
00238     std::vector<float> nn_dists;
00239 
00240 #if defined __GNUC__
00241 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00242 #    pragma omp parallel for shared (output) private (nn_indices, nn_dists) num_threads(threads_)
00243 #  endif
00244 #endif
00245     for (int idx = 0; idx < (int) response->points.size (); ++idx)
00246     {
00247       if (!isFinite (response->points[idx]) || response->points[idx].intensity < threshold_)
00248         continue;
00249       tree_->radiusSearch (idx, search_radius_, nn_indices, nn_dists);
00250       bool is_maxima = true;
00251       for (std::vector<int>::const_iterator iIt = nn_indices.begin(); iIt != nn_indices.end(); ++iIt)
00252       {
00253         if (response->points[idx].intensity < response->points[*iIt].intensity)
00254         {
00255           is_maxima = false;
00256           break;
00257         }
00258       }
00259       if (is_maxima)
00260         #pragma omp critical
00261         output.points.push_back (response->points[idx]);
00262     }
00263 
00264     if (refine_)
00265       refineCorners (output);
00266 
00267     output.height = 1;
00268     output.width = output.points.size();
00269   }
00270 
00271   // we don not change the denseness
00272   output.is_dense = input_->is_dense;
00273 }
00274 
00276 template <typename PointInT, typename PointOutT, typename NormalT> void
00277 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::responseHarris (PointCloudOut &output) const
00278 {
00279   PCL_ALIGN (16) float covar [8];
00280   std::vector<int> nn_indices;
00281   std::vector<float> nn_dists;
00282   output.resize (input_->size ());
00283 #if defined __GNUC__
00284 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00285 #    pragma omp parallel for shared (output) private (covar, nn_indices, nn_dists) num_threads(threads_)
00286 #  endif
00287 #endif
00288   for (int pIdx = 0; pIdx < (int) input_->size (); ++pIdx)
00289   {
00290     const PointInT& pointIn = input_->points [pIdx];
00291     output [pIdx].intensity = 0.0; //std::numeric_limits<float>::quiet_NaN ();
00292     if (isFinite (pointIn))
00293     {
00294       tree_->radiusSearch (pointIn, search_radius_, nn_indices, nn_dists);
00295       calculateNormalCovar (nn_indices, covar);
00296 
00297       float trace = covar [0] + covar [5] + covar [7];
00298       if (trace != 0)
00299       {
00300         float det = covar [0] * covar [5] * covar [7] + 2.0 * covar [1] * covar [2] * covar [6]
00301                   - covar [2] * covar [2] * covar [5]
00302                   - covar [1] * covar [1] * covar [7]
00303                   - covar [6] * covar [6] * covar [0];
00304 
00305         output [pIdx].intensity = 0.04 + det - 0.04 * trace * trace;
00306       }
00307     }
00308     output [pIdx].x = pointIn.x;
00309     output [pIdx].y = pointIn.y;
00310     output [pIdx].z = pointIn.z;
00311   }
00312   output.height = input_->height;
00313   output.width = input_->width;
00314 }
00315 
00317 template <typename PointInT, typename PointOutT, typename NormalT> void
00318 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::responseNoble (PointCloudOut &output) const
00319 {
00320   std::vector<int> nn_indices;
00321   std::vector<float> nn_dists;
00322   PCL_ALIGN (16) float covar [8];
00323   output.resize (input_->size ());
00324 #if defined __GNUC__
00325 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00326 #    pragma omp parallel for shared (output) private (covar, nn_indices, nn_dists) num_threads(threads_)
00327 #  endif
00328 #endif
00329   for (int pIdx = 0; pIdx < (int) input_->size (); ++pIdx)
00330   {
00331     const PointInT& pointIn = input_->points [pIdx];
00332     output [pIdx].intensity = 0.0;
00333     if (isFinite (pointIn))
00334     {
00335       tree_->radiusSearch (pointIn, search_radius_, nn_indices, nn_dists);
00336       calculateNormalCovar (nn_indices, covar);
00337       float trace = covar [0] + covar [5] + covar [7];
00338       if (trace != 0)
00339       {
00340         float det = covar [0] * covar [5] * covar [7] + 2.0 * covar [1] * covar [2] * covar [6]
00341                   - covar [2] * covar [2] * covar [5]
00342                   - covar [1] * covar [1] * covar [7]
00343                   - covar [6] * covar [6] * covar [0];
00344 
00345         output [pIdx].intensity = det / trace;
00346       }
00347     }
00348     output [pIdx].x = pointIn.x;
00349     output [pIdx].y = pointIn.y;
00350     output [pIdx].z = pointIn.z;
00351   }
00352   output.height = input_->height;
00353   output.width = input_->width;
00354 }
00355 
00357 template <typename PointInT, typename PointOutT, typename NormalT> void
00358 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::responseLowe (PointCloudOut &output) const
00359 {
00360   std::vector<int> nn_indices;
00361   std::vector<float> nn_dists;
00362   PCL_ALIGN (16) float covar [8];
00363   output.resize (input_->size ());
00364 #if defined __GNUC__
00365 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00366 #    pragma omp parallel for shared (output) private (covar, nn_indices, nn_dists) num_threads(threads_)
00367 #  endif
00368 #endif
00369   for (int pIdx = 0; pIdx < (int) input_->size (); ++pIdx)
00370   {
00371     const PointInT& pointIn = input_->points [pIdx];
00372     output [pIdx].intensity = 0.0;
00373     if (isFinite (pointIn))
00374     {
00375       tree_->radiusSearch (pointIn, search_radius_, nn_indices, nn_dists);
00376       calculateNormalCovar (nn_indices, covar);
00377       float trace = covar [0] + covar [5] + covar [7];
00378       if (trace != 0)
00379       {
00380         float det = covar [0] * covar [5] * covar [7] + 2.0 * covar [1] * covar [2] * covar [6]
00381                   - covar [2] * covar [2] * covar [5]
00382                   - covar [1] * covar [1] * covar [7]
00383                   - covar [6] * covar [6] * covar [0];
00384 
00385         output [pIdx].intensity = det / (trace * trace);
00386       }
00387     }
00388     output [pIdx].x = pointIn.x;
00389     output [pIdx].y = pointIn.y;
00390     output [pIdx].z = pointIn.z;
00391   }
00392   output.height = input_->height;
00393   output.width = input_->width;
00394 }
00395 
00397 template <typename PointInT, typename PointOutT, typename NormalT> void
00398 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::responseCurvature (PointCloudOut &output) const
00399 {
00400   PointOutT point;
00401   for (unsigned idx = 0; idx < input_->points.size(); ++idx)
00402   {
00403     point.x = input_->points[idx].x;
00404     point.y = input_->points[idx].y;
00405     point.z = input_->points[idx].z;
00406     point.intensity = normals_->points[idx].curvature;
00407     output.points.push_back(point);
00408   }
00409   // does not change the order
00410   output.height = input_->height;
00411   output.width = input_->width;
00412 }
00413 
00415 template <typename PointInT, typename PointOutT, typename NormalT> void
00416 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::responseTomasi (PointCloudOut &output) const
00417 {
00418   std::vector<int> nn_indices;
00419   std::vector<float> nn_dists;
00420   PCL_ALIGN (16) float covar [8];
00421   Eigen::Matrix3f covariance_matrix;
00422   output.resize (input_->size ());
00423 #if defined __GNUC__
00424 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00425 #    pragma omp parallel for shared (output) private (covar, nn_indices, nn_dists, covariance_matrix) num_threads(threads_)
00426 #  endif
00427 #endif
00428   for (int pIdx = 0; pIdx < (int) input_->size (); ++pIdx)
00429   {
00430     const PointInT& pointIn = input_->points [pIdx];
00431     output [pIdx].intensity = 0.0;
00432     if (isFinite (pointIn))
00433     {
00434       tree_->radiusSearch (pointIn, search_radius_, nn_indices, nn_dists);
00435       calculateNormalCovar (nn_indices, covar);
00436       float trace = covar [0] + covar [5] + covar [7];
00437       if (trace != 0)
00438       {
00439         covariance_matrix.coeffRef (0) = covar [0];
00440         covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) = covar [1];
00441         covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) = covar [2];
00442         covariance_matrix.coeffRef (4) = covar [5];
00443         covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) = covar [6];
00444         covariance_matrix.coeffRef (8) = covar [7];
00445 
00446         EIGEN_ALIGN16 Eigen::Vector3f eigen_values;
00447         pcl::eigen33(covariance_matrix, eigen_values);
00448         output [pIdx].intensity = eigen_values[0];
00449       }
00450     }
00451     output [pIdx].x = pointIn.x;
00452     output [pIdx].y = pointIn.y;
00453     output [pIdx].z = pointIn.z;
00454   }
00455   output.height = input_->height;
00456   output.width = input_->width;
00457 }
00458 
00460 template <typename PointInT, typename PointOutT, typename NormalT> void
00461 pcl::HarrisKeypoint3D<PointInT, PointOutT, NormalT>::refineCorners (PointCloudOut &corners) const
00462 {
00463   std::vector<int> nn_indices;
00464   std::vector<float> nn_dists;
00465 
00466   Eigen::Matrix3f nnT;
00467   Eigen::Matrix3f NNT;
00468   Eigen::Matrix3f NNTInv;
00469   Eigen::Vector3f NNTp;
00470   float diff;
00471   const unsigned max_iterations = 10;
00472 #if defined __GNUC__
00473 #  if __GNUC__ == 4 && __GNUC_MINOR__ > 3
00474 #    pragma omp parallel for shared (corners) private (nnT, NNT, NNTInv, NNTp, diff, nn_indices, nn_dists) num_threads(threads_)
00475 #  endif
00476 #endif
00477   //for (typename PointCloudOut::iterator cornerIt = corners.begin(); cornerIt != corners.end(); ++cornerIt)
00478   for (int cIdx = 0; cIdx < (int) corners.size (); ++cIdx)
00479   {
00480     unsigned iterations = 0;
00481     do {
00482       NNT.setZero();
00483       NNTp.setZero();
00484       PointInT corner;
00485       corner.x = corners[cIdx].x;
00486       corner.y = corners[cIdx].y;
00487       corner.z = corners[cIdx].z;
00488       tree_->radiusSearch (corner, search_radius_, nn_indices, nn_dists);
00489       for (std::vector<int>::const_iterator iIt = nn_indices.begin(); iIt != nn_indices.end(); ++iIt)
00490       {
00491         if (!pcl_isfinite (normals_->points[*iIt].normal_x))
00492           continue;
00493 
00494         nnT = normals_->points[*iIt].getNormalVector3fMap () * normals_->points[*iIt].getNormalVector3fMap ().transpose();
00495         NNT += nnT;
00496         NNTp += nnT * surface_->points[*iIt].getVector3fMap ();
00497       }
00498       if (invert3x3SymMatrix (NNT, NNTInv) != 0)
00499         corners[cIdx].getVector3fMap () = NNTInv * NNTp;
00500 
00501       diff = (corners[cIdx].getVector3fMap () - corner.getVector3fMap()).squaredNorm ();
00502 //      diff = (cornerIt->x - corner.x) * (cornerIt->x - corner.x) +
00503 //             (cornerIt->y - corner.y) * (cornerIt->y - corner.y) +
00504 //             (cornerIt->z - corner.z) * (cornerIt->z - corner.z);
00505     } while (diff > 1e-6 && ++iterations < max_iterations);
00506   }
00507 }
00508 
00509 #define PCL_INSTANTIATE_HarrisKeypoint3D(T,U,N) template class PCL_EXPORTS pcl::HarrisKeypoint3D<T,U,N>;
00510 #endif // #ifndef PCL_HARRIS_KEYPOINT_3D_IMPL_H_
00511