ceres小结 -- vins为例

2023-05-16

从 typora 复制的,排版有问题,见谅

在estimator.cpp文件里 这个函数 void Estimator::optimization()

1 声明problem

       ceres::Problem problem

2 引入核函数loss_function

       ceres::LossFunction *loss_function;// 核函数

        loss_function = new ceres::CauchyLoss(1.0);//柯西

3 添加参数块 problem.AddParameterBlock()

voidAddParameterBlock(double*values, int size); // values表示优化变量的指针,size表示优化变量的维度

// 显式 自己定义加法
voidAddParameterBlock( double*values, 
                    int size,
               LocalParameterization*local_parameterization); // slam 四元数旋转过参数化的时候用这个

位姿需要自己定义加法 ceres::LocalParameterization 是ceres自带的类, 自定义加法要自己写一个 PoseLocalParameterization 类继承它

ceres::LocalParameterization*local_parameterization=

                                   new PoseLocalParameterization();//自己写PoseLocalParameterization

vins 是在 pose_local_parameterization.h 这个文件里 定义了这个类

classPoseLocalParameterization : publicceres::LocalParameterization

{

virtualboolPlus(constdouble*x, constdouble*delta, double*x_plus_delta) const;// 自定义加法

virtualboolComputeJacobian(constdouble*x, double*jacobian) const;// 计算雅克比

virtualintGlobalSize() const { return 7; };//变量的维数

virtualintLocalSize() const { return 6; };//优化的维数

};

在 pose_local_parameterization.cpp 实现了 plus() 和 ComputeJacobian()

bool PoseLocalParameterization::Plus(const double*x, const double*delta, double*x_plus_delta) const

{
 
Eigen::Map<const Eigen::Vector3d>_p(x); // 把double 数组 映射(Map)成vector 能更方便的使用eigen x是指针 3d 自动取三维

Eigen::Map<const Eigen::Quaterniond>_q(x+3);

Eigen::Map<const Eigen::Vector3d> dp(delta);

Eigen::Quaterniond dq=Utility::deltaQ(Eigen::Map<constEigen::Vector3d>(delta+3)); // 旋转向量映射成四元数

Eigen::Map<Eigen::Vector3d>p(x_plus_delta);

Eigen::Map<Eigen::Quaterniond>q(x_plus_delta+3);

p=_p+dp;

q= (_q*dq).normalized();// 四元数乘法 (重载了*) , 归一化

return true;

}

bool PoseLocalParameterization::ComputeJacobian(constdouble*x, double*jacobian) const

{

Eigen::Map<Eigen::Matrix<double, 7, 6, Eigen::RowMajor>>j(jacobian);

j.topRows<6>().setIdentity();

j.bottomRows<1>().setZero();

return true;

}

4 添加残差

有两种形式

// 需要提供三种参数 —— cost_function对象、鲁棒核函数对象、 该残差的关联参数 。

problem.AddResidualBlock( cost_function对象、
                            鲁棒核函数对象、
                            该残差的关联参数。)

​

//1
template<typename... Ts>
ResidualBlockIdAddResidualBlock(CostFunction*cost_function,
                            LossFunction*loss_function,
                            double*x0,// 依次传入所有参数的指针double*<double*>
                            Ts*... xs)

​

//2
ResidualBlockIdAddResidualBlock(
                                CostFunction*cost_function,
                                LossFunction*loss_function,
                                conststd::vector<double*>&parameter_blocks); //**一次性传入所有参数的指针容器vector<double*>

vins 中 imu 为例 , 采用的 // 2

// AddResidualBlock 参数 : cost function, loss function(核函数)NULL 表示不使用, 相关的参数块
problem.AddResidualBlock(imu_factor, NULL, para_Pose[i], para_SpeedBias[i], para_Pose[j], para_SpeedBias[j]);

!!! CostFunction* cost_function

这个需要定义残差的计算方式, 如果是解析求导,还要给出雅克比的计算方式

这里的使用了仿函数的技巧,即在CostFunction结构体内,对()进行重载,这样的话,该结构体的一个实例就能具有类似一个函数的性质,在代码编写过程中就能当做一个函数一样来使用。

需要自己定义一个结构体或者类, 如果知道 残差维数, 就继承SizedCostFunction, 例如imu 视觉重投影, 如果不知到 维数, 例如路标, 就继承CostFunction

如果使用解析求导, 必须重载Evaluate() 函数, 所以类里面定义了这个函数,分块计算了雅克比矩阵

/ 在vins里后端解析求导, cost_function定义成类, 命名都是 xxx_factor

例如 imu : 在imu_factor .h 文件里定义了这个类

class IMUFactor : public ceres::SizedCostFunction<15, 7, 9, 7, 9> 
//残差维度15 (位姿)7  (速度 ba bg) 9  两帧 7 9 7 9

应用:

IMUFactor* imu_factor = new IMUFactor(pre_integrations[j]);// cost function
 // AddResidualBlock 参数 :           cost function,   loss function(核函数),    相关的参数块
problem.AddResidualBlock(imu_factor, NULL, para_Pose[i], para_SpeedBias[i], para_Pose[j], para_SpeedBias[j]);

/ 初始化自动求导 , cost_function 定义为结构体

如果想使用ceres 的自动求导, 必须定义一个类或者结构体, 需要重载()同时还要使用模板

例如重投影 , 定义ReprojectionError3D结构体

struct ReprojectionError3D  // 结构体
{
    // 构造函数
	ReprojectionError3D(double observed_u, double observed_v)
		:observed_u(observed_u), observed_v(observed_v) {}

	//重载()同时还要使用模板
	template <typename T>
	bool operator()(const T* const camera_R, const T* const camera_T, const T* point, T* residuals) const 	{ ...略... }
	
	// Create 函数
	static ceres::CostFunction* Create(const double observed_x, const double observed_y) 	{ ...略... }

	// 成员变量
	double observed_u;
	double observed_v;
};

应用:

ceres::CostFunction* cost_function = ReprojectionError3D::Create(
												sfm_f[i].observation[j].second.x(), // 特征点在这个图像帧的归一化坐标
												sfm_f[i].observation[j].second.y());
			// 添加残差块
    		problem.AddResidualBlock(cost_function, NULL, // 没有使用核函数
									c_rotation[l], c_translation[l],  sfm_f[i].position);	 // 约束了这一帧的位姿和3d地图点

5 配置求解

ceres::Solver::Optionsoptions;
options.linear_solver_type=ceres::DENSE_SCHUR;//稠密
//options.num_threads = 2;
options.trust_region_strategy_type=ceres::DOGLEG; // dog-leg
options.max_num_iterations=NUM_ITERATIONS;//8
//options.use_explicit_schur_complement = true;
//options.minimizer_progress_to_stdout = true;
//options.use_nonmonotonic_steps = true;

ceres::Solver::Summarysummary;//优化信息
ceres::Solve(options, &problem, &summary); // 求解, 求解的结果仍然放在double数组里面
//cout << summary.BriefReport() << endl;

vins示例(部分)

voidEstimator::optimization()

{

//------------------------------ 1 -------------------------------声明和 引入鲁棒核函数

ceres::Problemproblem;
ceres::LossFunction*loss_function;// 核函数
//loss_function = new ceres::HuberLoss(1.0);
loss_function=newceres::CauchyLoss(1.0);//柯西

//------------------------------2 -------------------------------- 添加ceres参数块 AddParameterBlock

//各种待优化量X——2.1 位姿优化量, 速度bias
//因为ceres用的是double数组,所以在下面用 vector2double 里初始化的,做类型装换
//Ps、Rs转变成 para_Pose, Vs、Bas、Bgs转变成 para_SpeedBias
for(int i=0; i<WINDOW_SIZE+1; i++)//还包括最新的第11帧
{
// !位姿需要自己定义加法 local_parameterization
ceres::LocalParameterization*local_parameterization=newPoseLocalParameterization();
problem.AddParameterBlock(para_Pose[i], SIZE_POSE, local_parameterization); // 参数: 指针,大小, 自定义的加法
problem.AddParameterBlock(para_SpeedBias[i], SIZE_SPEEDBIAS);//优化变量V Ba Bg SIZE_SPEEDBIAS=9
}

//添加各种待优化量X——2.2 相机外参
//ESTIMATE_EXTRINSIC!=0 则camera到IMU的外参 也添加到估计
for (inti=0; i<NUM_OF_CAM; i++)// 单目只有1个
{
// 也是位姿, 也需要单独定义,不过是和pose 一样的
ceres::LocalParameterization*local_parameterization=newPoseLocalParameterization();
problem.AddParameterBlock(para_Ex_Pose[i], SIZE_POSE, local_parameterization);//2.3 优化变量 外参
​

// eigen -> double 把状态转成double数组交给ceres进行优化
vector2double(); //给 ParameterBlock 赋值

​

//-- ---------------------------------- 3 -------------------------添加各种残差 AddResidualBlock

//3.2 添加各种残差——IMU残差 11个窗口有9个imu约束
for (inti=0; i<WINDOW_SIZE; i++)// 0-9 10个
{
intj=i+1;// 1-10 10个
if (pre_integrations[j]->sum_dt>10.0)// 预积分时间太长就不可信了
continue;
IMUFactor*imu_factor=newIMUFactor(pre_integrations[j]);// cost function
// AddResidualBlock 参数 : cost function, loss function(核函数), 相关的参数块
problem.AddResidualBlock(imu_factor, NULL, para_Pose[i], para_SpeedBias[i], para_Pose[j], para_SpeedBias[j]);

}


//------------------------------------4 ------------------------- 非线性优化 求解

ceres::Solver::Optionsoptions;
options.linear_solver_type=ceres::DENSE_SCHUR;//稠密
//options.num_threads = 2;
options.trust_region_strategy_type=ceres::DOGLEG; // dog-leg
options.max_num_iterations=NUM_ITERATIONS;//8
//options.use_explicit_schur_complement = true;
//options.minimizer_progress_to_stdout = true;
//options.use_nonmonotonic_steps = true;

ceres::Solver::Summarysummary;优化信息
ceres::Solve(options, &problem, &summary); // 求解, 求解的结果仍然放在double数组里面
//cout << summary.BriefReport() << endl;

//-- 把 double数组变回vector 同时 防止优化结果在零空间变化,通过固定第一帧的位姿
double2vector();

​



//! 第二部分 边缘化处理 这一部分,只边缘化,不求解,求解留给下一轮优化的第一部分来进行

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ceres小结 -- vins为例 的相关文章

  • VINS-MONO运行(运行VINS-Mono没有轨迹的原因)

    VINS MONO下载及编译 与github中 https github com HKUST Aerial Robotics VINS Mono的一致 下载VINS MONO文件 cd catkin ws src git clone htt
  • Ceres 详解(一) Problem类

    引言 Ceres 是由Google开发的开源C 43 43 通用非线性优化库 xff08 项目主页 xff09 xff0c 与g2o并列为目前视觉SLAM中应用最广泛的优化算法库 xff08 VINS Mono中的大部分优化工作均基于Cer
  • VINS - Fusion GPS/VIO 融合 二、数据融合

    https zhuanlan zhihu com p 75492883 一 简介 源代码 xff1a VINS Fusion 数据集 xff1a KITTI 数据 程序入口 xff1a globalOptNode cpp 二 程序解读 2
  • 树莓派4B(ubuntu mate系统)使用d435i运行vins

    树莓派4B xff08 ubuntu mate系统 xff09 使用d435i运行vins 提示本文为随手笔记 xff0c 并不严谨 xff0c 可参考 xff1a 博客和博客进行配置 树莓派 ubuntu mate 20系统安装ros的步
  • 【SLAM】VINS-MONO解析——前端

    各个部分的讲解如下链接 xff1a SLAM VINS MONO解析 综述 SLAM VINS MONO解析 feature tracker SLAM VINS MONO解析 IMU预积分 SLAM VINS MONO解析 vins est
  • 【SLAM】VINS-MONO解析——sliding window

    8 sliding window 8 1 理论基础 实际上 xff0c 这一部分跟后端非线性优化是一起进行的 xff0c 这一部分对应的非线性优化的损失函数的先验部分 理论基础部分的代码基本在第7章部分 8 1 1 上一次非线性优化结束 x
  • 【学习SLAM】vins笔记

    VINS ROS source catkin ws devel setup bash 3 1 1 Open three terminals launch the vins estimator rviz and play the bag fi
  • VINS-Mono 加rgbd

    通过对比VINS Mono与其RGBD版本 xff0c 分析其改动思路 一 feature tracker feature tracker node cpp 头文件加入了ros的多传感器时间戳 include lt message filt
  • realsense435i运行vins-mono,标定部分

    相机标定 1 安装kalibr xff1b 参考 xff1a https blog csdn net wangbaodong070411209 article details 112248834 https blog csdn net we
  • vins中imu融合_VINS代码解读

    VINS estimator 摘抄 我们初始化的原因是单目惯性紧耦合系统是一个非线性程度很高的系统 xff0c 首先单目是无法获得空间中的绝对尺度 xff0c 而IMU又必然存在偏置 xff0c 在后面进行求解的时候还需要用到重力加速度 包
  • VINS-Mono跑Kitti数据集

    参考文章 xff1a VINS Mono KITT00 测试 知乎 如何在kitti raw data上跑起vins mono 知乎 实际上我参考的是LIO SAM里将KITTI转化为bag的方法 Debug https blog csdn
  • vins位姿图优化

    我们 的滑动窗口和边缘化方案限制了计算的复杂性 xff0c 但也给系统带来了累积漂移 更确切地说 xff0c 漂移发生在全局三维位置 x y z 和围绕重力方向的旋转 yaw 为了消除漂移 xff0c 提出了一种与单目VIO无缝集成的紧耦合
  • TX2上布置vins_fusion_gpu指南

    1 参考链接 如果初次安装 xff0c 新的TX2环境 xff0c 请参考文档 https github com arjunskumar vins fusion gpu tx2 nano 2 问题记录 1 xff0c 自己的环境情况 我的环
  • RealSenseD435i (四):运行 VINS-mono代码

    一 必读博客 nbsp https blog csdn net hltt3838 article details 120691764 nbsp nbsp nbsp 一 https blog csdn net hltt3838 article
  • VINS记录

    euroc launch lt launch gt lt arg name 61 34 config path 34 default 61 34 find feature tracker config euroc euroc config
  • VINS-Mono视觉初始化代码详解

    摘要 视觉初始化的过程是至关重要的 xff0c 如果在刚开始不能给出很好的位姿态估计 xff0c 那么也就不能对IMU的参数进行精确的标定 这里就体现了多传感器融合的思想 xff0c 当一个传感器的数据具有不确定性的时候 xff0c 我们需
  • VINS-Mono代码阅读笔记(十三):posegraph中四自由度位姿优化

    本篇笔记紧接着VINS Mono代码阅读笔记 xff08 十二 xff09 xff1a 将关键帧加入位姿图当中 xff0c 来学习pose graph当中的紧耦合优化部分 在重定位完成之后 xff0c 进行位姿图优化是为了将已经产生的所有位
  • D435i运行VINS-mono以及Kalib标定

    D435i运行VINS mono以及Kalib标定 系统说明 xff1a Ubuntu 18 04 内核版本 xff1a 5 4 0 1 运行VINS mono 参考博客VINS xff08 D435i xff09 测试 问题 xff1a
  • 运行相机与vins_Fusion

    安装相机的SDK git clone https github com slightech MYNT EYE D SDK git cd MYNT EYE D SDK make init make all 这里由于没有添加依赖 xff0c O
  • VINS-Mono代码解读——视觉跟踪 feature_trackers

    前言 本文主要介绍VINS的视觉处理前端的视觉跟踪模块 xff08 feature trackers xff09 论文第四章A节 xff08 IV MEASUREMENT PREPROCESSING A Vision Processing

随机推荐

  • 【JavaWeb】el表达式与jstl标签的使用

    el表达式与jstl标签的使用 el表达式 简介 el表达式的全称 xff1a Expression Language 是表达式语言 EL表达式的作用 xff1a EL表达式主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出 因
  • 【Java】说说Java的线程池

    说说Java的线程池 文章目录 说说Java的线程池为什么要使用线程池ThreadPoolExecutor提供的构造方法解析 线程池处理流程 为什么要使用线程池 创建 销毁线程需要消耗系统资源 xff0c 线程池可以复用已创建的线程控制并发
  • 【Java】Java的类加载器和双亲委派模型

    文章目录 类加载器双亲委派模型 类加载器 对于任意一个类 xff0c 都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性 xff0c 每一个类加载器 xff0c 都有一个独立的类名称空间 比较两个类是否 34 相等
  • 【git】说说git的基础命令

    git的基础命令 命令名称作用git config global user name 用户名设置用户签名git config global user email 邮箱设置用户签名git init初始化本地库git status查看本地库状态
  • 【maven】maven基础知识入门

    maven 文章目录 maven什么是maven为什么使用maven项目构建过程的几个主要环节maven核心概念如何通过坐标到仓库中查找jar包 什么是maven Maven 是 Apache 软件基金会组织维护的一款自动化构建工具 xff
  • 【spring】说说spring的IOC与DI

    说说spring的IOC与DI 文章目录 说说spring的IOC与DIid属性和name属性标签scope Bean的作用范围Spring xff0c 配置生成Bean的三种方式Sping 的 Bean属性注入Sping的Bean属性通过
  • ffmpeg时间戳相关函数

    1 概述 ffmpeg中与时间戳相关的函数主要有 xff1a av rescale q xff0c av rescale q rnd xff0c av compare ts av rescale q span class token cla
  • 【计算机网络】网线规格的鉴别与接线方法

    网线规格的鉴别与接线发送 文章目录 网线规格的鉴别与接线发送一 怎么判断网线类型 xff1f 二 制作网线标准三 屏蔽类型四 使用场景五 米数标记接线方法 一 怎么判断网线类型 xff1f 可以根据网线外皮的标识来判断 xff0c 正规厂商
  • 【Java】说说spring-jdbc和spring事务管理

    文章目录 说说spring jdbc和spring事务管理spring jdbc1 配置数据源2 使用jdbcTemplete3 在dao层使用jdbcTemplete 外部配置方式新建配置文件jdbc properties修改数据源配置部
  • 【微服务】springcloud-dubbo,springCloudAlibaba服务调用使用dubbo

    springcloud dubbo xff0c springCloudAlibaba服务调用使用dubbo 文章目录 springcloud dubbo xff0c springCloudAlibaba服务调用使用dubbo添加依赖配置具体
  • 【项目实战】spring boot中使用webSocket

    spring boot中使用webSocket 文章目录 spring boot中使用webSocket引入依赖支持配置类接口类前端连接方式前端信息发送方式 引入依赖 需要在基础的spring boot web项目项目中添加下面一个依赖 x
  • 【项目复盘】springboot项目中使用mybatis-plus进行分页

    springboot项目中使用mybatis plus进行分页 文章目录 springboot项目中使用mybatis plus进行分页引入依赖配置类实体类持久层业务层 引入依赖 span class token generics span
  • 【项目复盘】javax.validation的简单使用

    javax validation的简单使用 javax validation需要与hibernate validator配合使用 validation bean 是基于JSR 303标准开发出来的 xff0c 使用注解方式实现 xff0c
  • 【项目复盘】springboot中使用swagger生成接口文档并配置bootstrap主题

    springboot中使用swagger生成接口文档并配置bootstrap主题 引入依赖 span class token generics span class token punctuation lt span dependency
  • 【项目复盘】微服务网关GateWay过滤

    微服务网管过滤 新建一个过滤类 span class token annotation punctuation 64 Component span span class token comment 过滤器的执行优先级 返回值越小 执行优先级
  • 【项目实战】Winodws下使用ELK搭建日志分析框架

    项目实战 Winodws下使用ELK搭建日志分析框架 ELK是什么 xff1a 引用官网的一句话 xff1a 核心产品包括 Elasticsearch Kibana Beats 和 Logstash xff08 也称为 ELK Stack
  • java_网络编程知识

    day11 网络编程 主要内容 软件架构CS xff0f BS网络通信三要素TCP通信Socket套接字ServerSocket 学习目标 能够辨别UDP和TCP协议特点 能够说出TCP协议下两个常用类名称 能够编写TCP协议下字符串数据传
  • AvFrame和AvPacket

    在FFmpeg中 未压缩的图像和压缩的视频码流分别使用AVFrame结构和AVPacket结构保存 针对视频编码器 其流程为从数据源获取图像格式的输入数据 保存为AVFrame对象并传入编码器 从编码器输出AVPacket结构 1 AVFr
  • 基于FreeRTOS的stm32程序初始化底层搭建(hal库)

    采用嵌入式实时操作系统 RTOS 可以更合理 更有效地利用CPU的资源 xff0c 简化应用软件的设计 xff0c 缩短系统开发时间 xff0c 更好地保证系统的实时性和可靠性 FreeRTOS是一个迷你的实时操作系统内核 作为一个轻量级的
  • ceres小结 -- vins为例

    从 typora 复制的 排版有问题 见谅 在estimator cpp文件里 这个函数 void Estimator optimization 1 声明problem ceres Problem problem 2 引入核函数loss f