使用Ceres求解非线性优化问题,一共分为三个部分:

1、 第一部分:构建cost fuction,即代价函数,也就是寻优的目标式。这个部分需要使用仿函数(functor)这一技巧来实现,做法是定义一个cost function的结构体,在结构体内重载()运算符。

2、 第二部分:通过代价函数构建待求解的优化问题。

3、 第三部分:配置求解器参数并求解问题,这个步骤就是设置方程怎么求解、求解过程是否输出等,然后调用一下Solve方法

#include <iostream>
#include <opencv2/core/core.hpp>
#include <ceres/ceres.h>
#include <chrono> using namespace std; // 代价函数的计算模型
struct CURVE_FITTING_COST {
CURVE_FITTING_COST(double x, double y) : _x(x), _y(y) {} // 残差的计算
template<typename T>
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 ar = 1.0, br = 2.0, cr = 1.0; // 真实参数值
double ae = 2.0, be = -1.0, ce = 5.0; // 估计参数值
int N = 100; // 数据点
double w_sigma = 1.0; // 噪声Sigma值
double inv_sigma = 1.0 / w_sigma;
cv::RNG rng; // OpenCV随机数产生器 vector<double> x_data, y_data; // 数据
for (int i = 0; i < N; i++) {
double x = i / 100.0;
x_data.push_back(x);
y_data.push_back(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma * w_sigma));
} double abc[3] = {ae, be, ce}; // 构建最小二乘问题
ceres::Problem problem;
for (int i = 0; i < N; i++) {
problem.AddResidualBlock( // 向问题中添加误差项
// 使用自动求导,将定义的代价函数结构体传入。模板参数:误差类型,输出维度即残差的维度,输入维度即优化参数的维度,维数要与前面struct中一致
new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3>(
new CURVE_FITTING_COST(x_data[i], y_data[i])
),
nullptr, // 核函数,这里不使用,为空
abc // 待估计参数
);
} // 配置求解器
ceres::Solver::Options options; // 这里有很多配置项可以填
options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; // 增量方程如何求解
//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<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "solve time cost = " << time_used.count() << " seconds. " << endl; // 输出结果
cout << summary.BriefReport() << endl; //输出优化的简要信息
cout << "estimated a,b,c = ";
for (auto a:abc) cout << a << " ";
cout << endl; return 0;
}

cmakelists.txt:

cmake_minimum_required(VERSION 2.8)
project(gaussnewton)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
find_package(Ceres REQUIRED)
include_directories(${CERES_INCLUDE_DIRS})
include_directories("/usr/include/eigen3")
set(SOURCE_FILES main.cpp)
add_executable(gaussnewton ${SOURCE_FILES})
target_link_libraries(gaussnewton ${OpenCV_LIBS})
target_link_libraries(gaussnewton ${CERES_LIBRARIES})

最新文章

  1. testng+reportng,运行xml
  2. mysql新建用户的方法
  3. array数组加过滤
  4. C语言:break和continue
  5. C++ 虚函数在基类与派生类对象间的表现及其分析
  6. WEB网页插件 如何实现 选择上传图片路径 【高级问题】
  7. 【个人笔记】001-PHP基础-01-PHP快速入门-01-PHP职业路线及PHP前景
  8. dedecms 文章排列方式
  9. 基于mapnik做切片服务器的几点总结
  10. Python常用字符编码(转)
  11. 一、PTA实验作业
  12. java 幂等性(转)
  13. 微服务解决框架--SpringCloud
  14. 【windows核心编程】远程线程DLL注入
  15. vue项目在安卓低版本机显示空白原因
  16. IE DIV背景透明,点击事件不响应解决方案
  17. Fading Like a Flower
  18. mysql编写存储过程(1)
  19. virtualbox+vagrant学习-2(command cli)-12-vagrant Provision命令
  20. RobotFramework自动化4-批量操作案例

热门文章

  1. 云原生之旅 - 14)遵循 GitOps 实践的好工具 ArgoCD
  2. 第2-4-3章 规则引擎Drools基础语法-业务规则管理系统-组件化-中台
  3. JavaEE Day14 Servlet&amp;HTTP&amp;Request
  4. kali2021.4a安装angr(使用virtualenv)
  5. Flask框架使用SQLAlchemy的ORM
  6. http转成https工具类
  7. Nmap常用方法
  8. 【FAQ】申请Health Kit权限的常见问题及解答
  9. json 提取器将提取的所有id拼接成字符串
  10. 物以类聚人以群分,通过GensimLda文本聚类构建人工智能个性化推荐系统(Python3.10)