上一篇博客大致说明了下ceres-solver库的编译,然后形成了一个二次开发的库,下面就是用这个二次开发库来写一个简单(其实不太简单)的DEMO来演示ceres-solver库的强大。我们以求解一个非线性的方程(椭球方程)的系数为例子。下面是椭球方程的公式。

我们要求解的就是。为了演示,我通过程序生成了一个单位球上面的一系列坐标,也就是上面的abc均为1,偏移量均为0。为了验证ceres-solver是否可以完成这个工作。

首先我们编写下面的测试代码。

#include "glog/logging.h"
#include "ceres/ceres.h"
#include <vector> using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve; struct EllipsoidResidual
{
/*
* x, y, z 分别为观测值
*/
EllipsoidResidual(double x, double y, double z):_x(x), _y(y), _z(z){} /*
*pEllipsoidParameters:-2分别为a、b、c,3-5分别为x0、y0、z0
*/
template <typename T> bool operator () (const T * const pEllipsoidParameters, T * residual) const
{
residual[0] = T(1.0) - T(_x - pEllipsoidParameters[3])*T(_x - pEllipsoidParameters[3])/T(pEllipsoidParameters[0]*pEllipsoidParameters[0]) -
T(_y - pEllipsoidParameters[4])*T(_y - pEllipsoidParameters[4])/T(pEllipsoidParameters[1]*pEllipsoidParameters[1]) -
T(_z - pEllipsoidParameters[5])*T(_z - pEllipsoidParameters[5])/T(pEllipsoidParameters[2]*pEllipsoidParameters[2]);
return true;
}
private:
const double _x;
const double _y;
const double _z;
}; struct Point3D
{
double x;
double y;
double z;
}; /*
* 用于解算椭球参数的类
* m_EllipsoidParameters:椭球参数的初始值
* m_bInitParameters:椭球参数是否已经进行初始化
* m_data:观测值
* m_options:解算方式选项,可以进行设置
* m_summary:解算的报告信息
*
* 使用方式:
* ()设置椭球参数的初始值(m_EllipsoidParameters),并标记m_bInitParameters为true
* ()设置观测值m_data(个数大于)
* ()调用SolveParameters()函数
* ()得到结果m_EllipsoidParameters与解算报告信息m_summary
*/
struct EllipsoidFittingSolver
{
EllipsoidFittingSolver()
{
m_options;
m_options.max_num_iterations = 25;
m_options.linear_solver_type = ceres::DENSE_QR;
m_options.minimizer_progress_to_stdout = true;
m_bInitParameters = false;
} bool SolveParameters()
{
if (m_data.size() < 6 || !m_bInitParameters)
{
return false;
} Problem problem;
const int nObservations = m_data.size();
for (int i = 0; i < nObservations; ++i)
{
problem.AddResidualBlock(new AutoDiffCostFunction<EllipsoidResidual, 1, 6>(
new EllipsoidResidual(m_data[i].x, m_data[i].y, m_data[i].z)),
NULL,
m_EllipsoidParameters);
} Solve(m_options, &problem, &m_summary);
return true;
} bool m_bInitParameters;
double m_EllipsoidParameters[6];
std::vector<Point3D> m_data;
Solver::Options m_options;
Solver::Summary m_summary;
}; double* readFile(const char* szFilename,int& nCount)
{
if(!szFilename)return NULL;
FILE* fid=fopen(szFilename,"rt");
if(!fid)return NULL; nCount=0;
fscanf(fid,"%d",&nCount);//读第一行数据,是行数,赋给nCount int nSize=sizeof(double)*3*nCount;//根据行数分配大小,要取列数据所以是*nCount
double* dbData=(double*)malloc(nSize);
if(!dbData)return NULL;
memset(dbData,0,nSize);//将申请的内存空间初始化为 double dbInvalid=0.;
for(int i=0;i<nCount;i++)
{
double* dbTmp=dbData+3*i;
fscanf(fid,"%lf %lf %lf",dbTmp,dbTmp+1,dbTmp+2);
}
fclose(fid); return dbData;
} int main(int argc, char** argv)
{
google::InitGoogleLogging(argv[0]); EllipsoidFittingSolver efs;
double dInit[6] = {0.5,0.5,0.5,0.5,0.5,0.5};
memcpy(efs.m_EllipsoidParameters, dInit, sizeof(double)*6);
efs.m_bInitParameters = true; const char* pszFilename = "testdata2.txt";
fprintf(stderr,"ReadFile begins.\n");
int nCount=-1;
double* dbSrcData= readFile(pszFilename, nCount);
if(nCount<0)
{
fprintf(stderr,"ReadFile Error!\n");
return -1;
}
else
fprintf(stderr,"ReadFile Completed.!\n"); for (int i=0; i<nCount; i++)
{
Point3D pt;
pt.x = dbSrcData[i*3+0];
pt.y = dbSrcData[i*3+1];
pt.z = dbSrcData[i*3+2]; efs.m_data.push_back(pt);
} free(dbSrcData); if(efs.SolveParameters())
{
fprintf(stdout,"Solver Success!\n"); fprintf(stdout,"a=%lf b=%lf c=%lf\n",efs.m_EllipsoidParameters[0],efs.m_EllipsoidParameters[1],efs.m_EllipsoidParameters[2]);
fprintf(stdout,"x0=%lf y0=%lf z0=%lf\n",efs.m_EllipsoidParameters[3],efs.m_EllipsoidParameters[4],efs.m_EllipsoidParameters[5]);
fprintf(stdout,"%s\n",efs.m_summary.FullReport().c_str());
}
else
fprintf(stdout,"Solver Failed!\n"); return 0;
}

测试数据部分截图如下:

新建一个控制台应用程序,然后将第一篇的include和lib目录分别添加到工程中,同时配置引用的lib文件(RELEASE版本引用libglog.lib和ceres_r.lib,DEBUG版本引用libglog.lib和ceres_d.lib),然后编译即可。执行结果如下图所示。

红色区域为迭代过程,蓝色区域为计算的结果,最下面的为拟合报告。从蓝色的区域可以看出,拟合的abc的值为1,偏移量为0,和我们开始指定的球体方程一致。

从代码中可以看出,ceres-solver库不需要对非线性的方程进行求偏导数进行线性化然后再使用最小二乘求解系数。这大大方便了人们手动计算偏导数列系数矩阵,可以避免复杂的计算以及手工计算过程中出现的错误。

最后感谢@末末_happy提供的测试数据,感谢@AegeanSea87编写的测试代码。

ceres-solver库使用示例的更多相关文章

  1. Ceres Solver: 高效的非线性优化库(一)

    Ceres Solver: 高效的非线性优化库(一) 注:本文基于Ceres官方文档,大部分由英文翻译而来.可作为非官方参考文档. 简介 Ceres,原意是谷神星,是发现不久的一颗轨道在木星和火星之间 ...

  2. VINS(九)Ceres Solver优化(未完待续)

    使用Ceres Solver库处理后端优化问题,首先系统的优化函数为

  3. Ceres Solver: 高效的非线性优化库(二)实战篇

    Ceres Solver: 高效的非线性优化库(二)实战篇 接上篇: Ceres Solver: 高效的非线性优化库(一) 如何求导 Ceres Solver提供了一种自动求导的方案,上一篇我们已经看 ...

  4. Ceres Solver for android

        最近开发中,需要对图片做一些处理与线性技术,这时就用到了Ceres Solver.如何把Ceres Solver集成到Android里呢? 官网给了一个解决方案,简洁明了:   Downloa ...

  5. C/C++ 开源库及示例代码

    C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...

  6. RAC集群数据库连库代码示例(jdbc thin方式,非oci)

    1.RAC集群数据库连库代码示例(jdbc thin方式,非oci):jdbc.driverClassName=oracle.jdbc.driver.OracleDriverjdbc.url=jdbc ...

  7. Ceres Solver 入门稍微多一点

    其实ceres solver用了挺多的,可能是入门不精,有时候感觉感觉不理解代码上是怎么实现的,这次就通过ceres的官网仔细看了一些介绍,感觉对cpp了解更好了一些. 跟g2o的比较的话,感觉cer ...

  8. node.js的Promise库-bluebird示例

    前两天公司一哥们写了一段node.js代码发给我,后面特意提了一句“写的不太优雅”.我知道,他意思是回调嵌套回调,因为当时比较急也就没有再纠结.然而内心中总记得要解决这个问题.解决node.js的回调 ...

  9. Robot Framework - 4 - 创建和扩展测试库的示例

    创建和扩展Library的示例 示例:Check status on Linux OS 创建与使用library的基本步骤:           1--- library实现的内容和实现的方式     ...

随机推荐

  1. 《Non-Negative Matrix Factorization for Polyphonic Music Transcription》译文

    NMF(非负矩阵分解),由于其分解出的矩阵是非负的,在一些实际问题中具有非常好的解释,因此用途很广.在此,我给大家介绍一下NMF在多声部音乐中的应用.要翻译的论文是利用NMF转录多声部音乐的开山之作, ...

  2. Android简易实战教程--第四十七话《使用OKhttp回调方式获取网络信息》

    在之前的小案例中写过一篇使用HttpUrlConnection获取网络数据的例子.在OKhttp盛行的时代,当然要学会怎么使用它,本篇就对其基本使用做一个介绍,然后再使用它的接口回调的方式获取相同的数 ...

  3. springMVC源码分析--异常处理机制HandlerExceptionResolver简单示例(一)

    springMVC对Controller执行过程中出现的异常提供了统一的处理机制,其实这种处理机制也简单,只要抛出的异常在DispatcherServlet中都会进行捕获,这样就可以统一的对异常进行处 ...

  4. 23 服务的绑定启动Demo3

    MainActivity.java package com.example.day23_service_demo3; import com.example.day23_service_demo3.My ...

  5. Java异常封装(自己定义错误码和描述,附源码)

    真正工作了才发现,Java里面的异常在真正工作中使用还是十分普遍的.什么时候该抛出什么异常,这个是必须知道的. 当然真正工作里面主动抛出的异常都是经过分装过的,自己可以定义错误码和异常描述. 下面小宝 ...

  6. PHP和MySQL Web开发学习笔记介绍

    前言 从2016年2月1日开始,之后的几个月左右的时间里,我会写一个系列的PHP和MySQL Web开发的学习笔记.我之前一直从事Java语言的开发工作,最近这段时间非常想学习一门语言,就选择了PHP ...

  7. tomcat启动批处理——catalina.bat

    这个批处理才是tomcat服务器启动跟关闭的核心脚本.其中包括....(各种变量),此节将详细讲解这个批处理的逻辑. 先看看第一部分脚本: ****************************** ...

  8. JDK的安装以及配置

    JDK的安装以及配置 JDK(Java Development Kit),顾名思义,是 Java 语言的软件开发工具包(SDK). Android发开使用Java语言,所以装JDK是Android开发 ...

  9. 如何使用《DB 查询分析器》高效地生成旬报货运量数据

    如何使用<DB 查询分析器>高效地生成旬报货运量数据 马根峰                    (广东联合电子服务股份有限公司, 广州 510300) 1      引言   中国本土 ...

  10. VS2008界面语言设置

    在卸载某个软件的时候,不知道什么原因导致vs2008的界面变成中文的了,但是菜单还是英文的,很不美观. 几经查找,最后可以在如下的地方设置界面语言 Tools -> Options 如果设置成 ...