53 if (samples.size () != sample_size_)
55 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Invalid set of samples given (%lu)!\n", samples.size ());
59 model_coefficients.resize (model_size_);
61 const Eigen::Vector3f p0((*input_)[samples[0]].x, (*input_)[samples[0]].y, (*input_)[samples[0]].z);
62 const Eigen::Vector3f p1((*input_)[samples[1]].x, (*input_)[samples[1]].y, (*input_)[samples[1]].z);
63 const Eigen::Vector3f p2((*input_)[samples[2]].x, (*input_)[samples[2]].y, (*input_)[samples[2]].z);
64 const Eigen::Vector3f p3((*input_)[samples[3]].x, (*input_)[samples[3]].y, (*input_)[samples[3]].z);
65 const Eigen::Vector3f p4((*input_)[samples[4]].x, (*input_)[samples[4]].y, (*input_)[samples[4]].z);
66 const Eigen::Vector3f p5((*input_)[samples[5]].x, (*input_)[samples[5]].y, (*input_)[samples[5]].z);
68 const Eigen::Vector3f common_helper_vec = (p1 - p0).cross(p1 - p2);
69 const Eigen::Vector3f ellipse_normal = common_helper_vec.normalized();
73 if (common_helper_vec.squaredNorm() < Eigen::NumTraits<float>::dummy_precision ())
75 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Sample points too similar or collinear!\n");
80 Eigen::Vector3f x_axis = (p1 - p0).normalized();
81 const Eigen::Vector3f z_axis = ellipse_normal.normalized();
82 const Eigen::Vector3f y_axis = z_axis.cross(x_axis).normalized();
85 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
86 << x_axis(0), y_axis(0), z_axis(0),
87 x_axis(1), y_axis(1), z_axis(1),
88 x_axis(2), y_axis(2), z_axis(2))
90 const Eigen::Matrix3f Rot_T = Rot.transpose();
93 const Eigen::Vector3f p0_ = Rot_T * (p0 - p0);
94 const Eigen::Vector3f p1_ = Rot_T * (p1 - p0);
95 const Eigen::Vector3f p2_ = Rot_T * (p2 - p0);
96 const Eigen::Vector3f p3_ = Rot_T * (p3 - p0);
97 const Eigen::Vector3f p4_ = Rot_T * (p4 - p0);
98 const Eigen::Vector3f p5_ = Rot_T * (p5 - p0);
106 const Eigen::VectorXf X = (Eigen::VectorXf(6) << p0_(0), p1_(0), p2_(0), p3_(0), p4_(0), p5_(0)).finished();
107 const Eigen::VectorXf Y = (Eigen::VectorXf(6) << p0_(1), p1_(1), p2_(1), p3_(1), p4_(1), p5_(1)).finished();
110 const Eigen::MatrixXf D = (Eigen::MatrixXf(6,6)
111 << X(0) * X(0), X(0) * Y(0), Y(0) * Y(0), X(0), Y(0), 1.0,
112 X(1) * X(1), X(1) * Y(1), Y(1) * Y(1), X(1), Y(1), 1.0,
113 X(2) * X(2), X(2) * Y(2), Y(2) * Y(2), X(2), Y(2), 1.0,
114 X(3) * X(3), X(3) * Y(3), Y(3) * Y(3), X(3), Y(3), 1.0,
115 X(4) * X(4), X(4) * Y(4), Y(4) * Y(4), X(4), Y(4), 1.0,
116 X(5) * X(5), X(5) * Y(5), Y(5) * Y(5), X(5), Y(5), 1.0)
120 const Eigen::MatrixXf S = D.transpose() * D;
123 const Eigen::MatrixXf C = (Eigen::MatrixXf(6,6)
124 << 0.0, 0.0, -2.0, 0.0, 0.0, 0.0,
125 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
126 -2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
127 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
128 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
129 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
133 Eigen::GeneralizedEigenSolver<Eigen::MatrixXf> solver;
134 solver.compute(S, C);
135 const Eigen::VectorXf eigvals = solver.eigenvalues().real();
140 for (
size_t i(0); i < static_cast<size_t>(eigvals.size()); ++i) {
141 if (eigvals(i) < absmin && !std::isinf(eigvals(i))) {
147 PCL_DEBUG(
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Failed to find the negative eigenvalue in the GES.\n");
150 const Eigen::VectorXf neigvec = solver.eigenvectors().real().col(idx).normalized();
156 const float con_A(neigvec(0));
157 const float con_B(neigvec(1));
158 const float con_C(neigvec(2));
159 const float con_D(neigvec(3));
160 const float con_E(neigvec(4));
161 const float con_F(neigvec(5));
164 const Eigen::Matrix3f M0 = (Eigen::Matrix3f()
165 << con_F, con_D/2.0, con_E/2.0,
166 con_D/2.0, con_A, con_B/2.0,
167 con_E/2.0, con_B/2.0, con_C)
171 const Eigen::Matrix2f M = (Eigen::Matrix2f()
177 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2f> solver_M;
178 solver_M.computeDirect(M, Eigen::EigenvaluesOnly);
180 Eigen::Vector2f eigvals_M = solver_M.eigenvalues();
183 float aux_eigval(0.0);
184 if (std::abs(eigvals_M(0) - con_A) > std::abs(eigvals_M(0) - con_C)) {
185 aux_eigval = eigvals_M(0);
186 eigvals_M(0) = eigvals_M(1);
187 eigvals_M(1) = aux_eigval;
191 float par_a = std::sqrt(-M0.determinant() / (M.determinant() * eigvals_M(0)));
192 float par_b = std::sqrt(-M0.determinant() / (M.determinant() * eigvals_M(1)));
193 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));
194 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));
195 const float par_t = (
M_PI / 2.0 - std::atan((con_A - con_C) / con_B)) / 2.0;
199 Eigen::Vector3f p_ctr;
202 p_ctr.noalias() = p0 + Rot * Eigen::Vector3f(par_h, par_k, 0.0);
207 p_ctr.noalias() = p0 + Rot * Eigen::Vector3f(par_k, par_h, 0.0);
211 model_coefficients[0] =
static_cast<float>(p_ctr(0));
212 model_coefficients[1] =
static_cast<float>(p_ctr(1));
213 model_coefficients[2] =
static_cast<float>(p_ctr(2));
216 model_coefficients[3] =
static_cast<float>(par_a);
218 model_coefficients[4] =
static_cast<float>(par_b);
221 model_coefficients[5] =
static_cast<float>(ellipse_normal[0]);
222 model_coefficients[6] =
static_cast<float>(ellipse_normal[1]);
223 model_coefficients[7] =
static_cast<float>(ellipse_normal[2]);
226 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, par_h, par_k, par_t).finished();
227 Eigen::Vector3f p_th_(0.0, 0.0, 0.0);
228 internal::get_ellipse_point(params, par_t, p_th_(0), p_th_(1));
231 x_axis = (Rot * p_th_).normalized();
232 model_coefficients[8] =
static_cast<float>(x_axis[0]);
233 model_coefficients[9] =
static_cast<float>(x_axis[1]);
234 model_coefficients[10] =
static_cast<float>(x_axis[2]);
237 PCL_DEBUG (
"[pcl::SampleConsensusModelEllipse3D::computeModelCoefficients] Model is (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g).\n",
238 model_coefficients[0], model_coefficients[1], model_coefficients[2], model_coefficients[3],
239 model_coefficients[4], model_coefficients[5], model_coefficients[6], model_coefficients[7],
240 model_coefficients[8], model_coefficients[9], model_coefficients[10]);
250 if (!isModelValid (model_coefficients))
255 distances.resize (indices_->size ());
258 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
260 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
262 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
264 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
266 const float par_a(model_coefficients[3]);
268 const float par_b(model_coefficients[4]);
271 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
272 << x_axis(0), y_axis(0), n_axis(0),
273 x_axis(1), y_axis(1), n_axis(1),
274 x_axis(2), y_axis(2), n_axis(2))
276 const Eigen::Matrix3f Rot_T = Rot.transpose();
279 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
284 for (
const auto& index : *indices_)
294 const Eigen::Vector3f p((*input_)[index].x, (*input_)[index].y, (*input_)[index].z);
297 const Eigen::Vector3f p_ = Rot_T * (p - c);
303 const Eigen::Vector2f distanceVector = internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
305 distances[i++] = distanceVector.norm();
312 const Eigen::VectorXf &model_coefficients,
const double threshold,
316 error_sqr_dists_.clear();
318 if (!isModelValid (model_coefficients))
322 inliers.reserve (indices_->size ());
323 error_sqr_dists_.reserve (indices_->size ());
326 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
328 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
330 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
332 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
334 const float par_a(model_coefficients[3]);
336 const float par_b(model_coefficients[4]);
339 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
340 << x_axis(0), y_axis(0), n_axis(0),
341 x_axis(1), y_axis(1), n_axis(1),
342 x_axis(2), y_axis(2), n_axis(2))
344 const Eigen::Matrix3f Rot_T = Rot.transpose();
346 const auto squared_threshold = threshold * threshold;
348 for (
const auto& index : *indices_)
351 const Eigen::Vector3f p((*input_)[index].x, (*input_)[index].y, (*input_)[index].z);
354 const Eigen::Vector3f p_ = Rot_T * (p - c);
360 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
362 const Eigen::Vector2f distanceVector = internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
364 const double sqr_dist = distanceVector.squaredNorm();
365 if (sqr_dist < squared_threshold)
368 inliers.push_back (index);
369 error_sqr_dists_.push_back (sqr_dist);
377 const Eigen::VectorXf &model_coefficients,
const double threshold)
const
380 if (!isModelValid (model_coefficients))
382 std::size_t nr_p = 0;
385 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
387 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
389 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
391 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
393 const float par_a(model_coefficients[3]);
395 const float par_b(model_coefficients[4]);
398 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
399 << x_axis(0), y_axis(0), n_axis(0),
400 x_axis(1), y_axis(1), n_axis(1),
401 x_axis(2), y_axis(2), n_axis(2))
403 const Eigen::Matrix3f Rot_T = Rot.transpose();
405 const auto squared_threshold = threshold * threshold;
407 for (
const auto& index : *indices_)
410 const Eigen::Vector3f p((*input_)[index].x, (*input_)[index].y, (*input_)[index].z);
413 const Eigen::Vector3f p_ = Rot_T * (p - c);
419 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
421 const Eigen::Vector2f distanceVector = internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
423 if (distanceVector.squaredNorm() < squared_threshold)
468 const Eigen::VectorXf &model_coefficients,
470 bool copy_data_fields)
const
473 if (!isModelValid (model_coefficients))
475 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::projectPoints] Given model is invalid!\n");
479 projected_points.header = input_->header;
480 projected_points.is_dense = input_->is_dense;
483 if (copy_data_fields)
486 projected_points.resize (input_->size ());
487 projected_points.width = input_->width;
488 projected_points.height = input_->height;
490 using FieldList =
typename pcl::traits::fieldList<PointT>::type;
492 for (std::size_t i = 0; i < projected_points.size(); ++i)
499 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
501 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
503 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
505 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
507 const float par_a(model_coefficients[3]);
509 const float par_b(model_coefficients[4]);
512 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
513 << x_axis(0), y_axis(0), n_axis(0),
514 x_axis(1), y_axis(1), n_axis(1),
515 x_axis(2), y_axis(2), n_axis(2))
517 const Eigen::Matrix3f Rot_T = Rot.transpose();
520 for (
const auto& inlier : inliers)
523 const Eigen::Vector3f p((*input_)[inlier].x, (*input_)[inlier].y, (*input_)[inlier].z);
526 const Eigen::Vector3f p_ = Rot_T * (p - c);
532 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
534 internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
537 Eigen::Vector3f k_(0.0, 0.0, 0.0);
538 internal::get_ellipse_point(params, th_opt, k_[0], k_[1]);
540 const Eigen::Vector3f k = c + Rot * k_;
542 projected_points[inlier].x =
static_cast<float> (k[0]);
543 projected_points[inlier].y =
static_cast<float> (k[1]);
544 projected_points[inlier].z =
static_cast<float> (k[2]);
550 projected_points.resize (inliers.size ());
551 projected_points.width = inliers.size ();
552 projected_points.height = 1;
554 using FieldList =
typename pcl::traits::fieldList<PointT>::type;
556 for (std::size_t i = 0; i < inliers.size (); ++i)
558 pcl::for_each_type <FieldList> (NdConcatenateFunctor <PointT, PointT> ((*input_)[inliers[i]], projected_points[i]));
561 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
563 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
565 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
567 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
569 const float par_a(model_coefficients[3]);
571 const float par_b(model_coefficients[4]);
574 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
575 << x_axis(0), y_axis(0), n_axis(0),
576 x_axis(1), y_axis(1), n_axis(1),
577 x_axis(2), y_axis(2), n_axis(2))
579 const Eigen::Matrix3f Rot_T = Rot.transpose();
583 for (
const auto& inlier : inliers)
586 const Eigen::Vector3f p((*input_)[inlier].x, (*input_)[inlier].y, (*input_)[inlier].z);
589 const Eigen::Vector3f p_ = Rot_T * (p - c);
595 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
597 internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
600 Eigen::Vector3f k_(0.0, 0.0, 0.0);
601 internal::get_ellipse_point(params, th_opt, k_[0], k_[1]);
603 const Eigen::Vector3f k = c + Rot * k_;
605 projected_points[i].x =
static_cast<float> (k[0]);
606 projected_points[i].y =
static_cast<float> (k[1]);
607 projected_points[i++].z =
static_cast<float> (k[2]);
615 const std::set<index_t> &indices,
616 const Eigen::VectorXf &model_coefficients,
617 const double threshold)
const
620 if (!isModelValid (model_coefficients))
622 PCL_ERROR (
"[pcl::SampleConsensusModelEllipse3D::doSamplesVerifyModel] Given model is invalid!\n");
627 const Eigen::Vector3f c(model_coefficients[0], model_coefficients[1], model_coefficients[2]);
629 const Eigen::Vector3f n_axis(model_coefficients[5], model_coefficients[6], model_coefficients[7]);
631 const Eigen::Vector3f x_axis(model_coefficients[8], model_coefficients[9], model_coefficients[10]);
633 const Eigen::Vector3f y_axis = n_axis.cross(x_axis).normalized();
635 const float par_a(model_coefficients[3]);
637 const float par_b(model_coefficients[4]);
640 const Eigen::Matrix3f Rot = (Eigen::Matrix3f(3,3)
641 << x_axis(0), y_axis(0), n_axis(0),
642 x_axis(1), y_axis(1), n_axis(1),
643 x_axis(2), y_axis(2), n_axis(2))
645 const Eigen::Matrix3f Rot_T = Rot.transpose();
647 const auto squared_threshold = threshold * threshold;
648 for (
const auto &index : indices)
651 const Eigen::Vector3f p((*input_)[index].x, (*input_)[index].y, (*input_)[index].z);
654 const Eigen::Vector3f p_ = Rot_T * (p - c);
660 const Eigen::VectorXf params = (Eigen::VectorXf(5) << par_a, par_b, 0.0, 0.0, 0.0).finished();
662 const Eigen::Vector2f distanceVector = internal::dvec2ellipse(params, p_(0), p_(1), th_opt);
664 if (distanceVector.squaredNorm() > squared_threshold)