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

2023-05-16

 其实还有一个Ceres库可以进行优化,但是之前的博客已经具体分析了,所以这里就对其余两个进行了介绍,相关的内容是SLAM14讲里面的知识

 

一、理论部分

我们先用一个简单的例子来说明如何求解最小二乘问题,然后展示如何手写高斯牛顿法和优化库求解此问题

高斯牛顿法

 

g2o曲线拟合

g2o (General Graphic Optimization G 2 O )。它是一个基于 图优化 的库。图优化是一种将非线性优化与图论结合起来的理论,因此在使用它之前,我们花一点篇幅介绍一个图优化理论。
图优化理论简介 我们已经介绍了非线性最小二乘的求解方式。它们是由很多个误差项之和组成的。然 而,仅有一组优化变量和许多个误差项,我们并不清楚它们之间的关联 。比方说,某一个 优化变量 x j 存在于多少个误差项里呢?我们能保证对它的优化是有意义的吗?进一步,我 们希望能够直观地看到该优化问题长什么样 。于是,就说到了图优化。 图优化,是把优化问题表现成图( Graph 的一种方式。这里的 是图论意义上的图。 一个图由若干个顶点( Vertex ,以及连接着这些节点的 边( Edge 组成。进而,用 顶点 表示优化变量 ,用 表示 误差项。于是,对任意一个上述形式的非线性最小二乘问题,我们可以构建与之对应的一个
 

6-2 是一个简单的图优化例子。我们用三角形表示相机位姿节点,用圆形表示路标 点,它们构成了图优化的顶点;同时,蓝色线表示相机的运动模型,红色虚线表示观测模 型,它们构成了图优化的边。此时,虽然整个问题的数学形式仍是式(6.12 )那样,但现在 我们可以直观地看到问题的结构 了。如果我们希望,也可以做 去掉孤立顶点 优先优化边 数较多(或按图论的术语,度数较大)的顶点这样的改进。但是最基本的图优化,是用图 模型来表达一个非线性最小二乘的优化问题。而我们可以利用图模型的某些性质,做更好 的优化。 g2o 为 SLAM 提供了图优化所需的内容。下面我们来演示一下 g2o 的使用方法。
 

g2o 的编译与安装

在使用一个库之前,我们需要对它进行编译和安装。读者应该已经体验很多次这个过 程了,它们基本都是大同小异的。关于 g2o ,读者可以从 github 下载它: https://github. com/RainerKuemmerle/g2o,或从本书提供的第三方代码库中获得。
解压代码包后,你会看到 g2o 库的所有源码,它也是一个 CMake 工程。我们先来安 装它的依赖项(部分依赖项与 Ceres 有重合):
sudo apt-get install libqt4-dev qt4-qmake libqglviewer-dev libsuitesparse-dev libcxsparse3.1.2
libcholmod-dev
然后,按照 cmake 的方式对 g2o 进行编译安装即可,我们略去该过程的说明。安装完 成后,g2o 的头文件将在 /usr/local/g2o 下,库文件在 /usr/local/lib/ 下。现在,我们重新 考虑 Ceres 例程中的曲线拟合实验,在 g2o 中实验一遍。
 
 

使用 g2o 拟合曲线

为了使用 g2o ,首先要做的是将曲线拟合问题抽象成图优化。这个过程中,只要记住节点为优化变量,边为误差项即可。因此,曲线拟合的图优化问题可以画成图 6-3 的形式。
 
 
在曲线拟合问题中,整个问题只有一个顶点:曲线模型的参数 a, b, c ;而每个带噪声的数据点,构成了一个个误差项,也就是图优化的边。但这里的边与我们平时想的边不太一样,它们是一元边 Unary Edge ),即 只连接一个顶点 ——因为我们整个图只有一个顶点。 所以在图 6-3 中,我们就只能把它画成自己连到自己的样子了。事实上,图优化中一条边可以连接一个、两个或多个顶点,这主要反映在每个误差与多少个优化变量有关。在稍微有些玄妙的说法中,我们把它叫做超边 Hyper Edge ),整个图叫做 超图 Hyper Graph ) ①。弄清了这个图模型之后,接下来就是在 g2o 中建立该模型,进行优化了。作为 g2o 的 用户,我们要做的事主要有以下几个步骤:
1. 定义顶点和边的类型;
2. 构建图;
3. 选择优化算法;
4. 调用 g2o 进行优化,返回结果。
 
 

二、实践部分

2.1 手写高斯牛顿法

#include <iostream>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int main(int argc, char **argv) {
  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;                                 // OpenCV随机数产生器

  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 * w_sigma));
  }

  // 开始Gauss-Newton迭代
  int iterations = 100;    // 迭代次数
  double cost = 0, lastCost = 0;  // 本次迭代的cost和上一次迭代的cost

  chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
  for (int iter = 0; iter < iterations; iter++) {

    Matrix3d H = Matrix3d::Zero();             // Hessian = J^T W^{-1} J in Gauss-Newton
    Vector3d b = Vector3d::Zero();             // bias
    cost = 0;

    for (int i = 0; i < N; i++) {
      double xi = x_data[i], yi = y_data[i];  // 第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);
    if (isnan(dx[0])) {
      cout << "result is nan!" << endl;
      break;
    }

    if (iter > 0 && cost >= lastCost) {
      cout << "cost: " << cost << ">= last cost: " << lastCost << ", break." << endl;
      break;
    }

    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;
  return 0;
}

其结果如下,经过多次迭代,曲线拟合趋于收敛的状态!

2.2 使用g2o进行曲线拟合

#include <iostream>
#include <g2o/core/g2o_core_api.h>
#include <g2o/core/base_vertex.h>
#include <g2o/core/base_unary_edge.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/optimization_algorithm_gauss_newton.h>
#include <g2o/core/optimization_algorithm_dogleg.h>
#include <g2o/solvers/dense/linear_solver_dense.h>
#include <Eigen/Core>
#include <opencv2/core/core.hpp>
#include <cmath>
#include <chrono>

using namespace std;

// 曲线模型的顶点,模板参数:优化变量维度和数据类型
class CurveFittingVertex : public g2o::BaseVertex<3, Eigen::Vector3d> {
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW

  // 重置
  virtual void setToOriginImpl() override {
    _estimate << 0, 0, 0;
  }

  // 更新
  virtual void oplusImpl(const double *update) override {
    _estimate += Eigen::Vector3d(update);
  }

  // 存盘和读盘:留空
  virtual bool read(istream &in) {}

  virtual bool write(ostream &out) const {}
};

// 误差模型 模板参数:观测值维度,类型,连接顶点类型
class CurveFittingEdge : public g2o::BaseUnaryEdge<1, double, CurveFittingVertex> {
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW

  CurveFittingEdge(double x) : BaseUnaryEdge(), _x(x) {}

  // 计算曲线模型误差
  virtual void computeError() override {
    const CurveFittingVertex *v = static_cast<const CurveFittingVertex *> (_vertices[0]);
    const Eigen::Vector3d abc = v->estimate();
    _error(0, 0) = _measurement - std::exp(abc(0, 0) * _x * _x + abc(1, 0) * _x + abc(2, 0));
  }

  // 计算雅可比矩阵
  virtual void linearizeOplus() override {
    const CurveFittingVertex *v = static_cast<const CurveFittingVertex *> (_vertices[0]);
    const Eigen::Vector3d abc = v->estimate();
    double y = exp(abc[0] * _x * _x + abc[1] * _x + abc[2]);
    _jacobianOplusXi[0] = -_x * _x * y;
    _jacobianOplusXi[1] = -_x * y;
    _jacobianOplusXi[2] = -y;
  }

  virtual bool read(istream &in) {}

  virtual bool write(ostream &out) const {}

public:
  double _x;  // x 值, y 值为 _measurement
};

int main(int argc, char **argv) {
  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;                                 // OpenCV随机数产生器

  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 * w_sigma));
  }

  // 构建图优化,先设定g2o
  typedef g2o::BlockSolver<g2o::BlockSolverTraits<3, 1>> BlockSolverType;  // 每个误差项优化变量维度为3,误差值维度为1
  typedef g2o::LinearSolverDense<BlockSolverType::PoseMatrixType> LinearSolverType; // 线性求解器类型

  // 梯度下降方法,可以从GN, LM, DogLeg 中选
  auto solver = new g2o::OptimizationAlgorithmGaussNewton(
    g2o::make_unique<BlockSolverType>(g2o::make_unique<LinearSolverType>()));
  g2o::SparseOptimizer optimizer;     // 图模型
  optimizer.setAlgorithm(solver);   // 设置求解器
  optimizer.setVerbose(true);       // 打开调试输出

  // 往图中增加顶点
  CurveFittingVertex *v = new CurveFittingVertex();
  v->setEstimate(Eigen::Vector3d(ae, be, ce));
  v->setId(0);
  optimizer.addVertex(v);

  // 往图中增加边
  for (int i = 0; i < N; i++) {
    CurveFittingEdge *edge = new CurveFittingEdge(x_data[i]);
    edge->setId(i);
    edge->setVertex(0, v);                // 设置连接的顶点
    edge->setMeasurement(y_data[i]);      // 观测数值
    edge->setInformation(Eigen::Matrix<double, 1, 1>::Identity() * 1 / (w_sigma * w_sigma)); // 信息矩阵:协方差矩阵之逆
    optimizer.addEdge(edge);
  }

  // 执行优化
  cout << "start optimization" << endl;
  chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
  optimizer.initializeOptimization();
  optimizer.optimize(10);
  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;

  // 输出优化值
  Eigen::Vector3d abc_estimate = v->estimate();
  cout << "estimated model: " << abc_estimate.transpose() << endl;

  return 0;
}
在这个程序中,我们从 g2o 派生出了用于曲线拟合的图优化顶点和边: CurveFittingVertex 和 CurveFittingEdge ,这实质上是扩展了 g2o 的使用方式。在这两个派生类 中,我们重写了重要的虚函数:
1. 顶点的更新函数:oplusImpl
我们知道优化过程最重要的是增量 x 的计算,而该 函数处理的是 x k +1 = x k + ∆ x 的过程。
读者会觉得这并不是什么值得一提的事情,因为仅仅是个简单的加法而已,为什么 g2o 不帮我们完成呢?在曲线拟合过程中,由于优化变量(曲线参数)本身位于向量 空间中,这个更新计算确实就是简单的加法。但是,当优化变量不处于向量空间中时,
比方说 x 是相机位姿,它本身不一定有加法运算。这时,就需要重新定义 增量如何加到现有的估计上的行为了。按照第四讲的解释,我们可能使用左乘更新或右乘更新,而不是直接的加法。
2. 顶点的重置函数: setToOriginImpl 。这是平凡的,我们把估计值置零即可。
3. 边的误差计算函数: computeError 。该函数需要取出边所连接的顶点的当前估计值, 根据曲线模型,与它的观测值进行比较。这和最小二乘问题中的误差模型是一致的。
4. 存盘和读盘函数: read, write 。由于我们并不想进行读写操作,就留空了。 定义了顶点和边之后,我们在 main 函数里声明了一个图模型,然后按照生成的噪声数据,往图模型中添加顶点和边,最后调用优化函数进行优化。g2o 会给出优化的结果:

三、小结

本节介绍了 SLAM 中经常碰到的一种非线性优化问题:由许多个误差项平方和组成的最小二乘问题。我们介绍了它的定义和求解,并且讨论了两种主要的梯度下降方式:GaussNewton 和 Levenberg-Marquardt 。在实践部分中,我们分别使用了 Ceres g2o 两种优化库求解同一个曲线拟合问题,发现它们给出了相似的结果。 由于我们还没有详细谈 Bundle Adjustment ,所以实践部分选择了曲线拟合这样一个 简单但有代表性的例子,以演示一般的非线性最小二乘求解方式。特别地,如果用 g2o 来拟合曲线,我们必须先把问题转换为图优化,定义新的顶点和边,这种做法是有一些迂回的——g2o 的主要目的并不在此。相比之下,Ceres 定义误差项,求曲线拟合问题则自然了很多,因为它本身即是一个优化库。然而,在 SLAM 中,更多的问题是,一个带有许多个相机位姿和许多个空间点的优化问题如何求解。特别地,当相机位姿以李代数表示时,误差项关于相机位姿的导数如何计算,将是一件值得详细讨论的事。我们将在后续的章节中发现,g2o 提供了大量的顶点和边的类型,使得它在相机位姿估计问题中非常方便。而在Ceres 中,我们不得不自己实现每一个 Cost Function,带来了一些不便。在实践部分的两个程序中,我们没有去计算曲线模型关于三个参数的导数,而是利用了优化库的数值求导,这使得理论和代码都会简洁一些。Ceres 库提供了基于模板元的自动求导和运行时的数值求导,而 g2o 只提供了运行时数值求导这一种方式。但是,对于大多数问题,如果我们能够推导出雅可比矩阵的解析形式并告诉优化库,就可以避免数值求导中的诸多问题。最后,希望读者能够适应 Ceres 和 g2o 这些大量使用模板编程的方式。也许一开始会看上去比较吓人(特别是 Ceres 设置 Problem 和 g2o 初始化部分的代码),但是一旦熟悉
之后,就会觉得这样的方式是自然的,而且容易扩展。我们将在 SLAM 后端章节中,继续 讨论稀疏性、核函数、位姿图(Pose Graph )等问题。

 

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

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

  • C++ opencv曲线拟合

    简介 xff1a 此问题是在做旋转模板匹配的时候 xff0c 选择最好的匹配结果时产生的 查找资料发现多项式拟合问题可以变成一个超定方程的求解问题 xff0c 而opencv中本身有一个cv solve 函数可以求解线性方程组 xff0c
  • g2o中的核函数

    文章目录 g2o中的核函数RobustKernelHuber函数 g2o中的核函数 作用限制误差较大的edge对最终优化结果的影响 RobustKernelHuber函数 g2o中的class名称 xff1a class RobustKer
  • SLAM本质剖析-G2O(转载,感觉写得不错)

    这块还是写得不错的 转载自 xff1a https mp weixin qq com s NeveBIh5bb37CUyVVNocLw SLAM本质剖析 G2O 原创 lovely yoshino 古月居 今天 0 前言 在了解SLAM的原
  • ceres-solver和g2o性能比较

    前言 ceres solver 和 g2o 是slam领域常见的优化器 xff0c 其中ceres solver被vins mono使用 xff0c 而g2o被orb slam3使用 xff0c 因此到底哪个优化器更适合于在slam算法开发
  • g2o学习

    g2o学习参考资料 1 深入理解图优化与g2o xff1a 图优化篇 https www cnblogs com gaoxiang12 p 5244828 html https www cnblogs com gaoxiang12 p 53
  • 曲线拟合-最小二乘法

    线性最小二乘法及matlab例程 线性最小二乘法 曲线拟合 xff1a 已知平面上一组横坐标互不相同的点 xff0c 寻求一个函数 xff0c 使其与所有数据点最为接近 拟合函数 xff1a f x 61
  • G2o,GTSAM,Ceres,Tensorflow优化器的方法比较

    首先是一些背景知识 xff1a 最速梯度下降法 xff08 GD xff09 和牛顿法可以用来优化所有种类的函数 牛顿高斯和基于牛顿高斯的LM法只能用来优化非线性最小二乘 SGD是最速梯度下降法的改进 xff0c 也就是每次迭代随即选取一些
  • 非线性优化库学习资料:Ceres Gtsam G2o

    其中 Ceres 资料最完善也相对稳定 xff0c 是谷歌的非线性优化库 xff0c Google Cartographer 就是调用了该库 http www ceres solver org tutorial html 既可以作为 Cer
  • 【Python】python曲线拟合

    python作为一款可以简单方便地进行科学计算的语言 xff0c 进行曲线拟合自然是必备的功能之一了 本文就如何进行曲线拟合进行讲解 本文需要进行拟合的数据为 xff1a x 61 np arange 1 31 1 y 61 np arra
  • java中类的main方法总结

    一 java中每个类都需要有main方法吗 xff1f 每个类可以有也可以没有main方法 xff0c 甚至所有类里可以都没有main方法 如果你想从某个类做为入口开始运行整个程序 那么就把他设成 public xff0c 之后再里面写个m
  • g2o非线性优化架构详解图

    流程 xff1a 1 每次添加边的时候 xff0c 会对jacobian workspace更新size xff0c 最终size等于所有边中顶点相关顶点数量最多的顶点数 xff1b 这样做的原因是所有边求解雅克比矩阵 xff0c 用的是同
  • G2O优化

    G2O优化 0 引言0 1 参考0 1 G2O的解决问题0 2 G2O整体框架 1 基本使用1 1 构造 g2o 模型1 2 g2o 类图 2 g2o 的顶点 xff08 Vertex xff09 2 1 顶点的格式2 2 自定义顶点2 3
  • graph slam tutorial : g2o 的使用

    g2o全称general graph optimization xff0c 是一个用来优化非线性误差函数的c 43 43 框架 如果阅读了前几篇graph slam tutorial的博客 xff0c 再去读 g2o xff1a a gen
  • 非线性优化 (曲线拟合) 问题:高斯牛顿、g2o 方法总结

    其实还有一个Ceres库可以进行优化 xff0c 但是之前的博客已经具体分析了 xff0c 所以这里就对其余两个进行了介绍 xff0c 相关的内容是SLAM14讲里面的知识 一 理论部分 我们先用一个简单的例子来说明如何求解最小二乘问题 x
  • G2O库和Eigen库can not find 问题——FindG2O.cmake FindEigen3.cmake

    目录 CMakeLists设置FindG2O cmake文件内容FindEigen3 cmake 文件内容 CMakeLists设置 在CMakeLists里加入如下这句话 xff0c 并在项目文件夹中新建cmake文件夹 LIST APP
  • 曲线拟合

    问题解决 给你一个二维的序列 你如何用多项式进行曲线拟合 一阶直线拟合 二阶抛物线拟合 并非阶次越高越好 看拟合情况而定 曲线拟合 clear clc syms s 声明一个符号变量 详细参考 https jingyan baidu com
  • 最小二乘曲线拟合——C语言算法实现一

    最小二乘曲线拟合 给定一组数据 我们要对这组数据进行曲线拟合 假定要拟合的曲线方程为 y a0 a1 x 1 a2 x 2 a3 x 3 an x n x y 0 995119 7 620000 2 001185 2 460000 2 99
  • 做SLAM实验时g2o的安装问题cmake的版本问题及git下载历史版本代码方法总结

    博主之前跑了ORBSLAM2做了相关实验 半年没碰之后 又重新来弄发现 WTF g2o用不了 cmake版本过低无法编译 直接修改CMakeLists txt文件还不行 好吧 我屈服了 升级cmake吧 升级到了3 2爽歪歪腰不酸了腿也利索
  • matlab曲线拟合

    曲线拟合不要求逼近函数通过各采样点 但要求尽量的接近这些点 使误差在某种意义上达到最小 一 利用函数的方式实现曲线拟合 在matlab中 用polyfit函数来求得最小二乘拟合多项式的系数 再用polyval函数按所得的多项式计算所给点上的
  • IDEA中设置网络代理

    需求 在IDEA中使用Database插件连接数据库时提示我需要安装插件依赖的数据库驱动 大家注意不要把这个数据库驱动和你的项目pom文件中导入的数据库驱动搞混了 不是一回事 选择下载后会自动去maven中央仓库下载 下载很慢很慢 而且好几

随机推荐

  • 使用Zoundry在CSDN发布Blog

    安装一个Zoundry吧 xff0c 用这个来离线写Blog xff0c 再也不怕突然断线和丢失文章了 Zoundry是用Python实现的一个离线撰写Blog工具 支持Community Servedr blogger com Wordp
  • Python中Array的常用操作(二)数组基本操作

    1 数组操作 x代表数组中的元素 xff0c i代表位置 a append x 把元素x添加到数组的尾部 b insert i x 把元素x 插入到位置i c remove x 删除第一个元素x d pop i 删除第i个元素 xff0c
  • Python中Array的常用操作(三)数组高级操作

    1 抽取数组中不重复的数据 gt gt gt a 61 x 2 for x in range 1 5 2 gt gt gt uniq 61 list set a 8 2 4 6 gt gt gt uniq 61 sorted set a 2
  • 2011年,移动互联网加速蔓延 – 来自2011移动开发者大会

    2011移动开发者大会 xff0c 这是第二届移动开发者大会了 xff0c 这一年来移动互联网各个领域蔓延开来 xff0c 蔓延这个词是开复老师演讲的主题 从事塞班开发的请举手 xff0c 举手者寥寥 记得在去年移动开发者大会上 xff0c
  • main函数之前做了什么?

    main函数之前 真正的函数执行入口或开始 一种解释 实际上 xff0c 在可执行文件被加载之后 xff0c 控制权立即交给由编译器插入的Start函数 xff0c 它将对后面这些全局变量进行准备 xff1a osver 操作系统的构件编号
  • detecron2中的注册机制

    文章目录 一 为什么使用注册类二 注册类的实现 传送门 Detectron2 01 注册机制 Registry 实现 一 为什么使用注册类 以下转自知乎 https zhuanlan zhihu com p 93835858 对于detec
  • 单目视觉SLAM在无人机上的应用

    目录 写在前面 本文说明 论文链接和实验视频 源代码链接 一 实验环境 硬件 软件 算法 二 实验环境搭建过程 1 Intel NUC安装Ubuntu 16 04 2 安装ROS D435i驱动以及ORB SLAM2算法 3 ORB SLA
  • TypeError: Expected cv::UMat for argument ‘img‘

    研究Detectron2中的在线数据增强的源码 并显示数据增强后的图像时 xff0c 遇到 TypeError Expected cv UMat for argument 39 img 的问题 显然 xff0c 问题要求是输入一个uint8
  • Linux 桌面终于迎来了 Docker Desktop

    Docker 桌面是容器化应用程序的最简单方法 无需考虑在你选择的系统上设置环境即可开始使用 只需要安装 Docker 桌面 xff0c 就可以开始了 Docker 桌面应用程序附带容器工具 xff0c 如 Kubernetes Docke
  • Dockerfile制作镜像和常用Shell脚本语法记录

    一 常规命令和使用记录 1 定义变量 判断匹配 赋值等 定义变量 addr 61 a namespace 61 b 判断匹配自定义的 包括参数化构建设置的变量 环境变量 xff0c 并赋值 case 34 Env 34 in dev nam
  • [Holo_wo]-vscode常用配置项说明

    vscode 配置文件核心 settings json xff1a 整个vscode的配置 xff0c 是本地vscode的配置 xff0c 如果有ssh远程 xff0c 那么会在远程主机的 vscode server目录下有setting
  • 基于jQuery的ajax跨域请求,PHP作为服务器端代码

    ajax实现跨域请求有两种方式 xff1a 方法一 xff1a jsonp的方式 jsonp方式的关键点在客户请求以jsonp作为数据类型 xff0c 服务器端接收jsonp的回调函数 xff0c 并通过回调函数进行数据的传输 具体代码如下
  • 无人机位置信息计算无人机的瞬时速度的matlab仿真

    目录 1 算法描述 2 仿真效果预览 3 MATLAB核心程序 4 完整MATLAB 1 算法描述 无人机最早在20世纪20年代出现 xff0c 1914年第一次世界大战正进行得如火如荼 xff0c 英国的卡德尔和皮切尔两位将军 xff0c
  • 基于simulink的无人机姿态飞行控制仿真

    目录 1 算法描述 2 仿真效果预览 3 MATLAB核心程序 4 完整MATLAB 1 算法描述 无人机是无人驾驶飞机的简称 xff08 Unmanned Aerial Vehicle xff09 xff0c 是利用无线电遥控设备和自备的
  • 基于ADRC自抗扰控制器的simulink仿真,ESO和TD等模块使用S函数开发

    目录 1 算法仿真效果 2 MATLAB核心程序 3 算法涉及理论知识概要 4 完整MATLAB 1 算法仿真效果 matlab2022a仿真结果如下 xff1a 2 MATLAB核心程序 function sys x0 str ts 61
  • m基于模糊控制与遗传优化的自适应ADRC双闭环控制策略matlab仿真

    目录 1 算法仿真效果 2 MATLAB核心程序 3 算法涉及理论知识概要 4 完整MATLAB 1 算法仿真效果 matlab2013b仿真结果如下 xff1a 遗传优化的优化迭代过程仿真图 xff1a 这个是我们采用的优化算法的有过过程
  • VINS-mono在Ubuntu20.04上从零开始安装运行和环境配置(尝试)

    最近尝试在Ubuntu 20 04上安装运行港科大的VINS mono算法 详细记录一下安装过程以及遇到的问题 先记录一下结果 ROS opencv Eigen Ceres以及VINS mono都编译并安装成功了 但是用euroc数据集跑V
  • 数据结构-C++实现

    之前的2周一直在学数据结构 xff0c 头都大了 我是之前对数据结构一点认识都没有 xff0c 我是直接看书怼的 xff0c 我看的是 大话数据结构 xff0c 前面的讲解还不错 xff0c 到了树 图后 xff0c 就有点看不懂了 xff
  • 几款好看的css表格

    表格一 xff1a 代码 xff1a html代码段 xff1a 是用vs写的 表头 lt th gt 那是从数据库读取的数据段 lt td gt 那是我为测试效果加的代码 xff0c 大家可以自行更改 lt h1 gt 待处理订单 lt
  • 非线性优化 (曲线拟合) 问题:高斯牛顿、g2o 方法总结

    其实还有一个Ceres库可以进行优化 xff0c 但是之前的博客已经具体分析了 xff0c 所以这里就对其余两个进行了介绍 xff0c 相关的内容是SLAM14讲里面的知识 一 理论部分 我们先用一个简单的例子来说明如何求解最小二乘问题 x