非线性优化Ceres的学习和使用(一)

本文参考视觉slam十四讲实现使用Ceres拟合曲线。

1.问题描述

假设下面曲线
y = e x p ( a x 2 + b x + c ) + w y=exp(ax^{2}+bx+c)+w y=exp(ax2+bx+c)+w
其中a,b,c为曲线的参数,w为高斯噪声。假设我们有N个关于x,y的观测数据点,想根据这些数据点求出曲线的参数。那么可以求解下面的最小二乘问题。
min ⁡ a , b , c 1 2 ∑ i = 1 N ∥ y i − e x p ( a x i 2 + b x i + c ) ∥ 2 \min_{a,b,c}\frac{1}{2}\sum_{i=1}^{N}\left \| y_{i}-exp(ax_i^{2}+bx_i+c) \right \|^{2} a,b,cmin21i=1Nyiexp(axi2+bxi+c)2

2.自动求导代码实现

CmakeLists.txt

project(ceresexp)
cmake_minimum_required(VERSION 2.8)
set( CMAKE_BUILD_TYPE "Debug" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )

# 寻找Ceres库并添加它的头文件
find_package( Ceres REQUIRED )
include_directories( ${CERES_INCLUDE_DIRS} )

# OpenCV
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_DIRS} )
add_executable(${PROJECT_NAME} main.cpp )
# 与Ceres和OpenCV链接
target_link_libraries( ${PROJECT_NAME} ${CERES_LIBRARIES} ${OpenCV_LIBS})

主函数

#include 
#include 
#include 
#include 

using namespace std;

// 代价函数的计算模型
struct CURVE_FITTING_COST
{
    CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {}
    // 残差的计算
    template 
    bool operator() (
        const T* const abc,     // 模型参数,有3维
        T* residual ) const     // 残差
    {
        residual[0] = T ( _y ) - ceres::exp ( abc[0]*T ( _x ) *T ( _x ) + abc[1]*T ( _x ) + abc[2] ); // y-exp(ax^2+bx+c)
        return true;
    }
    const double _x, _y;    // x,y数据
};

int main ( int argc, char** argv )
{
    double a=1.0, b=2.0, c=1.0;         // 真实参数值
    int N=100;                          // 数据点
    double w_sigma=1.0;                 // 噪声Sigma值
    cv::RNG rng;                        // OpenCV随机数产生器
    double abc[3] = {0,0,0};            // abc参数的估计值

    vector x_data, y_data;      // 数据

    cout<<"generating data: "< (
                new CURVE_FITTING_COST ( x_data[i], y_data[i] )
            ),
            nullptr,            // 核函数,这里不使用,为空
            abc                 // 待估计参数
        );
    }

    // 配置求解器
    ceres::Solver::Options options;     // 这里有很多配置项可以填
    options.linear_solver_type = ceres::DENSE_QR;  // 增量方程如何求解
    options.minimizer_progress_to_stdout = true;   // 输出到cout

    ceres::Solver::Summary summary;                // 优化信息
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    ceres::Solve ( options, &problem, &summary );  // 开始优化
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration time_used = chrono::duration_cast>( t2-t1 );
    cout<<"solve time cost = "<

3输出结果

Ceres Solver Report: Iterations: 22, Initial cost: 1.824887e+04, Final cost: 5.096854e+01, Termination: CONVERGENCE
estimated a,b,c = 0.891943 2.17039 0.944142 

4.总结1

Ceres求解最小二乘问题过程如下:
(1)构建最小二乘问题

problem.AddResidualBlock ( )    // 向问题中添加误差项

(2) 配置求解器

ceres::Solver::Options options;     // 这里有很多配置项可以填
 options.linear_solver_type = ceres::DENSE_QR;  // 增量方程如何求解

(3)设置输出优化迭代的信息

 ceres::Solver::Summary summary;                // 优化信息

(4)开始优化

 ceres::Solve ( options, &problem, &summary );  // 开始优化

你可能感兴趣的:(SLAM,非线性优化,ceres)