上一篇博客大致说明了下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. oo第二阶段总结

    第五次作业--多线程电梯 一.设计策略 本次作业是我们第一次接触多线程,给程序添加多线程功能后最大的挑战是实现共享数据的安全.避免冲突,由于这次作业是第一次尝试多线程方法,因此采用了将所有方法都加上s ...

  2. 安卓高级7 vitamio 视频框架 从raw文件下获取文件uri

    vitamio免费的拥有多种解码器 而且容易操作 我们先来看看原生视频播放器的怎么使用 原生的: package qianfeng.com.videoviewdemo; import android. ...

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

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

  4. Android系统对话框——自定义关闭

    Android系统对话框--自定义关闭 Dialog是我们在项目中经常用到的,5.x以后的Dialog也很好看,很安卓风,Android也给我们提供了新的包,低版本可以显示一样的效果.我们在使用的导入 ...

  5. Android二维码扫描、生成

    Android二维码扫描.生成 现在使用二维码作为信息的载体已经越来越普及,那么二维码的生成以及扫描是如何实现的呢 google为我们提供了zxing开源库供我们使用 zxing GitHub源码地址 ...

  6. python语言学习

    前段时间要做视频直播需要编写自动模块,就考虑使用python脚本语言,python的好多语法都是很独特的,比如数据类型不需要预定义,缩进的方式等,另外功能也很强大,豆瓣就是用python写的.我写的部 ...

  7. shell编程--流程控制for,do-while,if-then,break,continue,case等

    2.5 流程控制 2.5.1 if语法 1.语法格式 if condition then     statements [elif condition     then statements. ..] ...

  8. Linux下创建软链接

    创建软链接: ln -s /newdisk/app-tpl/apache-tomcat-7.0.47/webapps/app-tpl-webapp/ /newdisk/UCMSServer/tomca ...

  9. socket系列之socket服务端与客户端如何通信

    上面已经分别介绍了ServerSocket跟Socket的工作步骤,并且从应用层往系统底层剖析其运作原理,我们清楚了他们各自的一块,现在我们将把他们结合起来,看看他们是如何通信的,并详细讨论一下他们之 ...

  10. [ExtJS5学习笔记]第十八节 Extjs5的panel的dockeditems属性配置toolbar

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/39156321 官方例子:http://docs.sencha.com/extjs/5. ...