G2O Tutorial¶
Circle Fit¶
circle function:
\[(x - a)^2 + (y - b)^2 = r^2\]
circle极坐标的方程表示:
\[\begin{split}\begin{cases}
x = x_0 + r\cos{\theta} \\
y = y_0 + r\sin{\theta}
\end{cases}\end{split}\]
VertexCircle :
/**
* A circle located at x,y with radius r
*/
class VertexCircle : public ::g2o::BaseVertex<3, Eigen::Vector3d>
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
VertexCircle(){}
virtual bool read(std::istream& /*is*/);
virtual bool write(std::ostream& /*os*/) const;
virtual void setToOriginImpl();
virtual void oplusImpl(const double* update);
};
EdgePointOnCircle :
/**
* measurement for a point on the circle
*
* Here the measurement is the point which is on the circle.
* The error function computes the distance of the point to
* the center minus the radius of the circle.
*/
class EdgePointOnCircle : public ::g2o::BaseUnaryEdge<1, Eigen::Vector2d, VertexCircle>
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
EdgePointOnCircle() {}
virtual bool read(std::istream & /*is*/);
virtual bool write(std::ostream & /*os*/) const;
void computeError();
};
void CircleFit::RunDemo()
{
int numPoints = 100;
int maxIterations = 10;
bool verbose = true;
// --1 generate random data
Eigen::Vector2d center(4.0, 2.0);
double radius = 2.0;
Eigen::Vector2d* points = new Eigen::Vector2d[numPoints];
::g2o::Sampler::seedRand();
for (int i = 0; i < numPoints; ++i) {
double r = ::g2o::Sampler::gaussRand(radius, 0.05);
double angle = ::g2o::Sampler::uniformRand(0.0, 2.0 * M_PI);
points[i].x() = center.x() + r * cos(angle);
points[i].y() = center.y() + r * sin(angle);
}
// --2 setup the solver
::g2o::SparseOptimizer optimizer;
optimizer.setVerbose(false);
::g2o::OptimizationAlgorithmLevenberg* solver = new ::g2o::OptimizationAlgorithmLevenberg(
::g2o::make_unique<MyBlockSolver>(::g2o::make_unique<MyLinearSolver>()));
optimizer.setAlgorithm(solver);
// --3 build the optimization problem given the points
// 3.1. add the circle vertex
VertexCircle* circle = new VertexCircle();
circle->setId(0);
circle->setEstimate(Eigen::Vector3d(3.0, 3.0, 3.0)); // some initial value for the circle
optimizer.addVertex(circle);
// 3.2. add the points we measured
for (int i = 0; i < numPoints; ++i) {
EdgePointOnCircle* e = new EdgePointOnCircle;
e->setInformation(Eigen::Matrix<double, 1, 1>::Identity());
e->setVertex(0, circle);
e->setMeasurement(points[i]);
optimizer.addEdge(e);
}
// --4 perform the optimization
optimizer.initializeOptimization();
optimizer.setVerbose(verbose);
optimizer.optimize(maxIterations);
if (verbose) {
std::cout << std::endl;
}
// --5 print out the result
std::cout << "Iterative least squares solution" << std::endl;
std::cout << "center of the circle " << circle->estimate().head<2>().transpose() << std::endl;
std::cout << "radius of the cirlce " << circle->estimate()(2) << std::endl;
std::cout << "error " << ErrorOfSolution(numPoints, points, circle->estimate()) << std::endl;
std::cout << std::endl;
// clean up
delete[] points;
}
Footnotes