ceres库 拟合曲线 (含高斯牛顿法)

曲线拟合(高斯牛顿法,Ceres,g2o) 实践:曲线拟合问题 我们先通过高斯牛顿法来求解最小二乘问题,然后介绍使用优化库(Ceres/g2o)来求解此问题。 例题: 考虑一条满足如下方程的曲线: y = exp(ax2x^2x2+ bx + c) + w,其中a,b,c为曲线的参数,w是高斯噪声,满足w~(0,σ2\sigma^2σ2)。 这是个非线性模型。假设我们有N个关于x,y的观测点,想根据这些数据点来求出曲线的参数。那么可以通过求解下面的最小二乘问题来估计曲线参数: min⁡a,b,c\min\limits_{a,b,c}a,b,cmin. 阅读详情

Ceres是一个广泛使用的最小二乘问题求解库。
Ceres求解的最小二乘问题最一般的形式如下
min ⁡ x 1 2 ∑ i ρ i ( ∣ ∣ f i ( x i 1 , . . . , x i n ∣ ∣ 2 ) \min_{x}\frac{1}{2}\sum_{i}\rho_{i}(||f_{i}(x_{i1}, ... , x_{in}||^{2}) xmin​21​i∑​ρi​(∣∣fi​(xi1​,...,xin​∣∣2)

其中 f i f_{i} fi​为代价函数,在ceres中为残差块, ρ i \rho_{i} ρi​为核函数,如果不用的话,那么目标函数仍然是许多平方项的和。

Ceres求解步骤:

  1. 定义每个参数块,可以是向量,也可以是四元数,李代数。
    如果是向量,需要为每个参数块分配double数组来储存变量的值。
  2. 定义残差块的计算公式。
  3. 残差块需要定义雅可比的计算方式,也可以采用Ceres的自动求导功能。如果用自动求导,需要重载一个()操作符。
  4. 把参数块和残差块加入Ceres的problem对象中,调用Solve函数求解。

示例:
假设要拟合一个曲线 y = e x p ( a x 2 + b x + c ) + w y=exp(ax^{2}+bx+c)+w y=exp(ax2+bx+c)+w
其中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}(||y_{i}-exp(ax_{i}^{2}+bx_{i}+c)||^{2}) a,b,cmin​21​i=1∑N​(∣∣yi​−exp(axi2​+bxi​+c)∣∣2)
误差函数(残差)定义为 e i = y i − e x p ( a x i 2 + b x i + c ) e_{i}=y_{i}-exp(ax_{i}^{2}+bx_{i}+c) ei​=yi​−exp(axi2​+bxi​+c)

(x, y)是观测数据,我们要求解的参数是(a,b,c)
得到拟合的曲线 e x p ( a x 2 + b x + c ) exp(ax^{2}+bx+c) exp(ax2+bx+c)

先 给 出 高 斯 牛 顿 法 的 解 法 , 帮 助 理 解 最 小 二 乘 优 化 问 题 \color{#00F}{先给出高斯牛顿法的解法,帮助理解最小二乘优化问题} 先给出高斯牛顿法的解法,帮助理解最小二乘优化问题

如果直接用高斯牛顿法解的话,需要求误差函数 e i e_{i} ei​分别对a, b, c的偏导,得到雅可比矩阵J = [e对a的偏导,e对b的偏导,e对c的偏导]T
用JJT近似Hessian矩阵,令b=-Je (e是 e i e_{i} ei​)
直接给出增量解为 H Δ x = b H\Delta x = b HΔx=b
这个 Δ x = [ Δ a , Δ b , Δ c ] \Delta x = [\Delta a, \Delta b, \Delta c] Δx=[Δa,Δb,Δc]
然后每次对a,b,c调整 Δ x \Delta x Δx,直到误差 e i e_{i} ei​收敛且不再增大。

int gaussNewton() {
    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;

    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)); //rng:随机数产生,sigma指标准差
    }

    int iteration = 100;
    double cost = 0, lastCost = 0;  //本次迭代和上一次迭代
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for(int iter = 0; iter < iteration; iter++) {
        Matrix3d H = Matrix3d::Zero();   //Hessian = JJ^T
        Vector3d b = Vector3d::Zero();   //bias
        cost = 0;

        //每次迭代批量累加所有数据的误差
        for(int i = 0; i < N; i++) {
            double xi = x_data[i], yi = y_data[i];
            double error = yi - exp(ae*xi*xi + be*xi + ce);
            Vector3d J;
            J[0] = -xi*xi * exp(ae*xi*xi + be*xi + ce);  //de/da
            J[1] = -xi * exp(ae*xi*xi + be*xi + ce); //de/db
            J[2] = - exp(ae*xi*xi + be*xi + ce);  //de/dc

            H += inv_sigma * inv_sigma * J * J.transpose();
            b += -inv_sigma * inv_sigma * error * J;

            cost += error * error;
        }

        //批量求解方程Hx = b
        Vector3d dx = H.ldlt().solve(b); //用cholesky分解,避免求矩阵的逆
        if(isnan(dx[0])) {
            cout << "result is nan!" << endl;
            break;
        }
        if(iter > 0 && cost >= lastCost) {
            cout << "Cost : " << cost << ">=lastCost: " << lastCost << ", break: " << endl;
            break;  //理论上cost应该是逐渐变小的,变大了说明有问题
        }
        ae += dx[0];  //梯度下降法
        be += dx[1];
        ce += dx[2];

        lastCost = cost;
        cout << "total cost: " << cost << ", \t\tupdate: " << dx.transpose() <<
        "\t\testimated params: " << ae << ", " << be << ", " << ce << endl;
    }
    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 << "estimated abc = " << ae << ", " << be << ", " << ce << endl;
}

解出参数

abc = 0.890912, 2.1719, 0.943629

下面用Ceres解同一问题

//代价函数
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{
        //y-exp(ax^2 + bx + c)
        residual[0] = T(_y) - ceres::exp(abc[0] * T(_x) * T(_x) + abc[1] * T(_x) + abc[2]);
        return true;
    }
    const double _x, _y;
};

int ceres_fitting(){
    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;  //随机数产生器

    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)); //rng:随机数产生,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.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 abc = ";
    for(auto a:abc) cout << a << " ";
    cout << endl;

    return 0;
}

解出参数

estimated abc = 0.890908 2.1719 0.943628

参考链接

RTPS规范v2.3(中文版) DDSI-RTPSv2.3,DDS发现互操作性-实时发布订阅通信协议,中文版 阅读详情

相关推荐

ByteTrack参数调优全攻略:从原理到实战(含YOLOv8示例)

本文深入解析了ByteTrack多目标跟踪算法的核心原理与参数调优策略。通过拆解其独特的两阶段关联机制,并结合YOLOv8检测器,提供了针对不同应用场景(如拥挤行人、高速车辆)的精细化参数调整指南与实战示例,旨在帮助开发者解决ID切换、目标丢失等工程落地难题,提升跟踪系统的鲁棒性与实用性。

cheese的博客 321

Ceres 库:基础使用,以手写高斯-牛顿法为例

记录了使用Ceres库的基础方式,包括安装、编译、CMake工程建立,基础API的使用等内容。并以手写高斯-牛顿法为例,进行演示学习。

JasonLi的博客 4895

点云数据增强及预处理

数据增强: 1. random world flip:沿着x或者y轴,翻转点云 点云的x或者y,要翻转 3d box中心的x或者y,要翻转 3d box的朝向要翻转 point segmentation label,点云的相对顺序没有发生变化 2. random_world_rotation:沿着点云原点,旋转点云 点,x,y,绕z轴旋转 3d box,绕z轴旋转,中心和朝向都要变化 point segmentation label,点云的相对顺序没有发生变化 3. random_world_scaling

huang_victor的博客 4009

Ceres 曲线拟合

Ceres 是一个广泛使用的最小二乘问题求解库。在 Ceres 中,我们作为用户,只需按照一定步骤定义待解的优化问题,然后交给求解器计算。min⁡x12∑iρi(∥fi(xi1,…xin)∥2)s.t.lj≤xj≤ujminx​s.t.​21​∑i​ρi​(∥fi​(xi1​​,…xin​​)∥2)lj​≤xj​≤uj​​在这个问题中,x。

泠山的博客 1644

从零到一:RT-Thread与W5500的硬件抽象层设计哲学与实践启示

本文深入探讨了RT-Thread操作系统下W5500以太网模块的硬件抽象层(HAL)设计哲学与实践。通过GD32F103和STM32F103平台的适配案例,详细阐述了如何利用RT-Thread的驱动框架实现跨平台硬件无关性、模块化设计及配置定制,为嵌入式开发者提供了可复用的HAL设计方法论和实战经验。

7z8x2c4v6b9的博客 196

Vivado XDMA仿真实战:从配置到链路训练全解析

本文深入解析了Vivado中XDMA IP核的仿真实战流程,重点剖析了PCIe链路训练状态机(LTSSM)的工作原理与调试方法。通过搭建仿真环境、解读日志与波形,手把手指导如何从配置、链路训练(LTSSM)到BAR映射与DMA启动进行全流程分析与问题定位,帮助工程师掌握核心调试技能,确保PCIe链路稳定与数据传输正确。

weixin_29197051的博客 154

Ceres简介及示例(4)Curve Fitting(曲线拟合)

首先定义一个模板对象来计算残差。每一个观察值(采样点)都有一个残差,

热爱生活,忠于自己 1539

【知识点总结】电路原理 第一讲

大家好,从今天起,我将开始更新自上大学以来所学到的各种知识,之所以选择更新它们是因为最近我一直在收拾整理自己自上大学以来所收获到的各种知识,看着那厚厚一沓的书本心里不由得犯愁。如果我想找到特定的知识,那岂不是得翻到猴年马月。俗话说得好,下雨天打鞋子,闲着也是闲着,为此我设置一个专栏,将知识点一一分类总结,目的在于更好的整理所学的知识。本人学艺不精,有一些知识点地方可能存在瑕疵,希望各位大佬可以多多指教。以下是本篇文章正文内容虚断:一般通用性运算放大器的正反向输入端之间的电阻非常非常的大。

weixin_51130221的博客 4万+

视觉SLAM实践入门——(9)曲线拟合之g2o库

123

floatinglong的博客 1236

JS逆向-7881游戏平台Lb-Sign参数和Lb-Timestamp参数

本文是该专栏的第79篇,后面会持续分享python爬虫干货知识。本文以7881游戏平台为例,通过JS逆向获取它的lb-sign参数和lb-timestamp参数生成规律。针对lb-sign和lb-timestamp两个参数具体的“逆向”思路逻辑,笔者将在本文进行详细说明,并且将在正文结合“完整代码”来详细介绍。废话不多说,具体细节部分以及详细思路逻辑,跟着笔者直接往下看正文部分。(附带完整代码)

Python进阶专栏《爬虫实战进阶》,《Pyppeteer从入门到精通》原创作者 1220

基于电阻分压 + 电压跟随器的直流母线电压采样电路

摘要:本文介绍了一种基于电阻分压和电压跟随器的直流母线电压采样电路设计。该电路通过R38(240kΩ)和R41(20kΩ)组成的分压网络将高电压(如48V)降至3V,再经GS8331运放构成的电压跟随器进行隔离缓冲,最后通过RC滤波输出给ADC采集。重点分析了关键元件的选型要求:分压电阻需高精度、低温度系数;运放需高输入阻抗、低失调电压;滤波电容需稳定性好。该设计适用于工业电源、新能源BMS、变频器等需要高精度电压采样的应用场景。

qq_37999850的博客 887

非线性最小二乘拟合问题

高斯牛顿法中采用的近似二阶泰勒展开只能在展开点附近有较好的近似效果,所以我们很自然地想到应该给∆x添加一个范围,称为。SLAM的目标是最小化运动方程和观测方程的误差,这就是一个最小二乘问题。而两个方程通常是非线性的,因此也是一个。的求解要求H可逆,当H不可逆时,求解会出现问题。是f(x)的一阶导数。这个范围限定了二阶近似的有效区域,这类方法也称为。2.对于第k次迭代,求出当前的雅可比矩阵。之后类似高斯牛顿法求解即可。(此时这个方程是关于。

k42946的博客 958

【CC精品教程】iTwin capture倾斜摄影建模完整操作流程

【CC精品教程】iTwin capture倾斜摄影建模完整操作流程。包括:无人机航测外业作业流程(像控点布设、航线规划、仿地飞行、航拍)和内业数据处理软件(Pix4d、CC、EPS、PhotoScan、Globalmapper)像控点权重调配、空三加密、DOM、DSM、DEM,DLG生成、等高线生成、高程点提取,点云分类过滤分割、点云生成DEM、三维模型生成等。

智慧空间实验室 3953

非线性优化 (曲线拟合) 问题:高斯牛顿、g2o 方法总结

一、g2o图优化(General Graph Optimization) g2o最基本的类结构是怎么样的呢?我们如何来表达一个Graph,选择求解器呢?我们祭出一张图: 先看上半部分。SparseOptimizer 是我们最终要维护的东东。它是一个Optimizable Graph,从而也是一个Hyper Graph。一个 SparseOptimizer 含有很多个顶点 (都继承自 Bas...

努力努力努力 3202

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

使用C++实现最小二乘曲线拟合(使用Ceres实现)

高斯牛顿法实现时,需要根据目标函数计算雅可比矩阵,进一步计算海森矩阵,当目标函数比较简单时,雅可比矩阵和海森矩阵的计算比较容易,但是当当待估计的参数较多,并且目标函数比较复杂时,雅可比矩阵的计算非常复杂,因此引入谷歌的Ceres库,在使用Ceres进行曲线拟合之前

weixin_43283119的博客 1599

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【视觉SLAM】 十四讲ch6习题

《视觉SLAM十四讲》第六章的习题解答

weixin_68880273的博客 1277

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

视觉SLAM十四讲 第6讲 非线性优化--曲线拟合问题实践

视觉SLAM十四讲 第6讲 非线性优化–曲线拟合问题实践 6.1 代码说明 如何求解最小二乘问题 6.1.1 手写高斯牛顿法 gaussNewton.cpp #include <iostream> #include <chrono> #include <opencv2/opencv.hpp> #include <Eigen/Core> #include <Eigen/Dense> using namespace std; using namesp

weixin_48924581的博客 3505

《视觉SLAM十四讲从理论到实践 第二版》课后习题——ch6

《视觉SLAM十四讲从理论到实践 第二版》课后习题

a1446018093的博客 480

VSLAM(3):最优化问题与优化问题的代码实现

最优化问题一般是指求解特定函数定义下的最大值或则最小值,以及此时对应的自变量x的值。在SLAM问题中,可以描述为状态估计问题,这个状态一般是指机器人的位姿,现在定义系统为:其中是系统的输入,是预测模型的噪声,是观测值,是观测模型的噪声。那么我们就是想在已知系统输入和观测值的条件下去预测x,利用贝叶斯公式可知:我们假设观测的前后帧是无关的,也就是说当前观测值对应的概率恒为1,那么就可以上面的简化为然后我们就知道当前观测下的状态变量概率。

zhangzhixin1998的博客 670

第6讲 非线性优化(偏实践)

目录1 手写高斯牛顿法2 1 手写高斯牛顿法   对于如下测量方程, y=eax2+bx+c+w y=e^{ax^2+bx+c}+w y=eax2+bx+c+w 其中yyy表示对状态(a,b,c)T(a,b,c)^T(a,b,c)T的测量;www为噪声,它服从均值为0,方差为1的高斯分布。同时,有如下100个数据点, xdata[100]={0,0.01,0.02,…xi…,0.99} x_{data}[100] = \{0, 0.01, 0.02, …x_i…, 0.99 \} xdata​[100]=

YMWM_的博客 732

视觉slam学习之——ch6 非线性曲线拟合(centos系统)

非线性曲线拟合,高博士给的demo主要用谷歌ceres库实现,高斯牛顿方式实现,g2o库实现,这三个程序例子。 一.首先介绍ceres库安装与实现 ceres库是谷歌开发的C++库,用于建模和解决复杂的优化问题的。能用于解决非线性最小二乘问题。ceres介绍 ceres的官方安装链接:ceres安装文档 进入以上链接,首先下载文件,可以用git,或者点击最新稳定发布版本下载: 我下...

c20081052的专栏 1661

SLAM中的非线性优化方法

为了求解HΔgHJTJ需要对H求逆,而H为半正定矩阵,可能为病态或者奇异,此时稳定性较差,可能不收敛,即使H是非病态和非奇异,也有可能因为Δx过大而导致不收敛。

TheRun的博客 323

视觉SLAM十四讲CH6代码解析及课后习题详解

Ipopthttps://github.com/coin-or/Ipopt Overview - NLopt DocumentationNonehttps://nlopt.readthedocs.io/en/latest/ 【论文阅读1】SLAM++: SLAM at the Level of Objects - 知乎去年读了不少论文,但是感觉还是记录下来印象更深刻一些。就在知乎记录吧,内容基本都是是翻译过来的,由于时间有限,没有仔细润色,可能不太通顺,以后再慢慢改。 这里记录第一篇文章: R. F..

生活如此美好,致敬每一个热爱“热爱”的人! 4082

《视觉SLAM十四讲从理论到实践 第二版》实践部分——ch6

《视觉SLAM十四讲从理论到实践 第二版》实践部分

a1446018093的博客 341

视觉SLAM十四讲笔记-6-3

视觉SLAM十四讲笔记-6-3 6.3 实践:曲线拟合问题 6.3.1 手写高斯牛顿法 接下来用一个简单的例子来说明如何求解最小二乘问题,(最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小.最小二乘问题的主要思想就是求解未知参数 ,使得预测值与观测值之差(即误差,或者说残差)的平方和达到最小。) 接下来将演示如何手写高斯牛顿法,然后介绍如何使用优化库求解此问题.对于同一

qq_35588369的博客 1249

非线性优化 高翔

实践部分 手写高斯牛顿法 高斯牛顿法 #include <iostream> #include <opencv2/opencv.hpp> #include <Eigen/Core> #include <Eigen/Dense> #include <chrono> using namespace std; int main() { double ar = 1.0, br = 2.0, cr = 1.0 ; //真实参数值

一个有梦想,有追求,有抱负的人 350
上一篇: leetcode 413 Arithmetic Slices(等差数列划分)
下一篇: 解决error: inlining failed in call to always_inline ‘int _mm_popcnt_u32(unsigned int)’
蓝羽飞鸟
博客等级 码龄8年 1万+粉丝 727原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值