105 unsigned int nr_samples,
106 float min_sample_distance,
109 if (nr_samples > cloud.size()) {
110 PCL_ERROR(
"[pcl::%s::selectSamples] ", getClassName().c_str());
111 PCL_ERROR(
"The number of samples (%u) must not be greater than the number of "
114 static_cast<std::size_t
>(cloud.size()));
119 index_t iterations_without_a_sample = 0;
120 const auto max_iterations_without_a_sample = 3 * cloud.size();
121 sample_indices.clear();
122 while (sample_indices.size() < nr_samples) {
124 const auto sample_index = getRandomIndex(cloud.size());
127 bool valid_sample =
true;
128 for (
const auto& sample_idx : sample_indices) {
129 float distance_between_samples =
132 if (sample_index == sample_idx ||
133 distance_between_samples < min_sample_distance) {
134 valid_sample =
false;
141 sample_indices.push_back(sample_index);
142 iterations_without_a_sample = 0;
145 ++iterations_without_a_sample;
148 if (
static_cast<std::size_t
>(iterations_without_a_sample) >=
149 max_iterations_without_a_sample) {
150 PCL_WARN(
"[pcl::%s::selectSamples] ", getClassName().c_str());
151 PCL_WARN(
"No valid sample found after %zu iterations. Relaxing "
152 "min_sample_distance_ to %f\n",
153 static_cast<std::size_t
>(iterations_without_a_sample),
154 0.5 * min_sample_distance);
156 min_sample_distance_ *= 0.5f;
157 min_sample_distance = min_sample_distance_;
158 iterations_without_a_sample = 0;
171 std::vector<float> nn_distances(k_correspondences_);
173 corresponding_indices.resize(sample_indices.size());
174 for (std::size_t i = 0; i < sample_indices.size(); ++i) {
176 feature_tree_->nearestKSearch(input_features,
183 const auto random_correspondence = getRandomIndex(k_correspondences_);
184 corresponding_indices[i] = nn_indices[random_correspondence];
194 std::vector<float> nn_distance(1);
197 const auto& tree = tree_;
200#pragma omp parallel for default(none) shared(cloud, tree, compute_error) \
201 firstprivate(nn_index, nn_distance) reduction(+ : error) num_threads(threads_)
202 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(cloud.size()); ++i) {
203 const auto& point = cloud[
static_cast<std::size_t
>(i)];
206 tree->nearestKSearch(point, 1, nn_index, nn_distance);
209 error += compute_error(nn_distance[0]);
220 if (!input_features_) {
221 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
223 "No source features were given! Call setSourceFeatures before aligning.\n");
226 if (!target_features_) {
227 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
229 "No target features were given! Call setTargetFeatures before aligning.\n");
233 if (input_->size() != input_features_->size()) {
234 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
235 PCL_ERROR(
"The source points and source feature points need to be in a one-to-one "
236 "relationship! Current input cloud sizes: %ld vs %ld.\n",
238 input_features_->size());
242 if (target_->size() != target_features_->size()) {
243 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
244 PCL_ERROR(
"The target points and target feature points need to be in a one-to-one "
245 "relationship! Current input cloud sizes: %ld vs %ld.\n",
247 target_features_->size());
252 error_functor_.reset(
new TruncatedError(
static_cast<float>(corr_dist_threshold_)));
257 float lowest_error(0);
259 final_transformation_ = guess;
262 if (!guess.isApprox(Eigen::Matrix4f::Identity(), 0.01f)) {
266 computeErrorMetric(input_transformed,
static_cast<float>(corr_dist_threshold_));
270 for (; i_iter < max_iterations_; ++i_iter) {
272 selectSamples(*input_, nr_samples_, min_sample_distance_, sample_indices);
275 findSimilarFeatures(*input_features_, sample_indices, corresponding_indices);
278 transformation_estimation_->estimateRigidTransformation(
279 *input_, sample_indices, *target_, corresponding_indices, transformation_);
284 computeErrorMetric(input_transformed,
static_cast<float>(corr_dist_threshold_));
287 if (i_iter == 0 || error < lowest_error) {
288 lowest_error = error;
289 final_transformation_ = transformation_;
void selectSamples(const PointCloudSource &cloud, unsigned int nr_samples, float min_sample_distance, pcl::Indices &sample_indices)
Select nr_samples sample points from cloud while making sure that their pairwise distances are greate...
void findSimilarFeatures(const FeatureCloud &input_features, const pcl::Indices &sample_indices, pcl::Indices &corresponding_indices)
For each of the sample points, find a list of points in the target cloud whose features are similar t...
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.