|
Point Cloud Library (PCL)
1.6.0
|
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2011, Alexandru-Eugen Ichim 00005 * Willow Garage, Inc 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions 00010 * are met: 00011 * 00012 * * Redistributions of source code must retain the above copyright 00013 * notice, this list of conditions and the following disclaimer. 00014 * * Redistributions in binary form must reproduce the above 00015 * copyright notice, this list of conditions and the following 00016 * disclaimer in the documentation and/or other materials provided 00017 * with the distribution. 00018 * * Neither the name of Willow Garage, Inc. nor the names of its 00019 * contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00025 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00026 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00028 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00030 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00032 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00033 * POSSIBILITY OF SUCH DAMAGE. 00034 * 00035 * $Id: ppf_registration.hpp 5121 2012-03-16 03:03:47Z rusu $ 00036 */ 00037 00038 00039 #ifndef PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_ 00040 #define PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_ 00041 00042 //#include <pcl/registration/ppf_registration.h> 00043 #include <pcl/features/ppf.h> 00044 #include <pcl/common/transforms.h> 00045 00046 #include <pcl/features/pfh.h> 00048 void 00049 pcl::PPFHashMapSearch::setInputFeatureCloud (PointCloud<PPFSignature>::ConstPtr feature_cloud) 00050 { 00051 // Discretize the feature cloud and insert it in the hash map 00052 feature_hash_map_->clear (); 00053 unsigned int n = static_cast<unsigned int> (sqrt (static_cast<float> (feature_cloud->points.size ()))); 00054 int d1, d2, d3, d4; 00055 max_dist_ = -1.0; 00056 alpha_m_.resize (n); 00057 for (size_t i = 0; i < n; ++i) 00058 { 00059 std::vector <float> alpha_m_row (n); 00060 for (size_t j = 0; j < n; ++j) 00061 { 00062 d1 = static_cast<int> (floor (feature_cloud->points[i*n+j].f1 / angle_discretization_step_)); 00063 d2 = static_cast<int> (floor (feature_cloud->points[i*n+j].f2 / angle_discretization_step_)); 00064 d3 = static_cast<int> (floor (feature_cloud->points[i*n+j].f3 / angle_discretization_step_)); 00065 d4 = static_cast<int> (floor (feature_cloud->points[i*n+j].f4 / distance_discretization_step_)); 00066 feature_hash_map_->insert (std::pair<HashKeyStruct, std::pair<size_t, size_t> > (HashKeyStruct (d1, d2, d3, d4), std::pair<size_t, size_t> (i, j))); 00067 alpha_m_row [j] = feature_cloud->points[i*n + j].alpha_m; 00068 00069 if (max_dist_ < feature_cloud->points[i*n + j].f4) 00070 max_dist_ = feature_cloud->points[i*n + j].f4; 00071 } 00072 alpha_m_[i] = alpha_m_row; 00073 } 00074 00075 internals_initialized_ = true; 00076 } 00077 00078 00080 void 00081 pcl::PPFHashMapSearch::nearestNeighborSearch (float &f1, float &f2, float &f3, float &f4, 00082 std::vector<std::pair<size_t, size_t> > &indices) 00083 { 00084 if (!internals_initialized_) 00085 { 00086 PCL_ERROR("[pcl::PPFRegistration::nearestNeighborSearch]: input feature cloud has not been set - skipping search!\n"); 00087 return; 00088 } 00089 00090 int d1 = static_cast<int> (floor (f1 / angle_discretization_step_)), 00091 d2 = static_cast<int> (floor (f2 / angle_discretization_step_)), 00092 d3 = static_cast<int> (floor (f3 / angle_discretization_step_)), 00093 d4 = static_cast<int> (floor (f4 / distance_discretization_step_)); 00094 00095 indices.clear (); 00096 HashKeyStruct key = HashKeyStruct (d1, d2, d3, d4); 00097 std::pair <FeatureHashMapType::iterator, FeatureHashMapType::iterator> map_iterator_pair = feature_hash_map_->equal_range (key); 00098 for (; map_iterator_pair.first != map_iterator_pair.second; ++ map_iterator_pair.first) 00099 indices.push_back (std::pair<size_t, size_t> (map_iterator_pair.first->second.first, 00100 map_iterator_pair.first->second.second)); 00101 } 00102 00103 00105 template <typename PointSource, typename PointTarget> void 00106 pcl::PPFRegistration<PointSource, PointTarget>::setInputTarget (const PointCloudTargetConstPtr &cloud) 00107 { 00108 Registration<PointSource, PointTarget>::setInputTarget (cloud); 00109 00110 scene_search_tree_ = typename pcl::KdTreeFLANN<PointTarget>::Ptr (new pcl::KdTreeFLANN<PointTarget>); 00111 scene_search_tree_->setInputCloud (target_); 00112 } 00113 00114 00116 template <typename PointSource, typename PointTarget> void 00117 pcl::PPFRegistration<PointSource, PointTarget>::computeTransformation (PointCloudSource &output, const Eigen::Matrix4f& guess) 00118 { 00119 if (!search_method_) 00120 { 00121 PCL_ERROR("[pcl::PPFRegistration::computeTransformation] Search method not set - skipping computeTransformation!\n"); 00122 return; 00123 } 00124 00125 if (guess != Eigen::Matrix4f::Identity ()) 00126 { 00127 PCL_ERROR("[pcl::PPFRegistration::computeTransformation] setting initial transform (guess) not implemented!\n"); 00128 } 00129 00130 PoseWithVotesList voted_poses; 00131 std::vector <std::vector <unsigned int> > accumulator_array; 00132 accumulator_array.resize (input_->points.size ()); 00133 for (size_t i = 0; i < input_->points.size (); ++i) 00134 { 00135 std::vector <unsigned int> aux (static_cast<size_t> (floor(2*M_PI / search_method_->getAngleDiscretizationStep ()), 0)); 00136 accumulator_array[i] = aux; 00137 } 00138 PCL_INFO ("Accumulator array size: %u x %u.\n", accumulator_array.size (), accumulator_array.back ().size ()); 00139 00140 // Consider every <scene_reference_point_sampling_rate>-th point as the reference point => fix s_r 00141 float f1, f2, f3, f4; 00142 for (size_t scene_reference_index = 0; scene_reference_index < target_->points.size (); scene_reference_index += scene_reference_point_sampling_rate_) 00143 { 00144 Eigen::Vector3f scene_reference_point = target_->points[scene_reference_index].getVector3fMap (), 00145 scene_reference_normal = target_->points[scene_reference_index].getNormalVector3fMap (); 00146 00147 Eigen::AngleAxisf rotation_sg (acosf (scene_reference_normal.dot (Eigen::Vector3f::UnitX ())), 00148 scene_reference_normal.cross (Eigen::Vector3f::UnitX ()). normalized()); 00149 Eigen::Affine3f transform_sg = Eigen::Translation3f ( rotation_sg* ((-1)*scene_reference_point)) * rotation_sg; 00150 00151 // For every other point in the scene => now have pair (s_r, s_i) fixed 00152 std::vector<int> indices; 00153 std::vector<float> distances; 00154 scene_search_tree_->radiusSearch (target_->points[scene_reference_index], 00155 search_method_->getModelDiameter () /2, 00156 indices, 00157 distances); 00158 for(size_t i = 0; i < indices.size (); ++i) 00159 // for(size_t i = 0; i < target_->points.size (); ++i) 00160 { 00161 //size_t scene_point_index = i; 00162 size_t scene_point_index = indices[i]; 00163 if (scene_reference_index != scene_point_index) 00164 { 00165 if (/*pcl::computePPFPairFeature*/pcl::computePairFeatures (target_->points[scene_reference_index].getVector4fMap (), 00166 target_->points[scene_reference_index].getNormalVector4fMap (), 00167 target_->points[scene_point_index].getVector4fMap (), 00168 target_->points[scene_point_index].getNormalVector4fMap (), 00169 f1, f2, f3, f4)) 00170 { 00171 std::vector<std::pair<size_t, size_t> > nearest_indices; 00172 search_method_->nearestNeighborSearch (f1, f2, f3, f4, nearest_indices); 00173 00174 // Compute alpha_s angle 00175 Eigen::Vector3f scene_point = target_->points[scene_point_index].getVector3fMap (); 00176 Eigen::AngleAxisf rotation_sg (acosf (scene_reference_normal.dot (Eigen::Vector3f::UnitX ())), 00177 scene_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ()); 00178 Eigen::Affine3f transform_sg = Eigen::Translation3f ( rotation_sg * ((-1) * scene_reference_point)) * rotation_sg; 00179 // float alpha_s = acos (Eigen::Vector3f::UnitY ().dot ((transform_sg * scene_point).normalized ())); 00180 00181 Eigen::Vector3f scene_point_transformed = transform_sg * scene_point; 00182 float alpha_s = atan2f ( -scene_point_transformed(2), scene_point_transformed(1)); 00183 if ( alpha_s != alpha_s) 00184 { 00185 PCL_ERROR ("alpha_s is nan\n"); 00186 continue; 00187 } 00188 if (sin (alpha_s) * scene_point_transformed(2) < 0.0f) 00189 alpha_s *= (-1); 00190 alpha_s *= (-1); 00191 00192 // Go through point pairs in the model with the same discretized feature 00193 for (std::vector<std::pair<size_t, size_t> >::iterator v_it = nearest_indices.begin (); v_it != nearest_indices.end (); ++ v_it) 00194 { 00195 size_t model_reference_index = v_it->first, 00196 model_point_index = v_it->second; 00197 // Calculate angle alpha = alpha_m - alpha_s 00198 float alpha = search_method_->alpha_m_[model_reference_index][model_point_index] - alpha_s; 00199 unsigned int alpha_discretized = static_cast<unsigned int> (floor (alpha) + floor (M_PI / search_method_->getAngleDiscretizationStep ())); 00200 accumulator_array[model_reference_index][alpha_discretized] ++; 00201 } 00202 } 00203 else PCL_ERROR ("[pcl::PPFRegistration::computeTransformation] Computing pair feature vector between points %zu and %zu went wrong.\n", scene_reference_index, scene_point_index); 00204 } 00205 } 00206 00207 size_t max_votes_i = 0, max_votes_j = 0; 00208 unsigned int max_votes = 0; 00209 00210 for (size_t i = 0; i < accumulator_array.size (); ++i) 00211 for (size_t j = 0; j < accumulator_array.back ().size (); ++j) 00212 { 00213 if (accumulator_array[i][j] > max_votes) 00214 { 00215 max_votes = accumulator_array[i][j]; 00216 max_votes_i = i; 00217 max_votes_j = j; 00218 } 00219 // Reset accumulator_array for the next set of iterations with a new scene reference point 00220 accumulator_array[i][j] = 0; 00221 } 00222 00223 Eigen::Vector3f model_reference_point = input_->points[max_votes_i].getVector3fMap (), 00224 model_reference_normal = input_->points[max_votes_i].getNormalVector3fMap (); 00225 Eigen::AngleAxisf rotation_mg (acosf (model_reference_normal.dot (Eigen::Vector3f::UnitX ())), model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ()); 00226 Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg; 00227 Eigen::Affine3f max_transform = 00228 transform_sg.inverse () * 00229 Eigen::AngleAxisf ((static_cast<float> (max_votes_j) - floorf (static_cast<float> (M_PI) / search_method_->getAngleDiscretizationStep ())) * search_method_->getAngleDiscretizationStep (), Eigen::Vector3f::UnitX ()) * 00230 transform_mg; 00231 00232 voted_poses.push_back (PoseWithVotes (max_transform, max_votes)); 00233 } 00234 PCL_DEBUG ("Done with the Hough Transform ...\n"); 00235 00236 // Cluster poses for filtering out outliers and obtaining more precise results 00237 PoseWithVotesList results; 00238 clusterPoses (voted_poses, results); 00239 00240 pcl::transformPointCloud (*input_, output, results.front ().pose); 00241 00242 transformation_ = final_transformation_ = results.front ().pose.matrix (); 00243 converged_ = true; 00244 } 00245 00246 00248 template <typename PointSource, typename PointTarget> void 00249 pcl::PPFRegistration<PointSource, PointTarget>::clusterPoses (typename pcl::PPFRegistration<PointSource, PointTarget>::PoseWithVotesList &poses, 00250 typename pcl::PPFRegistration<PointSource, PointTarget>::PoseWithVotesList &result) 00251 { 00252 PCL_INFO ("Clustering poses ...\n"); 00253 // Start off by sorting the poses by the number of votes 00254 sort(poses.begin (), poses.end (), poseWithVotesCompareFunction); 00255 00256 std::vector<PoseWithVotesList> clusters; 00257 std::vector<std::pair<size_t, unsigned int> > cluster_votes; 00258 for (size_t poses_i = 0; poses_i < poses.size(); ++ poses_i) 00259 { 00260 bool found_cluster = false; 00261 for (size_t clusters_i = 0; clusters_i < clusters.size(); ++ clusters_i) 00262 { 00263 if (posesWithinErrorBounds (poses[poses_i].pose, clusters[clusters_i].front ().pose)) 00264 { 00265 found_cluster = true; 00266 clusters[clusters_i].push_back (poses[poses_i]); 00267 cluster_votes[clusters_i].second += poses[poses_i].votes; 00268 break; 00269 } 00270 } 00271 00272 if (found_cluster == false) 00273 { 00274 // Create a new cluster with the current pose 00275 PoseWithVotesList new_cluster; 00276 new_cluster.push_back (poses[poses_i]); 00277 clusters.push_back (new_cluster); 00278 cluster_votes.push_back (std::pair<size_t, unsigned int> (clusters.size () - 1, poses[poses_i].votes)); 00279 } 00280 } 00281 00282 // Sort clusters by total number of votes 00283 std::sort (cluster_votes.begin (), cluster_votes.end (), clusterVotesCompareFunction); 00284 // Compute pose average and put them in result vector 00287 result.clear (); 00288 size_t max_clusters = (clusters.size () < 3) ? clusters.size () : 3; 00289 for (size_t cluster_i = 0; cluster_i < max_clusters; ++ cluster_i) 00290 { 00291 PCL_INFO ("Winning cluster has #votes: %d and #poses voted: %d.\n", cluster_votes[cluster_i].second, clusters[cluster_votes[cluster_i].first].size ()); 00292 Eigen::Vector3f translation_average (0.0, 0.0, 0.0); 00293 Eigen::Vector4f rotation_average (0.0, 0.0, 0.0, 0.0); 00294 for (typename PoseWithVotesList::iterator v_it = clusters[cluster_votes[cluster_i].first].begin (); v_it != clusters[cluster_votes[cluster_i].first].end (); ++ v_it) 00295 { 00296 translation_average += v_it->pose.translation (); 00298 rotation_average += Eigen::Quaternionf (v_it->pose.rotation ()).coeffs (); 00299 } 00300 00301 translation_average /= static_cast<float> (clusters[cluster_votes[cluster_i].first].size ()); 00302 rotation_average /= static_cast<float> (clusters[cluster_votes[cluster_i].first].size ()); 00303 00304 Eigen::Affine3f transform_average; 00305 transform_average.translation () = translation_average; 00306 transform_average.linear () = Eigen::Quaternionf (rotation_average).normalized().toRotationMatrix (); 00307 00308 result.push_back (PoseWithVotes (transform_average, cluster_votes[cluster_i].second)); 00309 } 00310 } 00311 00312 00314 template <typename PointSource, typename PointTarget> bool 00315 pcl::PPFRegistration<PointSource, PointTarget>::posesWithinErrorBounds (Eigen::Affine3f &pose1, 00316 Eigen::Affine3f &pose2) 00317 { 00318 float position_diff = (pose1.translation () - pose2.translation ()).norm (); 00319 Eigen::AngleAxisf rotation_diff_mat (pose1.rotation ().inverse () * pose2.rotation ()); 00320 00321 float rotation_diff_angle = fabsf (rotation_diff_mat.angle ()); 00322 00323 if (position_diff < clustering_position_diff_threshold_ && rotation_diff_angle < clustering_rotation_diff_threshold_) 00324 return true; 00325 else return false; 00326 } 00327 00328 00330 template <typename PointSource, typename PointTarget> bool 00331 pcl::PPFRegistration<PointSource, PointTarget>::poseWithVotesCompareFunction (const typename pcl::PPFRegistration<PointSource, PointTarget>::PoseWithVotes &a, 00332 const typename pcl::PPFRegistration<PointSource, PointTarget>::PoseWithVotes &b ) 00333 { 00334 return (a.votes > b.votes); 00335 } 00336 00337 00339 template <typename PointSource, typename PointTarget> bool 00340 pcl::PPFRegistration<PointSource, PointTarget>::clusterVotesCompareFunction (const std::pair<size_t, unsigned int> &a, 00341 const std::pair<size_t, unsigned int> &b) 00342 { 00343 return (a.second > b.second); 00344 } 00345 00346 //#define PCL_INSTANTIATE_PPFRegistration(PointSource,PointTarget) template class PCL_EXPORTS pcl::PPFRegistration<PointSource, PointTarget>; 00347 00348 #endif // PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_
1.7.6.1