42 #ifndef PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_
43 #define PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_
45 #include <pcl/common/transforms.h>
46 #include <pcl/features/pfh.h>
47 #include <pcl/features/pfh_tools.h>
48 #include <pcl/features/ppf.h>
49 #include <pcl/registration/ppf_registration.h>
51 template <
typename Po
intSource,
typename Po
intTarget>
60 scene_search_tree_->setInputCloud(target_);
64 template <
typename Po
intSource,
typename Po
intTarget>
67 PointCloudSource& output,
const Eigen::Matrix4f& guess)
69 if (!search_method_) {
70 PCL_ERROR(
"[pcl::PPFRegistration::computeTransformation] Search method not set - "
71 "skipping computeTransformation!\n");
75 if (guess != Eigen::Matrix4f::Identity()) {
76 PCL_ERROR(
"[pcl::PPFRegistration::computeTransformation] setting initial transform "
77 "(guess) not implemented!\n");
80 const auto aux_size =
static_cast<std::size_t
>(
81 std::floor(2 *
M_PI / search_method_->getAngleDiscretizationStep()));
83 const std::vector<unsigned int> tmp_vec(aux_size, 0);
84 std::vector<std::vector<unsigned int>> accumulator_array(input_->size(), tmp_vec);
86 PCL_INFO(
"Accumulator array size: %u x %u.\n",
87 accumulator_array.size(),
88 accumulator_array.back().size());
90 PoseWithVotesList voted_poses;
94 for (std::size_t scene_reference_index = 0; scene_reference_index < target_->size();
95 scene_reference_index += scene_reference_point_sampling_rate_) {
96 Eigen::Vector3f scene_reference_point =
97 (*target_)[scene_reference_index].getVector3fMap(),
98 scene_reference_normal =
99 (*target_)[scene_reference_index].getNormalVector3fMap();
101 float rotation_angle_sg =
102 std::acos(scene_reference_normal.dot(Eigen::Vector3f::UnitX()));
103 bool parallel_to_x_sg =
104 (scene_reference_normal.y() == 0.0f && scene_reference_normal.z() == 0.0f);
105 Eigen::Vector3f rotation_axis_sg =
107 ? (Eigen::Vector3f::UnitY())
108 : (scene_reference_normal.cross(Eigen::Vector3f::UnitX()).
normalized());
109 Eigen::AngleAxisf rotation_sg(rotation_angle_sg, rotation_axis_sg);
110 Eigen::Affine3f transform_sg(
111 Eigen::Translation3f(rotation_sg * ((-1) * scene_reference_point)) *
115 std::vector<int> indices;
116 std::vector<float> distances;
117 scene_search_tree_->radiusSearch((*target_)[scene_reference_index],
118 search_method_->getModelDiameter() / 2,
121 for (
const auto& scene_point_index : indices)
125 if (scene_reference_index != scene_point_index) {
127 (*target_)[scene_reference_index].getVector4fMap(),
128 (*target_)[scene_reference_index].getNormalVector4fMap(),
129 (*target_)[scene_point_index].getVector4fMap(),
130 (*target_)[scene_point_index].getNormalVector4fMap(),
135 std::vector<std::pair<std::size_t, std::size_t>> nearest_indices;
136 search_method_->nearestNeighborSearch(f1, f2, f3, f4, nearest_indices);
139 Eigen::Vector3f scene_point = (*target_)[scene_point_index].getVector3fMap();
141 Eigen::Vector3f scene_point_transformed = transform_sg * scene_point;
143 std::atan2(-scene_point_transformed(2), scene_point_transformed(1));
144 if (std::sin(alpha_s) * scene_point_transformed(2) < 0.0f)
149 for (
const auto& nearest_index : nearest_indices) {
150 std::size_t model_reference_index = nearest_index.first;
151 std::size_t model_point_index = nearest_index.second;
154 search_method_->alpha_m_[model_reference_index][model_point_index] -
156 unsigned int alpha_discretized =
static_cast<unsigned int>(
158 std::floor(
M_PI / search_method_->getAngleDiscretizationStep()));
159 accumulator_array[model_reference_index][alpha_discretized]++;
163 PCL_ERROR(
"[pcl::PPFRegistration::computeTransformation] Computing pair "
164 "feature vector between points %u and %u went wrong.\n",
165 scene_reference_index,
170 std::size_t max_votes_i = 0, max_votes_j = 0;
171 unsigned int max_votes = 0;
173 for (std::size_t i = 0; i < accumulator_array.size(); ++i)
174 for (std::size_t j = 0; j < accumulator_array.back().size(); ++j) {
175 if (accumulator_array[i][j] > max_votes) {
176 max_votes = accumulator_array[i][j];
182 accumulator_array[i][j] = 0;
185 Eigen::Vector3f model_reference_point = (*input_)[max_votes_i].getVector3fMap(),
186 model_reference_normal =
187 (*input_)[max_votes_i].getNormalVector3fMap();
188 float rotation_angle_mg =
189 std::acos(model_reference_normal.dot(Eigen::Vector3f::UnitX()));
190 bool parallel_to_x_mg =
191 (model_reference_normal.y() == 0.0f && model_reference_normal.z() == 0.0f);
192 Eigen::Vector3f rotation_axis_mg =
194 ? (Eigen::Vector3f::UnitY())
195 : (model_reference_normal.cross(Eigen::Vector3f::UnitX()).
normalized());
196 Eigen::AngleAxisf rotation_mg(rotation_angle_mg, rotation_axis_mg);
197 Eigen::Affine3f transform_mg(
198 Eigen::Translation3f(rotation_mg * ((-1) * model_reference_point)) *
200 Eigen::Affine3f max_transform =
201 transform_sg.inverse() *
202 Eigen::AngleAxisf((
static_cast<float>(max_votes_j) -
203 std::floor(
static_cast<float>(
M_PI) /
204 search_method_->getAngleDiscretizationStep())) *
205 search_method_->getAngleDiscretizationStep(),
206 Eigen::Vector3f::UnitX()) *
209 voted_poses.push_back(PoseWithVotes(max_transform, max_votes));
211 PCL_DEBUG(
"Done with the Hough Transform ...\n");
214 PoseWithVotesList results;
215 clusterPoses(voted_poses, results);
219 transformation_ = final_transformation_ = results.front().pose.matrix();
224 template <
typename Po
intSource,
typename Po
intTarget>
230 PCL_INFO(
"Clustering poses ...\n");
232 sort(poses.begin(), poses.end(), poseWithVotesCompareFunction);
234 std::vector<PoseWithVotesList> clusters;
235 std::vector<std::pair<std::size_t, unsigned int>> cluster_votes;
236 for (std::size_t poses_i = 0; poses_i < poses.size(); ++poses_i) {
237 bool found_cluster =
false;
238 for (std::size_t clusters_i = 0; clusters_i < clusters.size(); ++clusters_i) {
239 if (posesWithinErrorBounds(poses[poses_i].pose,
240 clusters[clusters_i].front().pose)) {
241 found_cluster =
true;
242 clusters[clusters_i].push_back(poses[poses_i]);
243 cluster_votes[clusters_i].second += poses[poses_i].votes;
248 if (!found_cluster) {
250 PoseWithVotesList new_cluster;
251 new_cluster.push_back(poses[poses_i]);
252 clusters.push_back(new_cluster);
253 cluster_votes.push_back(std::pair<std::size_t, unsigned int>(
254 clusters.size() - 1, poses[poses_i].votes));
259 std::sort(cluster_votes.begin(), cluster_votes.end(), clusterVotesCompareFunction);
264 std::size_t max_clusters = (clusters.size() < 3) ? clusters.size() : 3;
265 for (std::size_t cluster_i = 0; cluster_i < max_clusters; ++cluster_i) {
266 PCL_INFO(
"Winning cluster has #votes: %d and #poses voted: %d.\n",
267 cluster_votes[cluster_i].second,
268 clusters[cluster_votes[cluster_i].first].size());
269 Eigen::Vector3f translation_average(0.0, 0.0, 0.0);
270 Eigen::Vector4f rotation_average(0.0, 0.0, 0.0, 0.0);
271 for (
typename PoseWithVotesList::iterator v_it =
272 clusters[cluster_votes[cluster_i].first].begin();
273 v_it != clusters[cluster_votes[cluster_i].first].end();
275 translation_average += v_it->pose.translation();
278 rotation_average += Eigen::Quaternionf(v_it->pose.rotation()).coeffs();
281 translation_average /=
282 static_cast<float>(clusters[cluster_votes[cluster_i].first].size());
284 static_cast<float>(clusters[cluster_votes[cluster_i].first].size());
286 Eigen::Affine3f transform_average;
287 transform_average.translation().matrix() = translation_average;
288 transform_average.linear().matrix() =
289 Eigen::Quaternionf(rotation_average).normalized().toRotationMatrix();
291 result.push_back(PoseWithVotes(transform_average, cluster_votes[cluster_i].second));
296 template <
typename Po
intSource,
typename Po
intTarget>
299 Eigen::Affine3f& pose1, Eigen::Affine3f& pose2)
301 float position_diff = (pose1.translation() - pose2.translation()).
norm();
302 Eigen::AngleAxisf rotation_diff_mat(
303 (pose1.rotation().inverse().lazyProduct(pose2.rotation()).eval()));
305 float rotation_diff_angle = std::abs(rotation_diff_mat.angle());
307 return (position_diff < clustering_position_diff_threshold_ &&
308 rotation_diff_angle < clustering_rotation_diff_threshold_);
312 template <
typename Po
intSource,
typename Po
intTarget>
322 template <
typename Po
intSource,
typename Po
intTarget>
325 const std::pair<std::size_t, unsigned int>& a,
326 const std::pair<std::size_t, unsigned int>& b)
328 return (a.second > b.second);
334 #endif // PCL_REGISTRATION_IMPL_PPF_REGISTRATION_H_