EnclosingEllipsoid.cpp
Go to the documentation of this file.
1 #include "EnclosingEllipsoid.h"
2 
3 #include <algorithm>
4 #include <cmath>
5 
6 #include <Eigen/Core>
7 #include <Eigen/Geometry>
8 #include <Eigen/src/Geometry/AngleAxis.h>
9 
10 #include <SimoxUtility/math/periodic/periodic_clamp.h>
11 #include <VirtualRobot/math/Helpers.h>
12 
15 
17 {
18 
19  // Eigen::Affine2f Ellipsoid::pose() const noexcept
20  // {
21  // Eigen::Affine2f pose;
22  // pose.translation() = center;
23  // pose.linear() = Eigen::Rotation2Df(angle).toRotationMatrix();
24 
25  // return pose;
26  // }
27 
28  // TODO(fabian.reister): use Eigen built-in stuff.
29  size_t
30  argmin(const Eigen::VectorXf& v)
31  {
32  const std::vector<float> vec(v.data(), v.data() + v.rows() * v.cols());
33  return std::distance(std::begin(vec), std::max_element(vec.begin(), vec.end()));
34  }
35 
36  // https://github.com/minillinim/ellipsoid/blob/master/ellipsoid.py
37 
39  {
40  ARMARX_CHECK(compute(points));
41  }
42 
43  bool
44  EnclosingEllipsoid::compute(const Points& points)
45  {
46  const float tolerance = 0.01;
47 
48  const int N = static_cast<int>(points.size());
49  const int d = 2;
50 
51  Eigen::MatrixXf P(N, d);
52 
53  for (int i = 0; i < N; i++)
54  {
55  P.row(i) = points.at(i);
56  }
57 
58  Eigen::MatrixXf Q(d + 1, N);
59  Q.topRows(d) = P.transpose();
60  Q.bottomRows(1).setOnes(); // last row
61 
62  Eigen::MatrixXf Qt = Q.transpose();
63 
64  float err = 1.F + tolerance;
65  Eigen::VectorXf u = (1.F / N) * Eigen::VectorXf::Ones(N);
66 
67  // Khachiyan Algorithm
68  while (err > tolerance)
69  {
70  const Eigen::MatrixXf V = Q * (u.asDiagonal() * Qt);
71  const Eigen::VectorXf M = (Qt * (V.inverse() * Q)).diagonal();
72 
73  const int j = static_cast<int>(argmin(M));
74  const float maximum = M(j);
75 
76  const float stepSize = (maximum - d - 1.0) / ((d + 1.0) * (maximum - 1.0));
77 
78  Eigen::VectorXf uNew = (1.0 - stepSize) * u;
79  uNew(j) += stepSize;
80 
81  err = (uNew - u).norm();
82  u = uNew;
83  }
84 
85  const Eigen::VectorXf center = P.transpose() * u;
86 
87  Eigen::MatrixXf K(d, d);
88  for (int i = 0; i < d; i++)
89  {
90  for (int j = 0; j < d; j++)
91  {
92  K(i, j) = center(i) * center(j);
93  }
94  }
95 
96  const Eigen::MatrixXf H = (P.transpose() * (u.asDiagonal() * P)) - K;
97  const Eigen::MatrixXf A = H.inverse() / d;
98 
99  const Eigen::JacobiSVD svd(A, Eigen::ComputeThinV);
100 
101  // angle
102  const Eigen::VectorXf v0 = svd.matrixV().col(0);
103  const float angle = math::Helpers::Angle(v0);
104 
105  // radii
106  const Eigen::Vector2f radii = svd.singularValues().cwiseSqrt().cwiseInverse();
107 
108  // As the singular values are sorted descending, the radii are sorted ascending.
109  // To fix this, the vector is reversed.
110  this->radii = radii.reverse();
111 
112  // Thus, the angle does no longer match the radii. It has to be altered by 90°.
113  const float angle1 = simox::math::periodic_clamp(angle + M_PI_2, -M_PI, M_PI);
114 
115  this->pose.setIdentity();
116  this->pose.translation().head<2>() = center;
117  this->pose.linear() =
118  Eigen::AngleAxisf(angle1, Eigen::Vector3f::UnitZ()).toRotationMatrix();
119 
120  return true;
121  }
122 
123 } // namespace armarx::navigation::components::laser_scanner_feature_extraction
visionx::Points
std::vector< Point > Points
Definition: ObjectShapeClassification.h:70
armarx::navigation::memory::Ellipsoid::pose
Eigen::Isometry3f pose
Definition: types.h:36
armarx::navigation::memory::Ellipsoid::radii
Eigen::Vector2f radii
Definition: types.h:38
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
EnclosingEllipsoid.h
M_PI
#define M_PI
Definition: MathTools.h:17
armarx::navigation::components::laser_scanner_feature_extraction::EnclosingEllipsoid::Points
std::vector< Point > Points
Definition: EnclosingEllipsoid.h:54
ExpressionException.h
A
class A(deque< T, A >)) ARMARX_OVERLOAD_STD_HASH_FOR_ITERABLE((class T
Enables hashing of std::list.
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:100
distance
double distance(const Point &a, const Point &b)
Definition: point.hpp:88
Logging.h
armarx::navigation::components::laser_scanner_feature_extraction::EnclosingEllipsoid::EnclosingEllipsoid
EnclosingEllipsoid(const Points &points)
Definition: EnclosingEllipsoid.cpp:38
armarx::navigation::components::laser_scanner_feature_extraction::argmin
size_t argmin(const Eigen::VectorXf &v)
Definition: EnclosingEllipsoid.cpp:30
armarx::navigation::components::laser_scanner_feature_extraction
Definition: ArVizDrawer.cpp:28
norm
double norm(const Point &a)
Definition: point.hpp:94