14 #include <unsupported/Eigen/NonLinearOptimization>
15 #include <pcl/sample_consensus/sac_model_ellipse3d.h>
16 #include <pcl/common/concatenate.h>
18 #include <Eigen/Eigenvalues>
23 template <
typename Po
intT>
bool
27 if (samples.size () != sample_size_)
29 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::isSampleGood] Wrong number of samples (is %lu, should be %lu)!\n", samples.size (), sample_size_);
34 const Eigen::Vector3d p0 ((*input_)[samples[0]].x, (*input_)[samples[0]].y, (*input_)[samples[0]].z);
35 const Eigen::Vector3d p1 ((*input_)[samples[1]].x, (*input_)[samples[1]].y, (*input_)[samples[1]].z);
36 const Eigen::Vector3d p2 ((*input_)[samples[2]].x, (*input_)[samples[2]].y, (*input_)[samples[2]].z);
41 if ((p1 - p0).cross(p1 - p2).squaredNorm() < Eigen::NumTraits<float>::dummy_precision ())
43 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::isSampleGood] Sample points too similar or collinear!\n");
51 template <
typename Po
intT>
bool
55 if (samples.size () != sample_size_)
57 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Invalid set of samples given (%lu)!\n", samples.size ());
61 model_coefficients.resize (model_size_);
63 const Eigen::Vector3f p0((*input_)[samples[0]].x, (*input_)[samples[0]].y, (*input_)[samples[0]].z);
64 const Eigen::Vector3f p1((*input_)[samples[1]].x, (*input_)[samples[1]].y, (*input_)[samples[1]].z);
65 const Eigen::Vector3f p2((*input_)[samples[2]].x, (*input_)[samples[2]].y, (*input_)[samples[2]].z);
66 const Eigen::Vector3f p3((*input_)[samples[3]].x, (*input_)[samples[3]].y, (*input_)[samples[3]].z);
67 const Eigen::Vector3f p4((*input_)[samples[4]].x, (*input_)[samples[4]].y, (*input_)[samples[4]].z);
68 const Eigen::Vector3f p5((*input_)[samples[5]].x, (*input_)[samples[5]].y, (*input_)[samples[5]].z);
70 const Eigen::Vector3f common_helper_vec = (p1 - p0).cross(p1 - p2);
71 const Eigen::Vector3f ellipse_normal = common_helper_vec.normalized();
75 if (common_helper_vec.squaredNorm() < Eigen::NumTraits<float>::dummy_precision ())
77 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Sample points too similar or collinear!\n");
82 Eigen::Vector3f x_axis = (p1 - p0).normalized();
83 const Eigen::Vector3f z_axis = ellipse_normal.normalized();
84 const Eigen::Vector3f y_axis = z_axis.cross(x_axis).normalized();
87 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
88 << x_axis(0), y_axis(0), z_axis(0),
89 x_axis(1), y_axis(1), z_axis(1),
90 x_axis(2), y_axis(2), z_axis(2))
92 const Eigen::Matrix3f Rot_T = Rot.transpose();
95 const Eigen::Vector3f p0_ = Rot_T * (p0 - p0);
96 const Eigen::Vector3f p1_ = Rot_T * (p1 - p0);
97 const Eigen::Vector3f p2_ = Rot_T * (p2 - p0);
98 const Eigen::Vector3f p3_ = Rot_T * (p3 - p0);
99 const Eigen::Vector3f p4_ = Rot_T * (p4 - p0);
100 const Eigen::Vector3f p5_ = Rot_T * (p5 - p0);
108 const Eigen::VectorXf X = (Eigen::VectorXf(6) << p0_(0), p1_(0), p2_(0), p3_(0), p4_(0), p5_(0)).finished();
109 const Eigen::VectorXf Y = (Eigen::VectorXf(6) << p0_(1), p1_(1), p2_(1), p3_(1), p4_(1), p5_(1)).finished();
112 const Eigen::MatrixXf D = (Eigen::MatrixXf(6,6)
113 << X(0) * X(0), X(0) * Y(0), Y(0) * Y(0), X(0), Y(0), 1.0,
114 X(1) * X(1), X(1) * Y(1), Y(1) * Y(1), X(1), Y(1), 1.0,
115 X(2) * X(2), X(2) * Y(2), Y(2) * Y(2), X(2), Y(2), 1.0,
116 X(3) * X(3), X(3) * Y(3), Y(3) * Y(3), X(3), Y(3), 1.0,
117 X(4) * X(4), X(4) * Y(4), Y(4) * Y(4), X(4), Y(4), 1.0,
118 X(5) * X(5), X(5) * Y(5), Y(5) * Y(5), X(5), Y(5), 1.0)
122 const Eigen::MatrixXf S = D.transpose() * D;
125 const Eigen::MatrixXf C = (Eigen::MatrixXf(6,6)
126 << 0.0, 0.0, -2.0, 0.0, 0.0, 0.0,
127 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
128 -2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
129 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
130 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
131 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
135 Eigen::GeneralizedEigenSolver<Eigen::MatrixXf> solver;
136 solver.compute(S, C);
137 const Eigen::VectorXf eigvals = solver.eigenvalues().real();
142 for (
size_t i(0); i < static_cast<size_t>(eigvals.size()); ++i) {
143 if (eigvals(i) < absmin && !std::isinf(eigvals(i))) {
149 PCL_DEBUG(
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Failed to find the negative eigenvalue in the GES.\n");
152 const Eigen::VectorXf neigvec = solver.eigenvectors().real().col(idx).normalized();
158 const float con_A(neigvec(0));
159 const float con_B(neigvec(1));
160 const float con_C(neigvec(2));
161 const float con_D(neigvec(3));
162 const float con_E(neigvec(4));
163 const float con_F(neigvec(5));
166 const Eigen::MatrixXf M0 = (Eigen::MatrixXf(3, 3)
167 << con_F, con_D/2.0, con_E/2.0,
168 con_D/2.0, con_A, con_B/2.0,
169 con_E/2.0, con_B/2.0, con_C)
173 const Eigen::MatrixXf M = (Eigen::MatrixXf(2, 2)
179 Eigen::EigenSolver<Eigen::MatrixXf> solver_M(M);
181 Eigen::VectorXf eigvals_M = solver_M.eigenvalues().real();
184 float aux_eigval(0.0);
185 if (std::abs(eigvals_M(0) - con_A) > std::abs(eigvals_M(0) - con_C)) {
186 aux_eigval = eigvals_M(0);
187 eigvals_M(0) = eigvals_M(1);
188 eigvals_M(1) = aux_eigval;
192 float par_a = std::sqrt(-M0.determinant() / (M.determinant() * eigvals_M(0)));
193 float par_b = std::sqrt(-M0.determinant() / (M.determinant() * eigvals_M(1)));
194 const float par_h = (con_B * con_E - 2.0 * con_C * con_D) / (4.0 * con_A * con_C - std::pow(con_B, 2));
195 const float par_k = (con_B * con_D - 2.0 * con_A * con_E) / (4.0 * con_A * con_C - std::pow(con_B, 2));
196 const float par_t = (
M_PI / 2.0 - std::atan((con_A - con_C) / con_B)) / 2.0;
200 Eigen::Vector3f p_ctr;
203 p_ctr = p0 + Rot * Eigen::Vector3f(par_h, par_k, 0.0);
208 p_ctr = p0 + Rot * Eigen::Vector3f(par_k, par_h, 0.0);
212 model_coefficients[0] =
static_cast<float>(p_ctr(0));
213 model_coefficients[1] =
static_cast<float>(p_ctr(1));
214 model_coefficients[2] =
static_cast<float>(p_ctr(2));
217 model_coefficients[3] =
static_cast<float>(par_a);
219 model_coefficients[4] =
static_cast<float>(par_b);
222 model_coefficients[5] =
static_cast<float>(ellipse_normal[0]);
223 model_coefficients[6] =
static_cast<float>(ellipse_normal[1]);
224 model_coefficients[7] =
static_cast<float>(ellipse_normal[2]);
227 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, par_h, par_k, par_t).finished();
228 Eigen::Vector3f p_th_(0.0, 0.0, 0.0);
229 get_ellipse_point(params, par_t, p_th_(0), p_th_(1));
232 x_axis = (Rot * p_th_).normalized();
233 model_coefficients[8] =
static_cast<float>(x_axis[0]);
234 model_coefficients[9] =
static_cast<float>(x_axis[1]);
235 model_coefficients[10] =
static_cast<float>(x_axis[2]);
238 PCL_DEBUG (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Model is (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g).\n",
239 model_coefficients[0], model_coefficients[1], model_coefficients[2], model_coefficients[3],
240 model_coefficients[4], model_coefficients[5], model_coefficients[6], model_coefficients[7],
241 model_coefficients[8], model_coefficients[9], model_coefficients[10]);
247 template <
typename Po
intT>
void
251 if (!isModelValid (model_coefficients))
256 distances.resize (indices_->size ());
259 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
261 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
263 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
265 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
267 const float par_a(model_coefficients[3]);
269 const float par_b(model_coefficients[4]);
272 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
273 << x_axis(0), y_axis(0), n_axis(0),
274 x_axis(1), y_axis(1), n_axis(1),
275 x_axis(2), y_axis(2), n_axis(2))
277 const Eigen::Matrix3f Rot_T = Rot.transpose();
280 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
284 for (std::size_t i = 0; i < indices_->size (); ++i)
293 const Eigen::Vector3f p((*input_)[(*indices_)[i]].x, (*input_)[(*indices_)[i]].y, (*input_)[(*indices_)[i]].z);
296 const Eigen::Vector3f p_ = Rot_T * (p - c);
302 const Eigen::Vector2f distanceVector = dvec2ellipse(params, p_(0), p_(1), th_opt);
304 distances[i] = distanceVector.norm();
309 template <
typename Po
intT>
void
311 const Eigen::VectorXf &model_coefficients,
const double threshold,
315 error_sqr_dists_.clear();
317 if (!isModelValid (model_coefficients))
321 inliers.reserve (indices_->size ());
322 error_sqr_dists_.reserve (indices_->size ());
325 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
327 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
329 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
331 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
333 const float par_a(model_coefficients[3]);
335 const float par_b(model_coefficients[4]);
338 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
339 << x_axis(0), y_axis(0), n_axis(0),
340 x_axis(1), y_axis(1), n_axis(1),
341 x_axis(2), y_axis(2), n_axis(2))
343 const Eigen::Matrix3f Rot_T = Rot.transpose();
345 const auto squared_threshold = threshold * threshold;
347 for (std::size_t i = 0; i < indices_->size (); ++i)
350 const Eigen::Vector3f p((*input_)[(*indices_)[i]].x, (*input_)[(*indices_)[i]].y, (*input_)[(*indices_)[i]].z);
353 const Eigen::Vector3f p_ = Rot_T * (p - c);
359 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
361 const Eigen::Vector2f distanceVector = dvec2ellipse(params, p_(0), p_(1), th_opt);
363 const double sqr_dist = distanceVector.squaredNorm();
364 if (sqr_dist < squared_threshold)
367 inliers.push_back ((*indices_)[i]);
368 error_sqr_dists_.push_back (sqr_dist);
374 template <
typename Po
intT> std::size_t
376 const Eigen::VectorXf &model_coefficients,
const double threshold)
const
379 if (!isModelValid (model_coefficients))
381 std::size_t nr_p = 0;
384 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
386 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
388 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
390 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
392 const float par_a(model_coefficients[3]);
394 const float par_b(model_coefficients[4]);
397 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
398 << x_axis(0), y_axis(0), n_axis(0),
399 x_axis(1), y_axis(1), n_axis(1),
400 x_axis(2), y_axis(2), n_axis(2))
402 const Eigen::Matrix3f Rot_T = Rot.transpose();
404 const auto squared_threshold = threshold * threshold;
406 for (std::size_t i = 0; i < indices_->size (); ++i)
409 const Eigen::Vector3f p((*input_)[(*indices_)[i]].x, (*input_)[(*indices_)[i]].y, (*input_)[(*indices_)[i]].z);
412 const Eigen::Vector3f p_ = Rot_T * (p - c);
418 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
420 const Eigen::Vector2f distanceVector = dvec2ellipse(params, p_(0), p_(1), th_opt);
422 if (distanceVector.squaredNorm() < squared_threshold)
429 template <
typename Po
intT>
void
432 const Eigen::VectorXf &model_coefficients,
433 Eigen::VectorXf &optimized_coefficients)
const
435 optimized_coefficients = model_coefficients;
438 if (!isModelValid (model_coefficients))
440 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::optimizeModelCoefficients] Given model is invalid!\n");
445 if (inliers.size () <= sample_size_)
447 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::optimizeModelCoefficients] Not enough inliers to refine/optimize the model's coefficients (%lu)! Returning the same coefficients.\n", inliers.size ());
451 OptimizationFunctor functor(
this, inliers);
452 Eigen::NumericalDiff<OptimizationFunctor> num_diff(functor);
453 Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor>,
double> lm(num_diff);
454 Eigen::VectorXd coeff;
455 int info = lm.minimize(coeff);
456 for (Eigen::Index i = 0; i < coeff.size (); ++i)
457 optimized_coefficients[i] =
static_cast<float> (coeff[i]);
460 PCL_DEBUG (
"[pcl::SampleConsensusModelEllipse3D::optimizeModelCoefficients] LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g %g %g %g %g %g %g %g %g\nFinal solution: %g %g %g %g %g %g %g %g %g %g %g\n",
461 info, lm.fvec.norm (),
463 model_coefficients[0],
464 model_coefficients[1],
465 model_coefficients[2],
466 model_coefficients[3],
467 model_coefficients[4],
468 model_coefficients[5],
469 model_coefficients[6],
470 model_coefficients[7],
471 model_coefficients[8],
472 model_coefficients[9],
473 model_coefficients[10],
475 optimized_coefficients[0],
476 optimized_coefficients[1],
477 optimized_coefficients[2],
478 optimized_coefficients[3],
479 optimized_coefficients[4],
480 optimized_coefficients[5],
481 optimized_coefficients[6],
482 optimized_coefficients[7],
483 optimized_coefficients[8],
484 optimized_coefficients[9],
485 optimized_coefficients[10]);
489 template <
typename Po
intT>
void
491 const Indices &inliers,
const Eigen::VectorXf &model_coefficients,
492 PointCloud &projected_points,
bool copy_data_fields)
const
495 if (!isModelValid (model_coefficients))
497 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::projectPoints] Given model is invalid!\n");
501 projected_points.
header = input_->header;
502 projected_points.
is_dense = input_->is_dense;
505 if (copy_data_fields)
508 projected_points.
resize (input_->size ());
509 projected_points.
width = input_->width;
510 projected_points.
height = input_->height;
512 using FieldList =
typename pcl::traits::fieldList<PointT>::type;
514 for (std::size_t i = 0; i < projected_points.
size(); ++i)
521 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
523 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
525 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
527 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
529 const float par_a(model_coefficients[3]);
531 const float par_b(model_coefficients[4]);
534 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
535 << x_axis(0), y_axis(0), n_axis(0),
536 x_axis(1), y_axis(1), n_axis(1),
537 x_axis(2), y_axis(2), n_axis(2))
539 const Eigen::Matrix3f Rot_T = Rot.transpose();
542 for (std::size_t i = 0; i < inliers.size (); ++i)
545 const Eigen::Vector3f p((*input_)[(*indices_)[i]].x, (*input_)[(*indices_)[i]].y, (*input_)[(*indices_)[i]].z);
548 const Eigen::Vector3f p_ = Rot_T * (p - c);
554 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
556 dvec2ellipse(params, p_(0), p_(1), th_opt);
559 Eigen::Vector3f k_(0.0, 0.0, 0.0);
560 get_ellipse_point(params, th_opt, k_[0], k_[1]);
562 const Eigen::Vector3f k = c + Rot * k_;
564 projected_points[i].x =
static_cast<float> (k[0]);
565 projected_points[i].y =
static_cast<float> (k[1]);
566 projected_points[i].z =
static_cast<float> (k[2]);
572 projected_points.
resize (inliers.size ());
573 projected_points.
width = inliers.size ();
574 projected_points.
height = 1;
576 using FieldList =
typename pcl::traits::fieldList<PointT>::type;
578 for (std::size_t i = 0; i < inliers.size (); ++i)
583 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
585 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
587 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
589 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
591 const float par_a(model_coefficients[3]);
593 const float par_b(model_coefficients[4]);
596 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
597 << x_axis(0), y_axis(0), n_axis(0),
598 x_axis(1), y_axis(1), n_axis(1),
599 x_axis(2), y_axis(2), n_axis(2))
601 const Eigen::Matrix3f Rot_T = Rot.transpose();
604 for (std::size_t i = 0; i < inliers.size (); ++i)
607 const Eigen::Vector3f p((*input_)[(*indices_)[i]].x, (*input_)[(*indices_)[i]].y, (*input_)[(*indices_)[i]].z);
610 const Eigen::Vector3f p_ = Rot_T * (p - c);
616 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
618 dvec2ellipse(params, p_(0), p_(1), th_opt);
622 Eigen::Vector3f k_(0.0, 0.0, 0.0);
623 get_ellipse_point(params, th_opt, k_[0], k_[1]);
625 const Eigen::Vector3f k = c + Rot * k_;
627 projected_points[i].x =
static_cast<float> (k[0]);
628 projected_points[i].y =
static_cast<float> (k[1]);
629 projected_points[i].z =
static_cast<float> (k[2]);
635 template <
typename Po
intT>
bool
637 const std::set<index_t> &indices,
638 const Eigen::VectorXf &model_coefficients,
639 const double threshold)
const
642 if (!isModelValid (model_coefficients))
644 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::doSamplesVerifyModel] Given model is invalid!\n");
649 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
651 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
653 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
655 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
657 const float par_a(model_coefficients[3]);
659 const float par_b(model_coefficients[4]);
662 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
663 << x_axis(0), y_axis(0), n_axis(0),
664 x_axis(1), y_axis(1), n_axis(1),
665 x_axis(2), y_axis(2), n_axis(2))
667 const Eigen::Matrix3f Rot_T = Rot.transpose();
669 const auto squared_threshold = threshold * threshold;
670 for (
const auto &index : indices)
673 const Eigen::Vector3f p((*input_)[index].x, (*input_)[index].y, (*input_)[index].z);
676 const Eigen::Vector3f p_ = Rot_T * (p - c);
682 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
684 const Eigen::Vector2f distanceVector = dvec2ellipse(params, p_(0), p_(1), th_opt);
686 if (distanceVector.squaredNorm() > squared_threshold)
693 template <
typename Po
intT>
bool
699 if (radius_min_ != std::numeric_limits<double>::lowest() && (model_coefficients[3] < radius_min_ || model_coefficients[4] < radius_min_))
701 PCL_DEBUG (
"[pcl::SampleConsensusModelEllipse3D::isModelValid] Semi-minor axis OR semi-major axis (radii) of ellipse is/are too small: should be larger than %g, but are {%g, %g}.\n",
702 radius_min_, model_coefficients[3], model_coefficients[4]);
705 if (radius_max_ != std::numeric_limits<double>::max() && (model_coefficients[3] > radius_max_ || model_coefficients[4] > radius_max_))
707 PCL_DEBUG (
"[pcl::SampleConsensusModelEllipse3D::isModelValid] Semi-minor axis OR semi-major axis (radii) of ellipse is/are too big: should be smaller than %g, but are {%g, %g}.\n",
708 radius_max_, model_coefficients[3], model_coefficients[4]);
718 template <
typename Po
intT>
720 const Eigen::VectorXf& par,
float th,
float& x,
float& y)
727 const float par_a(par[0]);
728 const float par_b(par[1]);
729 const float par_h(par[2]);
730 const float par_k(par[3]);
731 const float par_t(par[4]);
733 x = par_h + std::cos(par_t) * par_a * std::cos(th) -
734 std::sin(par_t) * par_b * std::sin(th);
735 y = par_k + std::sin(par_t) * par_a * std::cos(th) +
736 std::cos(par_t) * par_b * std::sin(th);
742 template <
typename Po
intT>
744 const Eigen::VectorXf& par,
float u,
float v,
float& th_opt)
752 const float par_h = par[2];
753 const float par_k = par[3];
755 const Eigen::Vector2f center(par_h, par_k);
756 Eigen::Vector2f p(u, v);
760 Eigen::Vector2f x_axis(0.0, 0.0);
761 get_ellipse_point(par, 0.0, x_axis(0), x_axis(1));
765 Eigen::Vector2f y_axis(0.0, 0.0);
766 get_ellipse_point(par,
M_PI / 2.0, y_axis(0), y_axis(1));
770 const float x_proj = p.dot(x_axis) / x_axis.norm();
771 const float y_proj = p.dot(y_axis) / y_axis.norm();
775 float th_min(0.0), th_max(0.0);
776 const float th = std::atan2(y_proj, x_proj);
778 if (-
M_PI <= th && th < -
M_PI / 2.0) {
781 th_max = -
M_PI / 2.0;
783 if (-
M_PI / 2.0 <= th && th < 0.0) {
785 th_min = -
M_PI / 2.0;
788 if (0.0 <= th && th <
M_PI / 2.0) {
793 if (
M_PI / 2.0 <= th && th <=
M_PI) {
800 th_opt = golden_section_search(par, u, v, th_min, th_max, 1.e-3);
803 float x(0.0), y(0.0);
804 get_ellipse_point(par, th_opt, x, y);
805 Eigen::Vector2f distanceVector(u - x, v - y);
806 return distanceVector;
810 template <
typename Po
intT>
812 const Eigen::VectorXf& par,
823 constexpr
float phi(1.61803398874989484820f);
826 float tl(th_min), tu(th_max);
827 float ta = tl + (tu - tl) * (1 - 1 / phi);
828 float tb = tl + (tu - tl) * 1 / phi;
830 while ((tu - tl) > epsilon) {
833 float x_a(0.0), y_a(0.0);
834 get_ellipse_point(par, ta, x_a, y_a);
835 float squared_dist_ta = (u - x_a) * (u - x_a) + (v - y_a) * (v - y_a);
838 float x_b(0.0), y_b(0.0);
839 get_ellipse_point(par, tb, x_b, y_b);
840 float squared_dist_tb = (u - x_b) * (u - x_b) + (v - y_b) * (v - y_b);
842 if (squared_dist_ta < squared_dist_tb) {
845 ta = tl + (tu - tl) * (1 - 1 / phi);
847 else if (squared_dist_ta > squared_dist_tb) {
850 tb = tl + (tu - tl) * 1 / phi;
855 ta = tl + (tu - tl) * (1 - 1 / phi);
856 tb = tl + (tu - tl) * 1 / phi;
859 return (tl + tu) / 2.0;
863 #define PCL_INSTANTIATE_SampleConsensusModelEllipse3D(T) template class PCL_EXPORTS pcl::SampleConsensusModelEllipse3D<T>;
PointCloud represents the base class in PCL for storing collections of 3D points.
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
void resize(std::size_t count)
Resizes the container to contain count elements.
std::uint32_t width
The point cloud width (if organized as an image-structure).
pcl::PCLHeader header
The point cloud header.
std::uint32_t height
The point cloud height (if organized as an image-structure).
SampleConsensusModelEllipse3D defines a model for 3D ellipse segmentation.
void optimizeModelCoefficients(const Indices &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients) const override
Recompute the 3d ellipse coefficients using the given inlier set and return them to the user.
std::size_t countWithinDistance(const Eigen::VectorXf &model_coefficients, const double threshold) const override
Count all the points which respect the given model coefficients as inliers.
void projectPoints(const Indices &inliers, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool copy_data_fields=true) const override
Create a new point cloud with inliers projected onto the 3d ellipse model.
bool computeModelCoefficients(const Indices &samples, Eigen::VectorXf &model_coefficients) const override
Check whether the given index samples can form a valid 3D ellipse model, compute the model coefficien...
bool doSamplesVerifyModel(const std::set< index_t > &indices, const Eigen::VectorXf &model_coefficients, const double threshold) const override
Verify whether a subset of indices verifies the given 3d ellipse model coefficients.
void selectWithinDistance(const Eigen::VectorXf &model_coefficients, const double threshold, Indices &inliers) override
Compute all distances from the cloud data to a given 3D ellipse model.
bool isSampleGood(const Indices &samples) const override
Check if a sample of indices results in a good sample of points indices.
bool isModelValid(const Eigen::VectorXf &model_coefficients) const override
Check whether a model is valid given the user constraints.
void getDistancesToModel(const Eigen::VectorXf &model_coefficients, std::vector< double > &distances) const override
Compute all distances from the cloud data to a given 3D ellipse model.
SampleConsensusModel represents the base model class.
IndicesAllocator<> Indices
Type used for indices in PCL.
Helper functor structure for concatenate.