32 #ifndef PCL_FEATURES_CURVATURE_ESTIMATION_TAUBIN_H_ 33 #define PCL_FEATURES_CURVATURE_ESTIMATION_TAUBIN_H_ 35 #include <pcl/features/feature.h> 36 #include <pcl/filters/extract_indices.h> 37 #include <pcl/point_types.h> 38 #include <Eigen/Dense> 42 extern "C" void dggev_(
const char* JOBVL,
const char* JOBVR,
const int* N,
const double* A,
const int* LDA,
43 const double* B,
const int* LDB,
double* ALPHAR,
double* ALPHAI,
double* BETA,
double* VL,
44 const int* LDVL,
double* VR,
const int* LDVR,
double* WORK,
const int* LWORK,
int* INFO);
86 };EIGEN_MAKE_ALIGNED_OPERATOR_NEW
98 template<
typename Po
intInT,
typename Po
intOutT>
102 using Feature<PointInT, PointOutT>::feature_name_;
103 using Feature<PointInT, PointOutT>::indices_;
104 using Feature<PointInT, PointOutT>::input_;
105 using Feature<PointInT, PointOutT>::surface_;
106 using Feature<PointInT, PointOutT>::k_;
107 using Feature<PointInT, PointOutT>::search_radius_;
108 using Feature<PointInT, PointOutT>::search_parameter_;
117 num_threads_ = num_threads;
118 feature_name_ =
"CurvatureEstimationTaubin";
130 inline void fitQuadric(
const std::vector<int> &indices, Eigen::VectorXd &quadric_parameters,
131 Eigen::Vector3d &quadric_centroid, Eigen::Matrix3d &quadric_covariance_matrix)
133 int n = indices.size();
136 Eigen::Matrix<double, TAUBIN_MATRICES_SIZE, TAUBIN_MATRICES_SIZE> M;
137 Eigen::Matrix<double, TAUBIN_MATRICES_SIZE, TAUBIN_MATRICES_SIZE> N;
141 for (
int i = 0; i < n; i++)
143 if (isnan(this->input_->points[indices[i]].x))
146 double x = this->input_->points[indices[i]].x;
147 double y = this->input_->points[indices[i]].y;
148 double z = this->input_->points[indices[i]].z;
253 M.triangularView<Eigen::StrictlyLower>() = M.triangularView<Eigen::StrictlyUpper>().transpose();
258 N.triangularView<Eigen::StrictlyLower>() = N.triangularView<Eigen::StrictlyUpper>().transpose();
261 Eigen::MatrixXd eigen_vectors;
262 Eigen::MatrixXd lambda;
263 this->solveGeneralizedEigenProblem(M, N, eigen_vectors, lambda);
264 Eigen::VectorXd eigen_values = lambda.col(0).cwiseQuotient(lambda.col(2));
266 eigen_values.segment(0, 9).minCoeff(&min_index);
267 quadric_parameters = eigen_vectors.col(min_index);
268 quadric_parameters.segment(3, 3) *= 0.5;
271 this->unpackQuadric(quadric_parameters, quadric_centroid, quadric_covariance_matrix);
280 return p1[1] < p2[1];
297 bool is_deterministic =
false)
300 double a = quadric_parameters(0);
301 double b = quadric_parameters(1);
302 double c = quadric_parameters(2);
303 double d = 2 * quadric_parameters(3);
304 double e = 2 * quadric_parameters(4);
305 double f = 2 * quadric_parameters(5);
306 double g = quadric_parameters(6);
307 double h = quadric_parameters(7);
308 double i = quadric_parameters(8);
311 Eigen::Matrix<double, 3, Eigen::Dynamic> samples_near_surf;
315 if (!is_deterministic)
318 Eigen::Matrix<double, 3, Eigen::Dynamic> samples_matrix(3, sample_num);
320 for (
int t = 0; t < sample_num; t++)
322 int r = rand() % indices.size();
324 if (isnan(this->input_->points[indices[r]].x))
327 samples_matrix.col(t) << this->input_->points[indices[r]].x, this->input_->points[indices[r]].y, this->input_->points[indices[r]].z;
330 samples_near_surf = samples_matrix;
335 Eigen::Matrix<double, 3, Eigen::Dynamic> samples_matrix(3, indices.size());
338 for (std::size_t t = 0; t < indices.size(); t++)
340 if (isnan(this->input_->points[indices[t]].x))
343 samples_matrix(0, t) = this->input_->points[indices[t]].x;
344 samples_matrix(1, t) = this->input_->points[indices[t]].y;
345 samples_matrix(2, t) = this->input_->points[indices[t]].z;
349 samples_matrix.conservativeResize(3, sample_num);
350 samples_near_surf = samples_matrix;
351 sample_num = samples_near_surf.cols();
356 (2 * a * samples_near_surf.row(0) + d * samples_near_surf.row(1) + f * samples_near_surf.row(2)).array() + g;
358 (2 * b * samples_near_surf.row(1) + d * samples_near_surf.row(0) + e * samples_near_surf.row(2)).array() + h;
360 (2 * c * samples_near_surf.row(2) + e * samples_near_surf.row(1) + f * samples_near_surf.row(0)).array() + i;
361 Eigen::MatrixXd normals(3, sample_num);
362 normals << fx, fy, fz;
363 Eigen::MatrixXd gradient_magnitude = ((normals.cwiseProduct(normals)).colwise().sum()).cwiseSqrt();
364 normals = normals.cwiseQuotient(gradient_magnitude.replicate(3, 1));
367 Eigen::Matrix3d second_derivative_f;
368 second_derivative_f << 2 * a, d, f, d, 2 * b, e, f, e, 2 * c;
369 std::vector < std::vector<double> > list(sample_num, std::vector<double>(2));
372 for (
int t = 0; t < sample_num; t++)
375 Eigen::Matrix3d curvature_matrix = -1
376 * (Eigen::MatrixXd::Identity(3, 3) - normals.col(t) * normals.col(t).transpose()) * second_derivative_f
377 / gradient_magnitude(t);
378 Eigen::EigenSolver<Eigen::Matrix3d> eigen_solver(curvature_matrix);
379 Eigen::Vector3d curvatures = eigen_solver.eigenvalues().real();
381 double max_coeff = curvatures.cwiseAbs().maxCoeff(&index);
383 list[t][1] = curvatures(index);
384 normals.col(t) *= this->
sign(list[t][1]);
385 list[t][1] = fabs(list[t][1]);
389 std::sort(list.begin(), list.end(), isSecondElementSmaller);
392 int median_curvature_index = list[sample_num / 2 - 1][0];
393 Eigen::Vector3d median_curvature_point = samples_near_surf.col(median_curvature_index);
394 median_curvature = list[sample_num / 2 - 1][1];
395 normal = normals.col(median_curvature_index);
399 Eigen::Matrix3d curvature_matrix = (-1) * (Eigen::MatrixXd::Identity(3, 3) - normal * normal.transpose())
400 * second_derivative_f / gradient_magnitude(median_curvature_index);
401 Eigen::EigenSolver<Eigen::Matrix3d> eigen_solver(curvature_matrix);
402 Eigen::Matrix3d curvature_vectors = eigen_solver.eigenvectors().real();
404 eigen_solver.eigenvalues().real().cwiseAbs().maxCoeff(&max_index);
405 curvature_axis = curvature_vectors.col(max_index).cross(normal);
413 num_samples_ = num_samples;
421 num_threads_ = num_threads;
428 return neighborhoods_;
436 return neighborhood_centroids_;
446 computeFeature(
const Eigen::MatrixXd &samples, PointCloudOut &output);
458 computeFeature(PointCloudOut &output);
468 computeFeature(
const std::vector<int> &nn_indices,
int index, PointCloudOut &output);
477 inline void unpackQuadric(
const Eigen::VectorXd &quadric_parameters, Eigen::Vector3d &quadric_centroid,
478 Eigen::Matrix3d &quadric_covariance_matrix)
480 double a = quadric_parameters(0);
481 double b = quadric_parameters(1);
482 double c = quadric_parameters(2);
483 double d = quadric_parameters(3);
484 double e = quadric_parameters(4);
485 double f = quadric_parameters(5);
486 double g = quadric_parameters(6);
487 double h = quadric_parameters(7);
488 double i = quadric_parameters(8);
489 double j = quadric_parameters(9);
491 Eigen::Matrix3d parameter_matrix;
492 parameter_matrix << a, d, f, d, b, e, f, e, c;
495 Eigen::Matrix3d inverse_parameter_matrix = parameter_matrix.inverse();
496 quadric_centroid = -0.5 * inverse_parameter_matrix * ghi;
497 double k = j - 0.25 * ghi.transpose() * inverse_parameter_matrix * ghi;
498 quadric_covariance_matrix = -1 * parameter_matrix / k;
523 Eigen::MatrixXd& lambda)
526 if (B.cols() != N || A.rows() != N || B.rows() != N)
532 int LDA = A.outerStride();
533 int LDB = B.outerStride();
534 int LDV = v.outerStride();
540 double* alphar =
const_cast<double*
>(lambda.col(0).data());
541 double* alphai =
const_cast<double*
>(lambda.col(1).data());
542 double* beta =
const_cast<double*
>(lambda.col(2).data());
545 dggev_(
"N",
"V", &N, A.data(), &LDA, B.data(), &LDB, alphar, alphai, beta, 0, &LDV, v.data(), &LDV, &WORKDUMMY,
548 LWORK = int(WORKDUMMY) + 32;
549 Eigen::VectorXd WORK(LWORK);
551 dggev_(
"N",
"V", &N, A.data(), &LDA, B.data(), &LDB, alphar, alphai, beta, 0, &LDV, v.data(), &LDV, WORK.data(),
567 #endif // PCL_FEATURES_CURVATURE_ESTIMATION_TAUBIN_H_
void dggev_(const char *JOBVL, const char *JOBVR, const int *N, const double *A, const int *LDA, const double *B, const int *LDB, double *ALPHAR, double *ALPHAI, double *BETA, double *VL, const int *LDVL, double *VR, const int *LDVR, double *WORK, const int *LWORK, int *INFO)
static bool isSecondElementSmaller(const std::vector< double > &p1, const std::vector< double > &p2)
Compares two vectors by looking at their second elements.
unsigned int num_samples_
std::vector< std::vector< int > > const & getNeighborhoods() const
Get the indices of each point neighborhood.
std::vector< std::vector< int > > neighborhoods_
unsigned int num_threads_
CurvatureEstimationTaubin estimates the curvature for a set of point neighborhoods in the cloud using...
bool solveGeneralizedEigenProblem(const Eigen::MatrixXd &A, const Eigen::MatrixXd &B, Eigen::MatrixXd &v, Eigen::MatrixXd &lambda)
Solves the generalized Eigen problem A * v(j) = lambda(j) * B * v(j), where v are the Eigen vectors...
float curvature_centroid_y
TFSIMD_FORCE_INLINE const tfScalar & y() const
void setNumSamples(int num_samples)
Set the number of samples (point neighborhoods).
struct pcl::PointCurvatureTaubin EIGEN_ALIGN16
const int TAUBIN_MATRICES_SIZE
float curvature_centroid[4]
CurvatureEstimationTaubin(unsigned int num_threads=0)
Constructor. Set the number of threads to use.
void estimateMedianCurvature(const std::vector< int > &indices, const Eigen::VectorXd &quadric_parameters, double &median_curvature, Eigen::Vector3d &normal, Eigen::Vector3d &curvature_axis, Eigen::Vector3d &curvature_centroid, bool is_deterministic=false)
Estimate the median curvature for a given quadric, using the indices of the point neighborhood that t...
float curvature_centroid_x
int sign(double x)
Get the sign of a given value (according to the sign function).
void fitQuadric(const std::vector< int > &indices, Eigen::VectorXd &quadric_parameters, Eigen::Vector3d &quadric_centroid, Eigen::Matrix3d &quadric_covariance_matrix)
Fit a quadric to a given set of points, using their indices, and return the parameters of the quadric...
Feature< PointInT, PointOutT >::PointCloudOut PointCloudOut
void unpackQuadric(const Eigen::VectorXd &quadric_parameters, Eigen::Vector3d &quadric_centroid, Eigen::Matrix3d &quadric_covariance_matrix)
Unpack the quadric, using its parameters, and return the centroid and the covariance matrix of the qu...
TFSIMD_FORCE_INLINE const tfScalar & x() const
TFSIMD_FORCE_INLINE const tfScalar & z() const
std::vector< int > const & getNeighborhoodCentroids() const
Get the centroid indices of each point neighborhood.
std::vector< int > neighborhood_centroids_
float curvature_centroid_z
void setNumThreads(int num_threads)
Set the number of threads used for parallelizing Taubin Quadric Fitting.