41 #ifndef PCL_REGISTRATION_SAMPLE_CONSENSUS_PREREJECTIVE_HPP_
42 #define PCL_REGISTRATION_SAMPLE_CONSENSUS_PREREJECTIVE_HPP_
44 #include <pcl/search/auto.h>
48 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
53 if (features ==
nullptr || features->empty()) {
55 "[pcl::%s::setSourceFeatures] Invalid or empty point cloud dataset given!\n",
56 getClassName().c_str());
59 input_features_ = features;
62 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
67 if (features ==
nullptr || features->empty()) {
69 "[pcl::%s::setTargetFeatures] Invalid or empty point cloud dataset given!\n",
70 getClassName().c_str());
73 target_features_ = features;
74 feature_tree_.reset(pcl::search::autoSelectMethod<FeatureT>(
78 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
83 if (nr_samples >
static_cast<int>(cloud.
size())) {
84 PCL_ERROR(
"[pcl::%s::selectSamples] ", getClassName().c_str());
85 PCL_ERROR(
"The number of samples (%d) must not be greater than the number of "
88 static_cast<std::size_t
>(cloud.
size()));
92 sample_indices.resize(nr_samples);
96 for (
int i = 0; i < nr_samples; i++) {
98 sample_indices[i] = getRandomIndex(
static_cast<int>(cloud.
size()) - i);
101 for (
int j = 0; j < i; j++) {
104 if (sample_indices[i] >= sample_indices[j]) {
110 temp_sample = sample_indices[i];
111 for (
int k = i; k > j; k--)
112 sample_indices[k] = sample_indices[k - 1];
114 sample_indices[j] = temp_sample;
121 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
125 std::vector<pcl::Indices>& similar_features,
129 corresponding_indices.resize(sample_indices.size());
130 std::vector<float> nn_distances(k_correspondences_);
133 for (std::size_t i = 0; i < sample_indices.size(); ++i) {
135 const auto& idx = sample_indices[i];
139 if (similar_features[idx].empty())
140 feature_tree_->nearestKSearch(*input_features_,
143 similar_features[idx],
147 if (k_correspondences_ == 1)
148 corresponding_indices[i] = similar_features[idx][0];
150 corresponding_indices[i] =
151 similar_features[idx][getRandomIndex(k_correspondences_)];
155 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
161 if (!input_features_) {
162 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
164 "No source features were given! Call setSourceFeatures before aligning.\n");
167 if (!target_features_) {
168 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
170 "No target features were given! Call setTargetFeatures before aligning.\n");
174 if (input_->size() != input_features_->size()) {
175 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
176 PCL_ERROR(
"The source points and source feature points need to be in a one-to-one "
177 "relationship! Current input cloud sizes: %ld vs %ld.\n",
179 input_features_->size());
183 if (target_->size() != target_features_->size()) {
184 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
185 PCL_ERROR(
"The target points and target feature points need to be in a one-to-one "
186 "relationship! Current input cloud sizes: %ld vs %ld.\n",
188 target_features_->size());
192 if (inlier_fraction_ < 0.0f || inlier_fraction_ > 1.0f) {
193 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
194 PCL_ERROR(
"Illegal inlier fraction %f, must be in [0,1]!\n", inlier_fraction_);
198 const float similarity_threshold =
199 correspondence_rejector_poly_->getSimilarityThreshold();
200 if (similarity_threshold < 0.0f || similarity_threshold >= 1.0f) {
201 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
202 PCL_ERROR(
"Illegal prerejection similarity threshold %f, must be in [0,1[!\n",
203 similarity_threshold);
207 if (k_correspondences_ <= 0) {
208 PCL_ERROR(
"[pcl::%s::computeTransformation] ", getClassName().c_str());
209 PCL_ERROR(
"Illegal correspondence randomness %d, must be > 0!\n",
216 correspondence_rejector_poly_->setInputSource(input_);
217 correspondence_rejector_poly_->setInputTarget(target_);
218 correspondence_rejector_poly_->setCardinality(nr_samples_);
219 int num_rejections = 0;
222 final_transformation_ = guess;
224 float lowest_error = std::numeric_limits<float>::max();
229 float inlier_fraction;
233 if (!guess.isApprox(Eigen::Matrix4f::Identity(), 0.01f)) {
234 getFitness(inliers, error);
236 static_cast<float>(inliers.size()) /
static_cast<float>(input_->size());
238 if (inlier_fraction >= inlier_fraction_ && error < lowest_error) {
240 lowest_error = error;
246 std::vector<pcl::Indices> similar_features(input_->size());
249 for (
int i = 0; i < max_iterations_; ++i) {
255 selectSamples(*input_, nr_samples_, sample_indices);
258 findSimilarFeatures(sample_indices, similar_features, corresponding_indices);
261 if (!correspondence_rejector_poly_->thresholdPolygon(sample_indices,
262 corresponding_indices)) {
268 transformation_estimation_->estimateRigidTransformation(
269 *input_, sample_indices, *target_, corresponding_indices, transformation_);
272 const Matrix4 final_transformation_prev = final_transformation_;
275 final_transformation_ = transformation_;
278 getFitness(inliers, error);
281 final_transformation_ = final_transformation_prev;
285 static_cast<float>(inliers.size()) /
static_cast<float>(input_->size());
288 if (inlier_fraction >= inlier_fraction_ && error < lowest_error) {
290 lowest_error = error;
292 final_transformation_ = transformation_;
301 PCL_DEBUG(
"[pcl::%s::computeTransformation] Rejected %i out of %i generated pose "
303 getClassName().c_str(),
308 template <
typename Po
intSource,
typename Po
intTarget,
typename FeatureT>
315 inliers.reserve(input_->size());
316 fitness_score = 0.0f;
319 const float max_range = corr_dist_threshold_ * corr_dist_threshold_;
323 input_transformed.
resize(input_->size());
327 for (std::size_t i = 0; i < input_transformed.
size(); ++i) {
330 std::vector<float> nn_dists(1);
331 tree_->nearestKSearch(input_transformed[i], 1, nn_indices, nn_dists);
334 if (nn_dists[0] < max_range) {
336 inliers.push_back(i);
339 fitness_score += nn_dists[0];
344 if (!inliers.empty())
345 fitness_score /=
static_cast<float>(inliers.size());
347 fitness_score = std::numeric_limits<float>::max();
void resize(std::size_t count)
Resizes the container to contain count elements.
Eigen::Matrix< Scalar, 4, 4 > Matrix4
void setTargetFeatures(const FeatureCloudConstPtr &features)
Provide a boost shared pointer to the target point cloud's feature descriptors.
void computeTransformation(PointCloudSource &output, const Eigen::Matrix4f &guess) override
Rigid transformation computation method.
typename FeatureCloud::ConstPtr FeatureCloudConstPtr
void findSimilarFeatures(const pcl::Indices &sample_indices, std::vector< pcl::Indices > &similar_features, 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 setSourceFeatures(const FeatureCloudConstPtr &features)
Provide a boost shared pointer to the source point cloud's feature descriptors.
void selectSamples(const PointCloudSource &cloud, int nr_samples, pcl::Indices &sample_indices)
Select nr_samples sample points from cloud while making sure that their pairwise distances are greate...
void getFitness(pcl::Indices &inliers, float &fitness_score)
Obtain the fitness of a transformation The following metrics are calculated, based on final_transform...
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.
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
IndicesAllocator<> Indices
Type used for indices in PCL.