38 #ifndef PCL_REGISTRATION_IMPL_IA_FPCS_H_
39 #define PCL_REGISTRATION_IMPL_IA_FPCS_H_
43 #include <pcl/common/utils.h>
44 #include <pcl/filters/random_sample.h>
45 #include <pcl/registration/ia_fpcs.h>
46 #include <pcl/registration/transformation_estimation_3point.h>
47 #include <pcl/sample_consensus/sac_model_plane.h>
48 #include <pcl/search/auto.h>
53 template <
typename Po
intT>
59 const float max_dist_sqr = max_dist * max_dist;
60 const std::size_t s = cloud->
size();
65 float mean_dist = 0.f;
68 std::vector<float> dists_sqr(2);
71 #pragma omp parallel for default(none) shared(tree, cloud) \
72 firstprivate(ids, dists_sqr) reduction(+ : mean_dist, num) \
73 firstprivate(s, max_dist_sqr) num_threads(nr_threads)
74 for (
int i = 0; i < 1000; i++) {
76 if (dists_sqr[1] < max_dist_sqr) {
77 mean_dist += std::sqrt(dists_sqr[1]);
82 return (mean_dist / num);
86 template <
typename Po
intT>
93 const float max_dist_sqr = max_dist * max_dist;
94 const std::size_t s = indices.size();
99 float mean_dist = 0.f;
102 std::vector<float> dists_sqr(2);
105 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
106 #pragma omp parallel for default(none) shared(tree, cloud, indices) \
107 firstprivate(ids, dists_sqr) reduction(+ : mean_dist, num) num_threads(nr_threads)
109 #pragma omp parallel for default(none) shared(tree, cloud, indices, s, max_dist_sqr) \
110 firstprivate(ids, dists_sqr) reduction(+ : mean_dist, num) num_threads(nr_threads)
112 for (
int i = 0; i < 1000; i++) {
113 tree->
nearestKSearch((*cloud)[indices[rand() % s]], 2, ids, dists_sqr);
114 if (dists_sqr[1] < max_dist_sqr) {
115 mean_dist += std::sqrt(dists_sqr[1]);
120 return (mean_dist / num);
124 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
129 , score_threshold_(std::numeric_limits<float>::max())
130 , fitness_score_(std::numeric_limits<float>::max())
132 reg_name_ =
"pcl::registration::FPCSInitialAlignment";
140 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
148 final_transformation_ = guess;
150 std::vector<MatchingCandidates> all_candidates(max_iterations_);
153 #pragma omp parallel default(none) shared(abort, all_candidates, timer) \
154 num_threads(nr_threads_)
157 const unsigned int seed =
158 static_cast<unsigned int>(std::time(
nullptr)) ^ omp_get_thread_num();
160 PCL_DEBUG(
"[%s::computeTransformation] Using seed=%u\n", reg_name_.c_str(), seed);
161 #pragma omp for schedule(dynamic)
163 for (
int i = 0; i < max_iterations_; i++) {
164 #pragma omp flush(abort)
168 all_candidates[i] = candidates;
173 if (selectBase(base_indices, ratio) == 0) {
176 if (bruteForceCorrespondences(base_indices[0], base_indices[1], pairs_a) ==
178 bruteForceCorrespondences(base_indices[2], base_indices[3], pairs_b) ==
182 std::vector<pcl::Indices> matches;
183 if (determineBaseMatches(base_indices, matches, pairs_a, pairs_b, ratio) ==
186 handleMatches(base_indices, matches, candidates);
187 if (!candidates.empty())
188 all_candidates[i] = candidates;
194 if (!candidates.empty() && candidates[0].fitness_score < score_threshold_) {
195 PCL_DEBUG(
"[%s::computeTransformation] Terminating because fitness score "
196 "(%g) is below threshold (%g).\n",
198 candidates[0].fitness_score,
203 PCL_DEBUG(
"[%s::computeTransformation] Terminating because time exceeded.\n",
208 #pragma omp flush(abort)
214 finalCompute(all_candidates);
223 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
228 const unsigned int seed = std::time(
nullptr);
230 PCL_DEBUG(
"[%s::initCompute] Using seed=%u\n", reg_name_.c_str(), seed);
237 if (!input_ || !target_) {
238 PCL_ERROR(
"[%s::initCompute] Source or target dataset not given!\n",
243 if (!target_indices_ || target_indices_->empty()) {
244 target_indices_.reset(
new pcl::Indices(target_->size()));
246 for (
auto& target_index : *target_indices_)
247 target_index = index++;
248 target_cloud_updated_ =
true;
253 if (nr_samples_ > 0 &&
static_cast<std::size_t
>(nr_samples_) < indices_->size()) {
260 random_sampling.
filter(*source_indices_);
263 source_indices_ = indices_;
266 if (source_normals_ && target_normals_ && source_normals_->size() == input_->size() &&
267 target_normals_->size() == target_->size())
271 if (target_cloud_updated_) {
272 tree_->setInputCloud(target_, target_indices_);
273 target_cloud_updated_ =
false;
277 constexpr
int min_iterations = 4;
278 constexpr
float diameter_fraction = 0.3f;
281 Eigen::Vector4f pt_min, pt_max;
283 diameter_ = (pt_max - pt_min).norm();
286 float max_base_diameter = diameter_ * approx_overlap_ * 2.f;
287 max_base_diameter_sqr_ = max_base_diameter * max_base_diameter;
290 if (nr_threads_ < 1) {
291 nr_threads_ = omp_get_num_procs();
292 PCL_DEBUG(
"[%s::initCompute] Setting number of threads to %i.\n",
299 if (normalize_delta_) {
300 float mean_dist = getMeanPointDensity<PointTarget>(
301 target_, *target_indices_, 0.05f * diameter_, nr_threads_);
307 if (max_iterations_ == 0) {
308 float first_est = std::log(small_error_) /
309 std::log(1.0 - std::pow(
static_cast<double>(approx_overlap_),
310 static_cast<double>(min_iterations)));
312 static_cast<int>(first_est / (diameter_fraction * approx_overlap_ * 2.f));
313 PCL_DEBUG(
"[%s::initCompute] Estimated max iterations as %i\n",
319 if (score_threshold_ == std::numeric_limits<float>::max())
320 score_threshold_ = 1.f - approx_overlap_;
322 if (max_iterations_ < 4)
325 if (max_runtime_ < 1)
326 max_runtime_ = std::numeric_limits<int>::max();
329 max_pair_diff_ = delta_ * 2.f;
330 max_edge_diff_ = delta_ * 4.f;
331 coincidation_limit_ = delta_ * 2.f;
332 max_mse_ = powf(delta_ * 2.f, 2.f);
333 max_inlier_dist_sqr_ = powf(delta_ * 2.f, 2.f);
334 PCL_DEBUG(
"[%s::initCompute] delta_=%g, max_inlier_dist_sqr_=%g, "
335 "coincidation_limit_=%g, max_edge_diff_=%g, max_pair_diff_=%g\n",
338 max_inlier_dist_sqr_,
344 fitness_score_ = std::numeric_limits<float>::max();
350 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
355 const float too_close_sqr = max_base_diameter_sqr_ * 0.01;
357 Eigen::VectorXf coefficients(4);
360 Eigen::Vector4f centre_pt;
361 float nearest_to_plane = std::numeric_limits<float>::max();
365 for (
int i = 0; i < ransac_iterations_; i++) {
367 if (selectBaseTriangle(base_indices) < 0)
370 pcl::Indices base_triple(base_indices.begin(), base_indices.end() - 1);
375 const PointTarget* pt1 = &((*target_)[base_indices[0]]);
376 const PointTarget* pt2 = &((*target_)[base_indices[1]]);
377 const PointTarget* pt3 = &((*target_)[base_indices[2]]);
379 for (
const auto& target_index : *target_indices_) {
380 const PointTarget* pt4 = &((*target_)[target_index]);
385 float d4 = (pt4->getVector3fMap() - centre_pt.head<3>()).squaredNorm();
389 if (d1 < too_close_sqr || d2 < too_close_sqr || d3 < too_close_sqr ||
390 d4 < too_close_sqr || d1 > max_base_diameter_sqr_ ||
391 d2 > max_base_diameter_sqr_ || d3 > max_base_diameter_sqr_)
396 if (dist_to_plane < nearest_to_plane) {
397 base_indices[3] = target_index;
398 nearest_to_plane = dist_to_plane;
403 if (nearest_to_plane != std::numeric_limits<float>::max()) {
406 setupBase(base_indices, ratio);
416 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
421 const auto nr_points = target_indices_->size();
425 base_indices[0] = (*target_indices_)[rand() % nr_points];
426 auto* index1 = base_indices.data();
429 for (
int i = 0; i < ransac_iterations_; i++) {
430 auto* index2 = &(*target_indices_)[rand() % nr_points];
431 auto* index3 = &(*target_indices_)[rand() % nr_points];
434 (*target_)[*index2].getVector3fMap() - (*target_)[*index1].getVector3fMap();
436 (*target_)[*index3].getVector3fMap() - (*target_)[*index1].getVector3fMap();
438 u.cross(v).squaredNorm();
441 if (t > best_t && u.squaredNorm() < max_base_diameter_sqr_ &&
442 v.squaredNorm() < max_base_diameter_sqr_) {
444 base_indices[1] = *index2;
445 base_indices[2] = *index3;
450 return (best_t == 0.f ? -1 : 0);
454 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
459 float best_t = std::numeric_limits<float>::max();
460 const pcl::Indices copy(base_indices.begin(), base_indices.end());
461 pcl::Indices temp(base_indices.begin(), base_indices.end());
464 for (
auto i = copy.begin(), i_e = copy.end(); i != i_e; ++i)
465 for (
auto j = copy.begin(), j_e = copy.end(); j != j_e; ++j) {
469 for (
auto k = copy.begin(), k_e = copy.end(); k != k_e; ++k) {
470 if (k == j || k == i)
473 auto l = copy.begin();
474 while (l == i || l == j || l == k)
485 float t = segmentToSegmentDist(temp, ratio_temp);
488 ratio[0] = ratio_temp[0];
489 ratio[1] = ratio_temp[1];
497 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
503 Eigen::Vector3f u = (*target_)[base_indices[1]].getVector3fMap() -
504 (*target_)[base_indices[0]].getVector3fMap();
505 Eigen::Vector3f v = (*target_)[base_indices[3]].getVector3fMap() -
506 (*target_)[base_indices[2]].getVector3fMap();
507 Eigen::Vector3f w = (*target_)[base_indices[0]].getVector3fMap() -
508 (*target_)[base_indices[2]].getVector3fMap();
516 float D = a * c - b * b;
517 float sN = 0.f, sD = D;
518 float tN = 0.f, tD = D;
521 if (D < small_error_) {
528 sN = (b * e - c * d);
529 tN = (a * e - b * d);
564 else if ((-d + b) > a)
574 ratio[0] = (std::abs(sN) < small_error_) ? 0.f : sN / sD;
575 ratio[1] = (std::abs(tN) < small_error_) ? 0.f : tN / tD;
577 Eigen::Vector3f x = w + (ratio[0] * u) - (ratio[1] * v);
582 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
587 const float max_norm_diff = 0.5f * max_norm_diff_ *
M_PI / 180.f;
591 float ref_norm_angle =
592 (use_normals_ ? ((*target_normals_)[idx1].getNormalVector3fMap() -
593 (*target_normals_)[idx2].getNormalVector3fMap())
598 auto it_out = source_indices_->begin(), it_out_e = source_indices_->end() - 1;
599 auto it_in_e = source_indices_->end();
600 for (; it_out != it_out_e; it_out++) {
601 auto it_in = it_out + 1;
602 const PointSource* pt1 = &(*input_)[*it_out];
603 for (; it_in != it_in_e; it_in++) {
604 const PointSource* pt2 = &(*input_)[*it_in];
608 if (std::abs(dist - ref_dist) < max_pair_diff_) {
611 const NormalT* pt1_n = &((*source_normals_)[*it_out]);
612 const NormalT* pt2_n = &((*source_normals_)[*it_in]);
615 (pt1_n->getNormalVector3fMap() - pt2_n->getNormalVector3fMap()).norm();
617 (pt1_n->getNormalVector3fMap() + pt2_n->getNormalVector3fMap()).norm();
619 float norm_diff = std::min<float>(std::abs(norm_angle_1 - ref_norm_angle),
620 std::abs(norm_angle_2 - ref_norm_angle));
621 if (norm_diff > max_norm_diff)
625 pairs.emplace_back(*it_in, *it_out, dist);
626 pairs.emplace_back(*it_out, *it_in, dist);
632 return (pairs.empty() ? -1 : 0);
636 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
640 std::vector<pcl::Indices>& matches,
643 const float (&ratio)[2])
659 cloud_e->resize(pairs_a.size() * 2);
660 auto it_pt = cloud_e->begin();
661 for (
const auto& pair : pairs_a) {
662 const PointSource* pt1 = &((*input_)[pair.index_match]);
663 const PointSource* pt2 = &((*input_)[pair.index_query]);
666 for (
int i = 0; i < 2; i++, it_pt++) {
667 it_pt->x = pt1->x + ratio[i] * (pt2->x - pt1->x);
668 it_pt->y = pt1->y + ratio[i] * (pt2->y - pt1->y);
669 it_pt->z = pt1->z + ratio[i] * (pt2->z - pt1->z);
675 tree_e->setInputCloud(cloud_e);
678 std::vector<float> dists_sqr;
681 for (
const auto& pair : pairs_b) {
682 const PointTarget* pt1 = &((*input_)[pair.index_match]);
683 const PointTarget* pt2 = &((*input_)[pair.index_query]);
686 for (
const float& r : ratio) {
688 pt_e.x = pt1->x + r * (pt2->x - pt1->x);
689 pt_e.y = pt1->y + r * (pt2->y - pt1->y);
690 pt_e.z = pt1->z + r * (pt2->z - pt1->z);
693 tree_e->radiusSearch(pt_e, coincidation_limit_, ids, dists_sqr);
694 for (
const auto&
id : ids) {
698 pairs_a[
static_cast<int>(std::floor((
id / 2.f)))].index_match;
700 pairs_a[
static_cast<int>(std::floor((
id / 2.f)))].index_query;
701 match_indices[2] = pair.index_match;
702 match_indices[3] = pair.index_query;
703 if (match_indices[0] == match_indices[2] ||
704 match_indices[0] == match_indices[3] ||
705 match_indices[1] == match_indices[2] ||
706 match_indices[1] == match_indices[3])
710 if (checkBaseMatch(match_indices, dist_base) < 0)
713 matches.push_back(match_indices);
719 if (matches.empty()) {
720 PCL_DEBUG(
"[%s::determineBaseMatches] no matches found\n", reg_name_.c_str());
724 PCL_DEBUG(
"[%s::determineBaseMatches] found %zu matches\n",
732 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
747 return (std::abs(d0 - dist_ref[0]) < max_edge_diff_ &&
748 std::abs(d1 - dist_ref[1]) < max_edge_diff_ &&
749 std::abs(d2 - dist_ref[2]) < max_edge_diff_ &&
750 std::abs(d3 - dist_ref[3]) < max_edge_diff_)
756 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
760 std::vector<pcl::Indices>& matches,
763 candidates.resize(1);
764 float fitness_score = std::numeric_limits<float>::max();
767 for (
auto& match : matches) {
768 Eigen::Matrix4f transformation_temp;
770 correspondences_temp.emplace_back(match[0], base_indices[0], 0.0);
771 correspondences_temp.emplace_back(match[1], base_indices[1], 0.0);
772 correspondences_temp.emplace_back(match[2], base_indices[2], 0.0);
773 correspondences_temp.emplace_back(match[3], base_indices[3], 0.0);
776 if (validateMatch(base_indices, match, correspondences_temp, transformation_temp) <
782 if (validateTransformation(transformation_temp, fitness_score) < 0)
786 candidates[0].fitness_score = fitness_score;
787 candidates[0].transformation = transformation_temp;
788 correspondences_temp.erase(correspondences_temp.end() - 1);
789 candidates[0].correspondences = correspondences_temp;
794 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
802 Eigen::Vector4f centre_base{0, 0, 0, 0}, centre_match{0, 0, 0, 0};
806 PointTarget centre_pt_base;
807 centre_pt_base.x = centre_base[0];
808 centre_pt_base.y = centre_base[1];
809 centre_pt_base.z = centre_base[2];
811 PointSource centre_pt_match;
812 centre_pt_match.x = centre_match[0];
813 centre_pt_match.y = centre_match[1];
814 centre_pt_match.z = centre_match[2];
819 auto it_match_orig = match_indices.begin();
820 for (
auto it_base = base_indices.cbegin(), it_base_e = base_indices.cend();
821 it_base != it_base_e;
822 it_base++, it_match_orig++) {
825 float best_diff_sqr = std::numeric_limits<float>::max();
828 for (
const auto& match_index : copy) {
832 float diff_sqr = std::abs(dist_sqr_1 - dist_sqr_2);
834 if (diff_sqr < best_diff_sqr) {
835 best_diff_sqr = diff_sqr;
836 best_index = match_index;
841 correspondences.emplace_back(best_index, *it_base, best_diff_sqr);
842 *it_match_orig = best_index;
847 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
853 Eigen::Matrix4f& transformation)
857 correspondences_temp.erase(correspondences_temp.end() - 1);
860 transformation_estimation_->estimateRigidTransformation(
861 *input_, *target_, correspondences_temp, transformation);
864 PointCloudSource match_transformed;
868 std::size_t nr_points = correspondences_temp.size();
870 for (std::size_t i = 0; i < nr_points; i++)
872 target_->points[base_indices[i]]);
875 return (mse < max_mse_ ? 0 : -1);
879 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
885 PointCloudSource source_transformed;
887 *input_, *source_indices_, source_transformed, transformation);
889 std::size_t nr_points = source_transformed.size();
890 std::size_t terminate_value =
891 fitness_score > 1 ? 0
892 :
static_cast<std::size_t
>((1.f - fitness_score) * nr_points);
894 float inlier_score_temp = 0;
896 std::vector<float> dists_sqr(1);
897 auto it = source_transformed.begin();
899 for (std::size_t i = 0; i < nr_points; it++, i++) {
901 tree_->nearestKSearch(*it, 1, ids, dists_sqr);
902 inlier_score_temp += (dists_sqr[0] < max_inlier_dist_sqr_ ? 1 : 0);
905 if (nr_points - i + inlier_score_temp < terminate_value)
910 inlier_score_temp /=
static_cast<float>(nr_points);
911 float fitness_score_temp = 1.f - inlier_score_temp;
913 if (fitness_score_temp > fitness_score)
916 fitness_score = fitness_score_temp;
921 template <
typename Po
intSource,
typename Po
intTarget,
typename NormalT,
typename Scalar>
924 finalCompute(
const std::vector<MatchingCandidates>& candidates)
927 int nr_candidates =
static_cast<int>(candidates.size());
929 float best_score = std::numeric_limits<float>::max();
930 for (
int i = 0; i < nr_candidates; i++) {
931 const float& fitness_score = candidates[i][0].fitness_score;
932 if (fitness_score < best_score) {
933 best_score = fitness_score;
938 "[%s::finalCompute] best score is %g (iteration %i), out of %zu iterations.\n",
945 if (!(best_index < 0)) {
946 fitness_score_ = candidates[best_index][0].fitness_score;
947 final_transformation_ = candidates[best_index][0].transformation;
948 *correspondences_ = candidates[best_index][0].correspondences;
951 converged_ = fitness_score_ < score_threshold_;
void filter(Indices &indices)
Calls the filtering method and returns the filtered point cloud indices.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Provide a pointer to the input dataset.
virtual void setIndices(const IndicesPtr &indices)
Provide a pointer to the vector of indices that represents the input data.
shared_ptr< const PointCloud< PointT > > ConstPtr
RandomSample applies a random sampling with uniform probability.
void setSeed(unsigned int seed)
Set seed of random function.
void setSample(unsigned int sample)
Set number of indices to be sampled.
typename KdTreeReciprocal::Ptr KdTreeReciprocalPtr
std::string reg_name_
The registration method name.
typename PointCloudSource::Ptr PointCloudSourcePtr
int ransac_iterations_
The number of iterations RANSAC should run for.
TransformationEstimationPtr transformation_estimation_
A TransformationEstimation object, used to calculate the 4x4 rigid transformation.
int max_iterations_
The maximum number of iterations the internal optimization should run for.
void setIndices(const IndicesPtr &indices)
Provide a pointer to the vector of indices that represents the input data.
SampleConsensusModelPlane defines a model for 3D plane segmentation.
bool computeModelCoefficients(const Indices &samples, Eigen::VectorXf &model_coefficients) const override
Check whether the given index samples can form a valid plane model, compute the model coefficients fr...
double getTimeSeconds() const
Retrieve the time in seconds spent since the last call to reset().
virtual void finalCompute(const std::vector< MatchingCandidates > &candidates)
Final computation of best match out of vector of best matches.
void setupBase(pcl::Indices &base_indices, float(&ratio)[2])
Setup the base (four coplanar points) by ordering the points and computing intersection ratios and se...
int selectBaseTriangle(pcl::Indices &base_indices)
Select randomly a triplet of points with large point-to-point distances.
virtual int bruteForceCorrespondences(int idx1, int idx2, pcl::Correspondences &pairs)
Search for corresponding point pairs given the distance between two base points.
int selectBase(pcl::Indices &base_indices, float(&ratio)[2])
Select an approximately coplanar set of four points from the source cloud.
virtual int validateTransformation(Eigen::Matrix4f &transformation, float &fitness_score)
Validate the transformation by calculating the number of inliers after transforming the source cloud.
virtual int determineBaseMatches(const pcl::Indices &base_indices, std::vector< pcl::Indices > &matches, const pcl::Correspondences &pairs_a, const pcl::Correspondences &pairs_b, const float(&ratio)[2])
Determine base matches by combining the point pair candidate and search for coinciding intersection p...
virtual void linkMatchWithBase(const pcl::Indices &base_indices, pcl::Indices &match_indices, pcl::Correspondences &correspondences)
Sets the correspondences between the base B and the match M by using the distance of each point to th...
virtual void handleMatches(const pcl::Indices &base_indices, std::vector< pcl::Indices > &matches, MatchingCandidates &candidates)
Method to handle current candidate matches.
int checkBaseMatch(const pcl::Indices &match_indices, const float(&ds)[4])
Check if outer rectangle distance of matched points fit with the base rectangle.
float segmentToSegmentDist(const pcl::Indices &base_indices, float(&ratio)[2])
Calculate intersection ratios and segment to segment distances of base diagonals.
virtual int validateMatch(const pcl::Indices &base_indices, const pcl::Indices &match_indices, const pcl::Correspondences &correspondences, Eigen::Matrix4f &transformation)
Validate the matching by computing the transformation between the source and target based on the four...
FPCSInitialAlignment()
Constructor.
void computeTransformation(PointCloudSource &output, const Eigen::Matrix4f &guess) override
Rigid transformation computation method.
virtual bool initCompute()
Internal computation initialization.
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
shared_ptr< pcl::search::Search< PointT > > Ptr
virtual int nearestKSearch(const PointT &point, int k, Indices &k_indices, std::vector< float > &k_sqr_distances) const =0
Search for the k-nearest neighbors for the given query point.
Define standard C methods to do distance calculations.
Define methods for measuring time spent in code blocks.
void getMinMax3D(const pcl::PointCloud< PointT > &cloud, PointT &min_pt, PointT &max_pt)
Get the minimum and maximum values on each of the 3 (x-y-z) dimensions in a given pointcloud.
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.
unsigned int compute3DCentroid(ConstCloudIterator< PointT > &cloud_iterator, Eigen::Matrix< Scalar, 4, 1 > ¢roid)
Compute the 3D (X-Y-Z) centroid of a set of points and return it as a 3D vector.
double pointToPlaneDistance(const Point &p, double a, double b, double c, double d)
Get the distance from a point to a plane (unsigned) defined by ax+by+cz+d=0.
std::vector< MatchingCandidate, Eigen::aligned_allocator< MatchingCandidate > > MatchingCandidates
@ many_knn_search
The search method will mainly be used for nearestKSearch where k is larger than 1.
void ignore(const T &...)
Utility function to eliminate unused variable warnings.
float squaredEuclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the squared euclidean distance between the two given points.
float getMeanPointDensity(const typename pcl::PointCloud< PointT >::ConstPtr &cloud, float max_dist, int nr_threads=1)
Compute the mean point density of a given point cloud.
std::vector< pcl::Correspondence, Eigen::aligned_allocator< pcl::Correspondence > > Correspondences
float euclideanDistance(const PointType1 &p1, const PointType2 &p2)
Calculate the euclidean distance between the two given points.
IndicesAllocator<> Indices
Type used for indices in PCL.
shared_ptr< Indices > IndicesPtr
A point structure representing normal coordinates and the surface curvature estimate.