|
Point Cloud Library (PCL)
1.4.0
|
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 * $Id: usc.hpp 3755 2011-12-31 23:45:30Z rusu $ 00037 * 00038 */ 00039 00040 #ifndef PCL_FEATURES_IMPL_USC_HPP_ 00041 #define PCL_FEATURES_IMPL_USC_HPP_ 00042 00043 #include <pcl/features/usc.h> 00044 #include <pcl/features/shot_common.h> 00045 #include <pcl/common/geometry.h> 00046 #include <pcl/common/angles.h> 00047 #include <pcl/common/utils.h> 00048 00050 template <typename PointInT, typename PointOutT> bool 00051 pcl::UniqueShapeContext<PointInT, PointOutT>::initCompute () 00052 { 00053 if (!Feature<PointInT, PointOutT>::initCompute ()) 00054 { 00055 PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ()); 00056 return (false); 00057 } 00058 00059 if (search_radius_< min_radius_) 00060 { 00061 PCL_ERROR ("[pcl::%s::initCompute] search_radius_ must be GREATER than min_radius_.\n", getClassName ().c_str ()); 00062 return (false); 00063 } 00064 00065 // Update descriptor length 00066 descriptor_length_ = elevation_bins_ * azimuth_bins_ * radius_bins_; 00067 00068 // Compute radial, elevation and azimuth divisions 00069 float azimuth_interval = (float) 360 / azimuth_bins_; 00070 float elevation_interval = (float) 180 / elevation_bins_; 00071 00072 // Reallocate divisions and volume lut 00073 radii_interval_.clear (); 00074 phi_divisions_.clear (); 00075 theta_divisions_.clear (); 00076 volume_lut_.clear (); 00077 00078 // Fills radii interval based on formula (1) in section 2.1 of Frome's paper 00079 radii_interval_.resize (radius_bins_ + 1); 00080 for (size_t j = 0; j < radius_bins_ + 1; j++) 00081 radii_interval_[j] = exp (log (min_radius_) + (((float) j / (radius_bins_)) * log (search_radius_/min_radius_))); 00082 00083 // Fill theta didvisions of elevation 00084 theta_divisions_.resize (elevation_bins_+1); 00085 for (size_t k = 0; k < elevation_bins_+1; k++) 00086 theta_divisions_[k] = k*elevation_interval; 00087 00088 // Fill phi didvisions of elevation 00089 phi_divisions_.resize (azimuth_bins_+1); 00090 for (size_t l = 0; l < azimuth_bins_+1; l++) 00091 phi_divisions_[l] = l*azimuth_interval; 00092 00093 // LookUp Table that contains the volume of all the bins 00094 // "phi" term of the volume integral 00095 // "integr_phi" has always the same value so we compute it only one time 00096 float integr_phi = pcl::deg2rad (phi_divisions_[1]) - pcl::deg2rad (phi_divisions_[0]); 00097 // exponential to compute the cube root using pow 00098 float e = 1.0 / 3.0; 00099 // Resize volume look up table 00100 volume_lut_.resize (radius_bins_ * elevation_bins_ * azimuth_bins_); 00101 // Fill volumes look up table 00102 for (size_t j = 0; j < radius_bins_; j++) 00103 { 00104 // "r" term of the volume integral 00105 float integr_r = (radii_interval_[j+1]*radii_interval_[j+1]*radii_interval_[j+1] / 3) - (radii_interval_[j]*radii_interval_[j]*radii_interval_[j]/ 3); 00106 00107 for (size_t k = 0; k < elevation_bins_; k++) 00108 { 00109 // "theta" term of the volume integral 00110 float integr_theta = cos (deg2rad (theta_divisions_[k])) - cos (deg2rad (theta_divisions_[k+1])); 00111 // Volume 00112 float V = integr_phi * integr_theta * integr_r; 00113 // Compute cube root of the computed volume commented for performance but left 00114 // here for clarity 00115 // float cbrt = pow(V, e); 00116 // cbrt = 1 / cbrt; 00117 00118 for (size_t l = 0; l < azimuth_bins_; l++) 00119 // Store in lut 1/cbrt 00120 //volume_lut_[ (l*elevation_bins_*radius_bins_) + k*radius_bins_ + j ] = cbrt; 00121 volume_lut_[(l*elevation_bins_*radius_bins_) + k*radius_bins_ + j] = 1.0 / pow (V, e); 00122 } 00123 } 00124 return (true); 00125 } 00126 00128 template <typename PointInT, typename PointOutT> bool 00129 pcl::UniqueShapeContext<PointInT, PointOutT>::computePointRF (size_t index, float rf[9]) 00130 { 00131 std::vector<int> nn_indices; 00132 std::vector<float> nn_dists; 00133 size_t nb_neighbours = searchForNeighbors ((*indices_)[index], local_radius_, nn_indices, nn_dists); 00134 00135 // The RF is formed as the SHOT local RF 00136 if (nb_neighbours < 5) 00137 { 00138 //PCL_WARN ("[pcl::%s::computePointRF] Neighborhood has %d vertices which is less than 5, aborting description of point index %d\n!", getClassName ().c_str (), nb_neighbours, (*indices_)[index]); 00139 return (false); 00140 } 00141 std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > rf_ (3); 00142 Eigen::Vector4f central_point = input_->points[(*indices_)[index]].getVector4fMap (); 00143 central_point[3] = 0; 00144 pcl::getLocalRF (*surface_, local_radius_, central_point /*(*indices_)[index]*/, nn_indices, nn_dists, rf_); 00145 for (int d = 0; d < 9; ++d) 00146 rf[d] = rf_[d/3][d%3]; 00147 00148 return (true); 00149 } 00150 00152 template <typename PointInT, typename PointOutT> void 00153 pcl::UniqueShapeContext<PointInT, PointOutT>::computePointDescriptor (size_t index, float rf[9], std::vector<float> &desc) 00154 { 00155 pcl::Vector3fMapConst origin = input_->points[(*indices_)[index]].getVector3fMap (); 00156 const Eigen::Map<Eigen::Vector3f> x_axis (rf); 00157 const Eigen::Map<Eigen::Vector3f> y_axis (rf + 3); 00158 const Eigen::Map<Eigen::Vector3f> normal (rf + 6); 00159 // Find every point within specified search_radius_ 00160 std::vector<int> nn_indices; 00161 std::vector<float> nn_dists; 00162 const size_t neighb_cnt = searchForNeighbors ((*indices_)[index], search_radius_, nn_indices, nn_dists); 00163 // For each point within radius 00164 for (size_t ne = 0; ne < neighb_cnt; ne++) 00165 { 00166 if (pcl::utils::equal(nn_dists[ne], 0.0f)) 00167 continue; 00168 // Get neighbours coordinates 00169 Eigen::Vector3f neighbour = surface_->points[nn_indices[ne]].getVector3fMap (); 00170 00171 // ----- Compute current neighbour polar coordinates ----- 00172 00173 // Get distance between the neighbour and the origin 00174 float r = sqrt (nn_dists[ne]); 00175 00176 // Project point into the tangent plane 00177 Eigen::Vector3f proj; 00178 pcl::geometry::project (neighbour, origin, normal, proj); 00179 proj -= origin; 00180 00181 // Normalize to compute the dot product 00182 proj.normalize (); 00183 00184 // Compute the angle between the projection and the x axis in the interval [0,360] 00185 Eigen::Vector3f cross = x_axis.cross (proj); 00186 float phi = rad2deg (std::atan2 (cross.norm (), x_axis.dot (proj))); 00187 phi = cross.dot (normal) < 0.f ? (360.0 - phi) : phi; 00189 Eigen::Vector3f no = neighbour - origin; 00190 no.normalize (); 00191 float theta = normal.dot (no); 00192 theta = pcl::rad2deg (acos (std::min (1.0f, std::max (-1.0f, theta)))); 00193 00195 size_t j = 0; 00196 size_t k = 0; 00197 size_t l = 0; 00198 00200 for (size_t rad = 1; rad < radius_bins_ + 1; rad++) 00201 { 00202 if (r <= radii_interval_[rad]) 00203 { 00204 j = rad - 1; 00205 break; 00206 } 00207 } 00208 00209 for (size_t ang = 1; ang < elevation_bins_ + 1; ang++) 00210 { 00211 if (theta <= theta_divisions_[ang]) 00212 { 00213 k = ang - 1; 00214 break; 00215 } 00216 } 00217 00218 for (size_t ang = 1; ang < azimuth_bins_ + 1; ang++) 00219 { 00220 if (phi <= phi_divisions_[ang]) 00221 { 00222 l = ang - 1; 00223 break; 00224 } 00225 } 00226 00228 std::vector<int> neighbour_indices; 00229 std::vector<float> neighbour_didtances; 00230 float point_density = (float) searchForNeighbors (*surface_, nn_indices[ne], point_density_radius_, neighbour_indices, neighbour_didtances); 00232 float w = (1.0 / point_density) * volume_lut_[(l*elevation_bins_*radius_bins_) + 00233 (k*radius_bins_) + 00234 j]; 00235 00236 assert (w >= 0.0); 00237 if (w == std::numeric_limits<float>::infinity ()) 00238 PCL_ERROR ("Shape Context Error INF!\n"); 00239 if (w != w) 00240 PCL_ERROR ("Shape Context Error IND!\n"); 00242 desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] += w; 00243 00244 assert (desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] >= 0); 00245 } // end for each neighbour 00246 } 00247 00249 template <typename PointInT, typename PointOutT> void 00250 pcl::UniqueShapeContext<PointInT, PointOutT>::computeFeature (PointCloudOut &output) 00251 { 00252 for (size_t point_index = 0; point_index < indices_->size (); point_index++) 00253 { 00254 output[point_index].descriptor.resize (descriptor_length_); 00255 computePointRF (point_index, output[point_index].rf); 00256 computePointDescriptor (point_index, output[point_index].rf, output[point_index].descriptor); 00257 } 00258 } 00259 00261 template <typename PointInT> void 00262 pcl::UniqueShapeContext<PointInT, Eigen::MatrixXf>::computeFeature (pcl::PointCloud<Eigen::MatrixXf> &output) 00263 { 00264 output.points.resize (indices_->size (), descriptor_length_ + 9); 00265 for (size_t point_index = 0; point_index < indices_->size (); point_index++) 00266 { 00267 computePointRF (point_index, output.points.row (point_index).data ()); 00268 std::vector<float> descriptor (descriptor_length_); 00269 computePointDescriptor (point_index, output.points.row (point_index).data (), descriptor); 00270 for (size_t j = 0; j < descriptor_length_; ++j) 00271 output.points (point_index, 9 + j) = descriptor[j]; 00272 } 00273 } 00274 00275 #define PCL_INSTANTIATE_UniqueShapeContext(T,OutT) template class PCL_EXPORTS pcl::UniqueShapeContext<T,OutT>; 00276 00277 #endif
1.7.6.1