上一篇博客大致说明了下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. ubuntu ssh 防止登陆断开

    client 端: echo -e '\nServerAliveInterval 30' >> ~/.ssh/ssh_config server 端: echo -e '\nClientA ...

  2. AJAX编程实践

    ---------------------------------------------------------------------------------------------------- ...

  3. Android通知Notification全面剖析

    通知 通知是您可以在应用的常规 UI 外部向用户显示的消息.当您告知系统发出通知时,它将先以图标的形式显示在通知区域中.用户可以打开抽屉式通知栏查看通知的详细信息. 通知区域和抽屉式通知栏均是由系统控 ...

  4. Tomcat如何实现WebSocket

    WebSocket协议属于HTML5标准,越来越多浏览器已经原生支持WebSocket,它能让客户端和服务端实现双向通信.在客户端和服务器端建立一条WebSocket连接后,服务器端消息可直接发送到客 ...

  5. RxJava(二) map操作符用法详解

    欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/51531348 本文出自:[余志强的博客] 1 map操作符的作用 R ...

  6. jar包执行报ClassNotFoundException

    使用Eclipse打包jar包,指定了main class. java -jar mongoCluster.jar 但是运行的时候报ClassNotFoundException NoClassDefF ...

  7. little kernel中如何决定app目录下应该包含哪个app

    lk中是会为每个app建立一个thread,所以的app都是放在app这个路径下,那是在哪里决定的呢?一般是通过在project下面的MODULE决定的,例如下面这个例子就只用app下面的aboot这 ...

  8. 01安卓像素 dpi 、 dip 、分辨率、屏幕尺寸、px、density 关系以及换算

    一.基本概念 dip        : Density independent pixels ,设备无关像素. dp        :就是dip px        : 像素 dpi       :d ...

  9. UNIX环境高级编程——进程间通信概念

    进程间通信 --- IPC1. 进程间通信的目的a. 数据传输: 一个进程需要将他的数据发送给另一个进程b. 资源共享: 多个进程之间共享同样的资源c. 通知事件: 一个进程需要向另一个或一组进程发送 ...

  10. pig中查询top k,返回每个hour和ad_network_id下最大两个记录(SUBSTRING,order,COUNT_STAR,limit)

    pig里面是有TOP函数,不知道为什么用不了.有时间要去看看pig源码了. SET job.name 'top_k'; SET job.priority HIGH; --REGISTER piggyb ...