

CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(untitled2)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Release)
set(ALL_TARGET_LIBRARIES "")
include(cmake/FindG2O.cmake)
#方式1
find_package(Eigen3 REQUIRED)
include_directories("/usr/local/include/eigen3")
#方式2
#include(cmake/FindEigen3.cmake)
add_executable(fit_curve fit_curve.cpp)
target_link_libraries(fit_curve ${ALL_TARGET_LIBRARIES})

fit_curve.cpp
#include <Eigen/Core>
#include <iostream>
#include "g2o/stuff/sampler.h"
#include "g2o/core/sparse_optimizer.h"
#include "g2o/core/block_solver.h"
#include "g2o/core/optimization_algorithm_levenberg.h"
#include "g2o/core/base_vertex.h"
#include "g2o/core/base_unary_edge.h"
#include "g2o/solvers/dense/linear_solver_dense.h"
#include "g2o/core/robust_kernel_impl.h"
using namespace std;
/*!
* 继承BaseVertex类,构造顶点
*/
class VertexParams : public g2o::BaseVertex<3, Eigen::Vector3d> {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
VertexParams() = default;
bool read(std::istream & /*is*/) override {
cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
return false;
}
bool write(std::ostream & /*os*/) const override {
cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
return false;
}
//该函数作用是更新顶点的估计值
void setToOriginImpl() override {
cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
}
//更新优化之后的顶点
void oplusImpl(const double *update) override {
Eigen::Vector3d::ConstMapType v(update);
_estimate += v;
}
};
/*!
* 从BaseUnaryEdge继承得到一元边
*/
class EdgePointOnCurve : public g2o::BaseUnaryEdge<1, Eigen::Vector2d, VertexParams> {
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
EdgePointOnCurve() = default;
bool read(std::istream & /*is*/) override {
cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
return false;
}
bool write(std::ostream & /*os*/) const override {
cerr << __PRETTY_FUNCTION__ << " not implemented yet" << endl;
return false;
}
//边的误差计算
void computeError() override {
const VertexParams *params = dynamic_cast<const VertexParams *>(vertex(0));//顶点
const double &a = params->estimate()(0);
const double &b = params->estimate()(1);
const double &lambda = params->estimate()(2);
double fval = a * exp(-lambda * measurement()(0)) + b;
_error(0) = std::abs(fval - measurement()(1));
}
};
int main(int argc, char **argv) {
int numPoints = 50;
int maxIterations = 50;
bool verbose = true;
double a = 2.;
double b = 0.4;
double lambda = 0.2;
Eigen::Vector2d *points = new Eigen::Vector2d[numPoints];
ofstream points_file("../points.txt", ios::out);
//准备用于拟合的数据
for (int i = 0; i < numPoints; ++i) {
double x = g2o::Sampler::uniformRand(0, 10);
double y = a * exp(-lambda * x) + b;
y += g2o::Sampler::gaussRand(0, 0.02);
if (i == 20) {
x = 8;
y = 2.5;
}
points[i].x() = x;
points[i].y() = y;
points_file << x << " " << y << endl;
}
points_file.close();
typedef g2o::BlockSolver<g2o::BlockSolverTraits<Eigen::Dynamic, Eigen::Dynamic> > MyBlockSolver;
typedef g2o::LinearSolverDense<MyBlockSolver::PoseMatrixType> MyLinearSolver;
g2o::SparseOptimizer optimizer;
g2o::OptimizationAlgorithmLevenberg *solver = new g2o::OptimizationAlgorithmLevenberg(
g2o::make_unique<MyBlockSolver>(g2o::make_unique<MyLinearSolver>()));
optimizer.setAlgorithm(solver);
VertexParams *params = new VertexParams();
params->setId(0);
params->setEstimate(Eigen::Vector3d(1, 1, 1));//初始化顶点的估计值
optimizer.addVertex(params);
for (int i = 0; i < numPoints; ++i) {
EdgePointOnCurve *e = new EdgePointOnCurve;
e->setInformation(Eigen::Matrix<double, 1, 1>::Identity());
if (i == 20) {
e->setInformation(Eigen::Matrix<double, 1, 1>::Identity() * 10);
}
e->setVertex(0, params);
e->setMeasurement(points[i]);
g2o::RobustKernelHuber *robust_kernel_huber = new g2o::RobustKernelHuber;
robust_kernel_huber->setDelta(0.3);
e->setRobustKernel(robust_kernel_huber);
optimizer.addEdge(e);
}
optimizer.initializeOptimization();
optimizer.setVerbose(verbose);
optimizer.optimize(maxIterations);
ofstream result_file("../result.txt");
result_file << params->estimate()[0] << " "
<< params->estimate()[1] << " "
<< params->estimate()[2];
result_file.close();
cout << endl << "a, b, lambda: "
<< params->estimate()[0] << ", "
<< params->estimate()[1] << ", "
<< params->estimate()[2] << endl;
delete[] points;
return 0;
}
FindG2O.cmake

找到g2o
# Find the header files
find_path(G2O_INCLUDE_DIR g2o/core/base_vertex.h
${G2O_ROOT}/include
$ENV{G2O_ROOT}/include
$ENV{G2O_ROOT}
/usr/local/include
/usr/include
/opt/local/include
/sw/local/include
/sw/include
NO_DEFAULT_PATH
)
# Macro to unify finding both the debug and release versions of the
# libraries; this is adapted from the OpenSceneGraph FIND_LIBRARY
# macro.
macro(FIND_G2O_LIBRARY MYLIBRARY MYLIBRARYNAME)
find_library("${MYLIBRARY}_DEBUG"
NAMES "g2o_${MYLIBRARYNAME}_d"
PATHS
${G2O_ROOT}/lib/Debug
${G2O_ROOT}/lib
$ENV{G2O_ROOT}/lib/Debug
$ENV{G2O_ROOT}/lib
NO_DEFAULT_PATH
)
find_library("${MYLIBRARY}_DEBUG"
NAMES "g2o_${MYLIBRARYNAME}_d"
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/local/lib64
/usr/lib
/usr/lib64
/opt/local/lib
/sw/local/lib
/sw/lib
)
find_library(${MYLIBRARY}
NAMES "g2o_${MYLIBRARYNAME}"
PATHS
${G2O_ROOT}/lib/Release
${G2O_ROOT}/lib
$ENV{G2O_ROOT}/lib/Release
$ENV{G2O_ROOT}/lib
NO_DEFAULT_PATH
)
find_library(${MYLIBRARY}
NAMES "g2o_${MYLIBRARYNAME}"
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/local/lib64
/usr/lib
/usr/lib64
/opt/local/lib
/sw/local/lib
/sw/lib
)
if (NOT ${MYLIBRARY}_DEBUG)
if (MYLIBRARY)
set(${MYLIBRARY}_DEBUG ${MYLIBRARY})
endif (MYLIBRARY)
endif (NOT ${MYLIBRARY}_DEBUG)
endmacro(FIND_G2O_LIBRARY LIBRARY LIBRARYNAME)
# Find the core elements
FIND_G2O_LIBRARY(G2O_STUFF_LIBRARY stuff)
FIND_G2O_LIBRARY(G2O_CORE_LIBRARY core)
# Find the CLI library
FIND_G2O_LIBRARY(G2O_CLI_LIBRARY cli)
# Find the pluggable solvers
FIND_G2O_LIBRARY(G2O_SOLVER_CHOLMOD solver_cholmod)
FIND_G2O_LIBRARY(G2O_SOLVER_CSPARSE solver_csparse)
FIND_G2O_LIBRARY(G2O_SOLVER_CSPARSE_EXTENSION csparse_extension)
FIND_G2O_LIBRARY(G2O_SOLVER_DENSE solver_dense)
FIND_G2O_LIBRARY(G2O_SOLVER_PCG solver_pcg)
FIND_G2O_LIBRARY(G2O_SOLVER_SLAM2D_LINEAR solver_slam2d_linear)
FIND_G2O_LIBRARY(G2O_SOLVER_STRUCTURE_ONLY solver_structure_only)
FIND_G2O_LIBRARY(G2O_SOLVER_EIGEN solver_eigen)
# Find the predefined types
FIND_G2O_LIBRARY(G2O_TYPES_DATA types_data)
FIND_G2O_LIBRARY(G2O_TYPES_ICP types_icp)
FIND_G2O_LIBRARY(G2O_TYPES_SBA types_sba)
FIND_G2O_LIBRARY(G2O_TYPES_SCLAM2D types_sclam2d)
FIND_G2O_LIBRARY(G2O_TYPES_SIM3 types_sim3)
FIND_G2O_LIBRARY(G2O_TYPES_SLAM2D types_slam2d)
FIND_G2O_LIBRARY(G2O_TYPES_SLAM3D types_slam3d)
# G2O solvers declared found if we found at least one solver
set(G2O_SOLVERS_FOUND "NO")
if (G2O_SOLVER_CHOLMOD OR G2O_SOLVER_CSPARSE OR G2O_SOLVER_DENSE OR G2O_SOLVER_PCG OR G2O_SOLVER_SLAM2D_LINEAR OR G2O_SOLVER_STRUCTURE_ONLY OR G2O_SOLVER_EIGEN)
set(G2O_SOLVERS_FOUND "YES")
endif (G2O_SOLVER_CHOLMOD OR G2O_SOLVER_CSPARSE OR G2O_SOLVER_DENSE OR G2O_SOLVER_PCG OR G2O_SOLVER_SLAM2D_LINEAR OR G2O_SOLVER_STRUCTURE_ONLY OR G2O_SOLVER_EIGEN)
# G2O itself declared found if we found the core libraries and at least one solver
set(G2O_FOUND "NO")
if (G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_SOLVERS_FOUND)
set(G2O_FOUND "YES")
endif (G2O_STUFF_LIBRARY AND G2O_CORE_LIBRARY AND G2O_INCLUDE_DIR AND G2O_SOLVERS_FOUND)
include_directories(SYSTEM ${G2O_INCLUDE_DIR})
list(APPEND ALL_TARGET_LIBRARIES
${G2O_TYPES_DATA}
${G2O_CORE_LIBRARY}
${G2O_STUFF_LIBRARY}
${G2O_SOLVER_PCG}
${G2O_SOLVER_CSPARSE}
${G2O_SOLVER_CHOLMOD}
${G2O_TYPES_SLAM3D}
${G2O_TYPES_SLAM3D_ADDONS})
可视化代码
import numpy as np
import matplotlib.pyplot as plt
filename = './points.txt'
X, Y = [], []
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
value = [float(s) for s in line.split()]
X.append(float(value[0]))
Y.append(float(value[1]))
result_name = './result.txt'
with open(result_name, 'r') as r:
lines = r.readlines()
for line in lines:
value = [float(s) for s in line.split()]
a = float(value[0])
b = float(value[1])
my_lambda = float(value[2])
x = np.linspace(0, 10, 10)
y = a * np.exp(-my_lambda * x) + b
plt.plot(x, y, 'r')
plt.scatter(X, Y)
plt.show()
浙公网安备 33010602011771号