127 std::vector<pcl::Indices>& similar_features,
131 corresponding_indices.resize(sample_indices.size());
132 std::vector<float> nn_distances(k_correspondences_);
135 for (std::size_t i = 0; i < sample_indices.size(); ++i) {
137 const auto& idx = sample_indices[i];
141 if (similar_features[idx].empty())
142 feature_tree_->nearestKSearch(*input_features_,
145 similar_features[idx],
149 if (k_correspondences_ == 1)
150 corresponding_indices[i] = similar_features[idx][0];
152 corresponding_indices[i] =
153 similar_features[idx][getRandomIndex(k_correspondences_)];
163 if (!input_features_) {
164 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
166 "No source features were given! Call setSourceFeatures before aligning.\n");
169 if (!target_features_) {
170 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
172 "No target features were given! Call setTargetFeatures before aligning.\n");
176 if (input_->size() != input_features_->size()) {
177 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
178 PCL_ERROR(
"The source points and source feature points need to be in a one-to-one "
179 "relationship! Current input cloud sizes: %ld vs %ld.\n",
181 input_features_->size());
185 if (target_->size() != target_features_->size()) {
186 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
187 PCL_ERROR(
"The target points and target feature points need to be in a one-to-one "
188 "relationship! Current input cloud sizes: %ld vs %ld.\n",
190 target_features_->size());
194 if (inlier_fraction_ < 0.0f || inlier_fraction_ > 1.0f) {
195 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
196 PCL_ERROR(
"Illegal inlier fraction %f, must be in [0,1]!\n", inlier_fraction_);
200 const float similarity_threshold =
201 correspondence_rejector_poly_->getSimilarityThreshold();
202 if (similarity_threshold < 0.0f || similarity_threshold >= 1.0f) {
203 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
204 PCL_ERROR(
"Illegal prerejection similarity threshold %f, must be in [0,1[!\n",
205 similarity_threshold);
209 if (k_correspondences_ <= 0) {
210 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
211 PCL_ERROR(
"Illegal correspondence randomness %d, must be > 0!\n",
218 correspondence_rejector_poly_->setInputSource(input_);
219 correspondence_rejector_poly_->setInputTarget(target_);
220 correspondence_rejector_poly_->setCardinality(nr_samples_);
221 int num_rejections = 0;
224 final_transformation_ = guess;
226 float lowest_error = std::numeric_limits<float>::max();
231 float inlier_fraction;
235 if (!guess.isApprox(Eigen::Matrix4f::Identity(), 0.01f)) {
236 getFitness(inliers, error);
238 static_cast<float>(inliers.size()) /
static_cast<float>(input_->size());
240 if (inlier_fraction >= inlier_fraction_ && error < lowest_error) {
242 lowest_error = error;
248 std::vector<pcl::Indices> similar_features(input_->size());
253 if ((1.0 - std::pow(1.0 - nr_samples_ /
static_cast<double>(input_->size()),
257 std::vector<float> nn_distances(k_correspondences_);
258#pragma omp parallel for default(none) shared(similar_features) \
259 firstprivate(nn_distances) num_threads(num_threads_) schedule(dynamic, 64)
260 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(input_->size()); ++i) {
261 nn_distances.clear();
262 feature_tree_->nearestKSearch(
263 (*input_features_)[i], k_correspondences_, similar_features[i], nn_distances);
272 for (
int i = 0; i < max_iterations_; ++i) {
275 selectSamples(*input_, nr_samples_, sample_indices);
278 findSimilarFeatures(sample_indices, similar_features, corresponding_indices);
281 if (!correspondence_rejector_poly_->thresholdPolygon(sample_indices,
282 corresponding_indices)) {
288 transformation_estimation_->estimateRigidTransformation(
289 *input_, sample_indices, *target_, corresponding_indices, transformation_);
292 const Matrix4 final_transformation_prev = final_transformation_;
295 final_transformation_ = transformation_;
298 getFitness(inliers, error);
301 final_transformation_ = final_transformation_prev;
305 static_cast<float>(inliers.size()) /
static_cast<float>(input_->size());
308 if (inlier_fraction >= inlier_fraction_ && error < lowest_error) {
310 lowest_error = error;
312 final_transformation_ = transformation_;
321 PCL_DEBUG(
"[pcl::%s::computeTransformation] Rejected %i out of %i generated pose "
323 getClassName().c_str(),
335 inliers.resize(input_->size());
336 float fitness_score_tmp = 0.0f;
339 const float max_range = corr_dist_threshold_ * corr_dist_threshold_;
343 input_transformed.resize(input_->size());
347#pragma omp parallel for default(none) shared(input_transformed, max_range, inliers) \
348 reduction(+ : fitness_score_tmp) num_threads(num_threads_) schedule(dynamic, 64)
349 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(input_transformed.size());
353 std::vector<float> nn_dists(1);
354 tree_->nearestKSearch(input_transformed[i], 1, nn_indices, nn_dists);
357 if (nn_dists[0] < max_range) {
361 fitness_score_tmp += nn_dists[0];
368 inliers.erase(std::remove(inliers.begin(), inliers.end(),
UNAVAILABLE),
372 if (!inliers.empty())
373 fitness_score = fitness_score_tmp /
static_cast<float>(inliers.size());
375 fitness_score = std::numeric_limits<float>::max();
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const Eigen::Matrix< Scalar, 4, 4 > &transform, bool copy_all_fields)
Apply a rigid transform defined by a 4x4 matrix.