视觉里程计1 高翔

2023-05-16

小白(我)本着学习,提高自我,增加知识的想法,决定认真分析高翔博士slam。在此立下一个flag:

  • 每周进行知识总结(CSDN);
  • 每周要有一个计划
  • 决定一年时间入门vslam。
    我也不知道要说什么了,总之就是这个意思吧,“不荒废自己,撸起袖子加油干,做出成绩来”。废话不说了。

视觉里程计1

特征点法

特征点是由关键点和描述子两部分组成,关键点是指该特征点在图像里面的位置,描述子通常是一个向量,描述了该关键点周围像素的信息。到目前为止ORB特征则是目前非常具有代表性的实时图像特征。

ORB特征由关键点和描述子两部分组成,因此提取ORB特征分为两个步骤:
1、FAST角点提取;2、BRIEF描述子。
FAST角点不具有方向性和尺度的弱点,ORB添加了尺度和旋转的描述。尺度不变性由构建图像金字塔,并在金字塔的每一层上检测角点来实现。而特征的旋转是由灰度质心法实现的。

特征匹配解决了SLAM中的数据关联问题,即确定当前看到的路标与之前看到的路标之间的对应关系。

汉明距离:表示了两个特征之间的相似程度。

实践:特征提取和匹配(代码详解)

#include <iostream>
//core模块包含了OpenCV库的基础结构以及基本操作
#include <opencv2/core/core.hpp>
//features2d包含了用于检测,描述以及匹配特征点的算法
#include <opencv2/features2d/features2d.hpp>
//highgui模块包含可以用来显示图像或者简单的输入的用户交互函数
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main(int argc, char ** argv) {
//argc :表示可执行程序输入参数的个数,argv:表示输入参数的字符串名称
//argc为1时,argv[0]是程序本身(默认的)
    if(argc != 3)
    {
        cout << "usage: feture_ectraction img1 img2" << endl;
        return 1;
    }
    //-- 读取图像
    Mat img_1 = imread(argv[1],CV_LOAD_IMAGE_COLOR);
    Mat img_2 = imread(argv[2],CV_LOAD_IMAGE_COLOR);

    //--初始化(为什么要定义以下变量,请查看detect()函数和compute()函数)
    std::vector<KeyPoint> keypoints_1, keypoints_2;
    Mat descriptors_1,descriptors_2;
    Ptr<ORB> orb = ORB::create();//请查看ORB的构造函数
    //Ptr<ORB> orb = ORB::create(500, 1.2f, 8, 31, 0, 2, ORB::HARRIS_SCORE, 31,20);
    //ORB::create都是默认值

    //--第1步:检测Oriented FAST角点位置(并存储到vector中)
    orb -> detect (img_1, keypoints_1);
    orb -> detect (img_2, keypoints_2);

    //--第2步:根据角点位置计算BRIEF描述子
    orb -> compute(img_1, keypoints_1, descriptors_1);
    orb -> compute(img_2, keypoints_2, descriptors_2);

    Mat outimg1;
    drawKeypoints(img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
    imshow("ORB特征点", outimg1);

    //-- 第3步:对两幅图像中的BRIEF描述子进行匹配,使用汉明距离
    vector<DMatch> matches;
    BFMatcher matcher (NORM_HAMMING);
    matcher.match(descriptors_1, descriptors_2, matches);

    //--第4步:匹配点对筛选
    double min_dist = 10000, max_dist = 0;

    //找出所有匹配之间的最小距离和最大距离,即最相似的和最不相似的两组点之间的距离
    for(int i = 0; i < descriptors_1.rows; i++)
    {
        double dist = matches[i].distance;
        if(dist < min_dist) min_dist = dist;
        if(dist > max_dist) max_dist = dist;
    }
/*
  min_dist = min_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;
  max_dist = max_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;
*/
    cout << "-- Max dist : " << max_dist << endl;
    cout << "-- Min dist : " << min_dist << endl;

    //当描述子之间的距离大于两倍的最小距离时,即认为匹配有误。
    //但有时候最小距离会非常小,设置一个经验值30作为下限。
    vector<DMatch> good_matches;
    for(int i = 0; i < descriptors_1.rows; i++)
    {
        if(matches[i].distance <= max(2*min_dist, 30.0))
        {
            good_matches.push_back(matches[i]);
        }
    }
//注意注意注意:筛选的依据是汉明距离小于最小距离的两倍,这是一种工程上的经验的方法,不一定有理论依据
//尽管在示例图像中能够筛选出正确的匹配,但我们仍然不嫩高保真挂在所有其他图像中得到的匹配都是正确的。
//因此,在后面的运动估计中,还需要使用去除误匹配的算法。
    //--第5步:绘制匹配结果
    Mat img_match;
    Mat img_goodmatch;
    drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_match);
    drawMatches(img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch);
    imshow("所有匹配点对", img_match);
    imshow("优化后匹配点对", img_goodmatch);
    waitKey(0);
    return 0;
}
注意:储存特征描述子的矩阵(descriptors_1,descriptors_2)应该是: 行数表示特征分量,列数表示第几个特征点的特征向量.
cmake_minimum_required(VERSION 3.16)
project(feature2d)

set(CMAKE_CXX_STANDARD 11)

find_package(OpenCV REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(feature2d main.cpp)

target_link_libraries(feature2d ${OpenCV_LIBS})

对极几何

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d_c.h>
#include <cv.hpp>

using namespace std;
using namespace cv;

// 像素坐标转相机归一化坐标
Point2d pixel2cam ( const Point2d& p, const Mat& K );

//两张图像得到关键点(keypoints)和描述子之间匹配关系(matches)
void find_feature_matches(
        const Mat& img_1, const Mat& img_2,
        vector<KeyPoint>& keypoints_1,
        vector<KeyPoint>& keypoints_2,
        vector<DMatch>& matches
        );
//从特征点(keypoints)和匹配关系(matches)求解位姿(R,t)
void pose_estimation_2d2d(
        const vector<KeyPoint> keypoints_1,
        const vector<KeyPoint> keypoints_2,
        const vector<DMatch> matches,
        Mat& R, Mat& t
        );

int main(int argc, char **argv) {
    if(argc != 3){
        cout << "usage: feature_extraction img1 img2" << endl;
        return 1;
    }

    //--读取图像
    Mat img_1 = imread(argv[1],CV_LOAD_IMAGE_COLOR);
    Mat img_2 = imread(argv[2],CV_LOAD_IMAGE_COLOR);

    vector<KeyPoint> keypoints_1, keypoints_2;
    vector<DMatch> matches;
    find_feature_matches(img_1, img_2, keypoints_1, keypoints_2, matches);
    cout << "一共找到了"<< matches.size() << "组匹配点"<< endl;

    //--估计两张图像间的运动
    Mat R, t;
    pose_estimation_2d2d(keypoints_1, keypoints_2, matches, R, t);

    //--验证 E=t^R*scale
    //--计算反对称矩阵
    Mat t_x = (Mat_<double>(3,3)<<
            0,                  -t.at<double>(2, 0),    t.at<double>(1, 0),
            t.at<double>(2, 0),  0,                     -t.at<double>(0, 0),
            -t.at<double>(1, 0), t.at<double>(0, 0),    0);
    cout << "t^R=" << endl << t_x*R << endl;
    //-- 验证对极约束
    Mat K = (Mat_<double> (3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);
    for (DMatch m: matches){
        Point2d pt1 = pixel2cam(keypoints_1[m.queryIdx].pt, K);
        Mat y1 = (Mat_<double>(3, 1) << pt1.x, pt1.y, 1);
        Point2d pt2 = pixel2cam(keypoints_2[m.trainIdx].pt, K);
        Mat y2 = (Mat_<double>(3, 1) << pt2.x, pt2.y, 1);
        Mat d = y2.t() * t_x * R * y1;
        cout << "epipolar constraint = " << d << endl;
    }
    return 0}

void find_feature_matches(
        const Mat& img_1, const Mat& img_2,
        vector<KeyPoint>& keypoints_1,
        vector<KeyPoint>& keypoints_2,
        vector<DMatch>& matches
        ){
    //--初始化
    Mat descriptors_1, descriptors_2;
    Ptr<ORB> orb = ORB::create();

    //-- 第1步:检测Oriented FAST角点位置
    orb -> detect( img_1, keypoints_1);
    orb -> detect( img_2, keypoints_2);

    //-- 第2步:根据角点位置计算BRIEF描述子
    orb -> compute(img_1, keypoints_1, descriptors_1);
    orb -> compute(img_2, keypoints_2, descriptors_2);

    //--第3步:对两幅图像中的BRIEF描述子进行匹配,使用汉明距离
    vector<DMatch> ngmatches;
    BFMatcher matcher(NORM_HAMMING);
    matcher.match(descriptors_1, descriptors_2, ngmatches);

    //--第4步:匹配点对筛选
    double min_dist = 10000, max_dist = 0;

    //找出所有匹配之间的最小距离和最大距离,即最相似的和最不相似的两组点之间的距离
    for (int i = 0; i < descriptors_1.rows; i++){
        double dist = ngmatches[i].distance;
        if ( dist < min_dist ) min_dist = dist;
        if ( dist > max_dist ) max_dist = dist;
    }

    printf("-- Max dist :%f \n", max_dist);
    printf("-- Min dist : %f \n", min_dist);

    for (int i = 0; i < descriptors_1.rows; i++)
    {
        if (ngmatches[i].distance <= max( 2 * min_dist, 30.0))
        {
            matches.push_back(ngmatches[i]);
        }
    }
}

void pose_estimation_2d2d(
        const vector<KeyPoint> keypoints_1,
        const vector<KeyPoint> keypoints_2,
        const vector<DMatch> matches,
        Mat& R, Mat& t
        ){
    // 相机内参, TUM Freiburg2
    Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 249.7, 0, 0, 1);

    //-- 对齐匹配的点对,并用.pt转化为像素坐标。把匹配点转换为简单的Point2f形式,
    vector<Point2f> points1;
    vector<Point2f> points2;

    for (int i = 0; i < (int) matches.size(); i++)
    {
        points1.push_back( keypoints_1[matches[i].queryIdx].pt);//queryIdx第一个图像索引
        points2.push_back( keypoints_2[matches[i].trainIdx].pt);//trainIdx第二个图像索引
    }

    //-- 计算基础矩阵
    Mat fundamental_matrix;
    fundamental_matrix = findFundamentalMat( points1, points2, CV_FM_8POINT);
    cout << "fundamental_matrix is" << endl << fundamental_matrix << endl;

    //-- 计算本质矩阵
    Point2d principal_point(325.1, 249.7);  // 光心,TUM dataset标定值
    int focal_length = 521;                         // 焦距,TUM dataset标定值
    Mat essential_matrix;
    essential_matrix = findEssentialMat(points1, points2, focal_length, principal_point);
    cout << "essential_matrix is " << endl << essential_matrix << endl;

    //--计算单应矩阵
    Mat homography_matrix;
    homography_matrix = findHomography( points1, points2, RANSAC);
    cout << "homography_matrix is " << endl << homography_matrix << endl;

    //-- 从本质矩阵中恢复旋转矩阵和平移信息
    recoverPose(essential_matrix, points1, points2, R, t, focal_length, principal_point);
    cout << "R is " << endl << R << endl;
    cout << "t is " << endl << t << endl;
}
//像素坐标系p到相机坐标系x
Point2d pixel2cam ( const Point2d& p, const Mat& K )
{
    return Point2d
            (
                    ( p.x - K.at<double> ( 0,2 ) ) / K.at<double> ( 0,0 ),
                    ( p.y - K.at<double> ( 1,2 ) ) / K.at<double> ( 1,1 )
            );
}

像素坐标系p到相机坐标系的转换函数
注意:最后得到的坐标是归一化平面上的坐标(位于相机前方z=1出的平面)

在这里插入图片描述在这里插入图片描述

Point2d pixel2cam ( const Point2d& p, const Mat& K )
{
    return Point2d
            (
                    ( p.x - K.at<double> ( 0,2 ) ) / K.at<double> ( 0,0 ),
                    ( p.y - K.at<double> ( 1,2 ) ) / K.at<double> ( 1,1 )
            );
}

findFundamentalMat函数(计算基础矩阵F)

//函数原型

 Mat findFundamentalMat(InputArray points1, InputArray points2, int method = FM_RANSAC, double ransacReprojThreshold = 3., 
 
double confidence = 0.99, OutputArray mask = noArray())
 
  • points1,points2 是匹配点对的像素坐标,并且能够一一对应
  • method 使用那种方法,默认的是FM_RANSAC也就是RANSAC的方法估算基础矩阵。CV_FM_8POINT是8点法。
  • ransacReprojThreshold 表示RANSAC迭代过程中,判断点是内点还是外点的阈值(到对极线的像素距离);
  • confidence 表示内点占的比例,以此来判断估计出的基础矩阵是否正确。

findEssentialMat函数(计算本质矩阵E)

//函数原型

Mat findEssentialMat(InputArray points1, InputArray points2, double focal = 1.0, Point_<double> pp = Point2d(0, 0), 

int method = RANSAC, double prob = 0.999, double threshold = 1.0, OutputArray mask = noArray())
  • focal: 焦距
  • pp: 光心坐标

findHomography函数(计算单应矩阵H)

//函数原型

Mat findHomography(InputArray srcPoints, InputArray dstPoints, int method = 0, double ransacReprojThreshold = 3,

 OutputArray mask = noArray(), const int maxIters = 2000, const double confidence = 0.995)
  • maxIter 最大迭代次数

recoverPose 函数(从本质矩阵中恢复旋转矩阵和平移信息)

int recoverPose(InputArray E, InputArray points1, InputArray points2, OutputArray R, OutputArray t, double focal = 1.0, Point_<double> pp = Point2d(0, 0), InputOutputArray mask = noArray())
  • E: 本质矩阵E
  • 对极几何的实践部分程序比较简单,中规中矩,没有什么特别复杂的地方。

初始换的纯旋转问题

E分解到R,t的过程,如果相机发生的是纯旋转,导致t为零,那么,得到的E也将为零,这将导致我们无法求解R。不过,此时我们可以依靠H求取像旋转,但仅有旋转时,我们无法用三角测量估计特征点的空间位置。
结论:单目初始化不能只有纯旋转,必须要有一定程度的平移。
在实践当中,如果初始换时平移太小,会使得位姿求解与三角化结果不稳定,从而导致失败。相对地,如果把相机左右移动而不是原地旋转,就容易让单目SLAM初始化。

多于8对点的情况

当可能存在误匹配的情况时,更倾向于使用随机采样一致性(Random Sample Concensus, RANSAC)来求,这个方法是一种通用的方法,适用于很多带错误数据的情况,可以处理带有错误匹配的数据。

三角测量

三角测量(高斯提出)是指,通过在两处观察同一个点的夹角,从而确定该点的距离。
三角化的矛盾:增大平移,会导致匹配失效,平移太小,则三角化精度不够

三角测量代码实践部分<triangulation()函数>

void triangulation(
        const vector< KeyPoint > & keypoints_1,
        const vector< KeyPoint > & keypoints_2,
        const vector< DMatch > & matches,
        const Mat & R, const Mat & t,
        vector<Point3d> & points
    ){
    Mat T1 = (Mat_<double> (3,4) <<
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0);//这块表示图1的相机作为参考,变换矩阵中没有相机旋转和平移
    Mat T2 = (Mat_<double> (3, 4) <<
            R.at<double>(0, 0), R.at<double>(0, 1), R.at<double>(0, 2), t.at<double>(0, 0),
            R.at<double>(1, 0), R.at<double>(1, 1), R.at<double>(1, 2), t.at<double>(1, 0),
            R.at<double>(2, 0), R.at<double>(2, 1), R.at<double>(2, 2), t.at<double>(2, 0)
                    );  //T2中传入R,t,即图2相对图1这个参考位置的变换矩阵  
    Mat K = (Mat_<double> (3, 3) <<
            520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);
    vector<Point2d> pts_1, pts_2;
    //图1和图2上的2D图像像素点转换后的归一化相机坐标点,对应的Zc=1,所以只要计算Xc和Yc
    for (DMatch m: matches)
    {
        //--将像素坐标转换至相机坐标
        pts_1.push_back( pixel2cam( keypoints_1[m.queryIdx].pt, K));
        pts_2.push_back( pixel2cam( keypoints_2[m.trainIdx].pt, K));
    }

    Mat pts_4d;
    cv::triangulatePoints( T1, T2, pts_1, pts_2, pts_4d );
    //--传入两个图像对应相机的变化矩阵,各自相机坐标系下归一化相机坐标,输出的3D坐标是齐次坐标,
    //--共四个维度,因此需要将前三个维度除以第四个维度以得到非齐次坐标xyz
    // 转换成非齐次坐标
    for (int i = 0; i < pts_4d.cols; i++) //遍历所有的点,列数表述点的数量
    {
        Mat x = pts_4d.col(i);  //x为4x1维度
        x /= x.at<float>(3 , 0); //归一化
        Point3d p (
                x.at<float> (0, 0),
                x.at<float> (1, 0),
                x.at<float>(2, 0)
                );
        points.push_back( p );//将图1测得的目标相对相机实际位置(Xc,Yc,Zc)存入points
    }
}

3D-2D: PnP

PnP(Perspective-n-Point) 是求解3D到2D点对运动的方法。它描述了当知道n个3D空间点及其投影位置时,如何估计相机的位姿。
如果两张图像中其中一张特征点的3D位置已知,那么最少只需3个点对(需要至少一个额外点验证结果)就可以估计相机运动。特征点的3D位置可以由三角化或者RGB-D相机的深度图确定。因此,在双目或RGB-D的视觉里程计中,我们可以直接使用PnP估计相机运动。而在单目视觉里程计中,必须先进行初始化,然后才能使用PnP。3D-2D方法不要使用对极约束,又可以在很少的匹配点中获得较好的运动估计,是最重要的一种姿态估计方法。
为了求解PnP,我们利用了三角形相似性质,P3P存在的问题:

  • P3P只利用了3个点的信息。当给定的配对点对于3组时,难以利用更多的信息。
  • 如果3D点后2D点受噪声影响,或者存在误匹配,则算法失效

在SLAM当中,通常的做法是先使用P3P/EPnP等方法估计相机位姿,然后构建最小二乘优化问题对估计值进行调整(Bundle Adjustment)。

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

视觉里程计1 高翔 的相关文章

  • NVIDIA Jetson TX2重装系统

    博主所用的Jetson TX2初始环境及相关方面的介绍见前两篇博客 NVIDIA Jetson TX2简介 竹叶青lvye的博客 CSDN博客 nvidiatx2 NVIDIA Jetson官网资料整理 竹叶青lvye的博客 CSDN博客
  • Jetson TX2配置Tensorflow、Pytorch等常用库

    之前在PC Ubuntu或者树莓派上都配置过 方法不变 所以此篇博客会简单记录 下过程 详细的一些方法思路可以去参考博主之前的系列博客 虽然硬件平台不一样 但方法大体一致的 硬件平台主流的有树莓派 NVIDIA Jetson Google的
  • Macbook pro外接显卡实现深度学习

    耗时一整天加一晚上终于成功了安装配置外接GPU并运行深度学习案列 故事的缘由 2017年底鬼使神差的买了个macbook xff0c 放在家里吃了一年灰 xff0c 心想还是要用起来啊 目前主要从事数据挖掘机器学习的工作 xff0c 需要搞
  • Gradle技术之一 Groovy语法精讲

    Gradle技术之一 Groovy语法精讲 gradle脚本是基于groovy语言开发的 xff0c 想要学好gradle必须先要对groovy有一个基本的认识 1 Groovy特点 groovy是一种DSL语言 xff0c 所谓的DSL语
  • 字符串子串的查找

    1 考虑用标准函数库中 strstr 函数 包含文件 xff1a string h 函数名 strstr 函数原型 xff1a extern char strstr char str1 char str2 功能 xff1a 从字符串str1
  • 大锤老湿教您如何配置TP-Link路由器组建wifi上网

    TP Link路由器设置教程 大家好 xff0c 今天由大锤老湿教大家如何设置使用最广的TP Link路由器 一般家庭都希望能上wifi 那么首先看看我们如何将新买回的或者由于故障已经恢复成重置出厂状态的路由器 xff0c 如何经过重新设置
  • 【ESP01S】使用串口调试助手,发送AT指令收回的是乱码/重复一遍AT指令发回的问题

    调试帮助 span class token punctuation span 技术交流Q xff1a span class token number 1083091092 span xff08 备注CSDN xff09 一 问题描述 在使用
  • 刷leetcode使用python还是c++?

    我身边80 的程序员朋友在刷题的时候会选择Java xff0c 很少有人用C 43 43 来刷题 这两门语言各有特点 xff1a C 43 43 xff1a 从C语言发展过来的一门语言 xff0c 继承了灵活 xff08 可以潜入任何现代的
  • VINS-Mono代码精简版代码详解-后端非线性优化(三)

    非线性优化部分代码解析 之前已经对VINS Mono的初始化部分进行了介绍 xff0c 下面结合代码和公式介绍其非线性优化部分 本文部分参考 https blog csdn net u012871872 article details 78
  • Ubuntu IO占用过多导致文件读取变慢的原因查找方法

    问题描述 xff1a 多用户服务器 xff0c ubuntu系统 xff0c 突然点开文件夹 xff0c 发现变慢 查看方法 xff1a step1 xff1a 进入管理员用户 step2 xff1a 运行iostat x 1 在显示的结果
  • ROS Docker

    Docker 常用指令 docker pull osrf ros galactic desktop 从网络上下载镜像 docker images 查看已加载镜像列表 window docker界面 xff1a 命令行结果 xff1a doc
  • Win10C盘文件夹内容详解(持续更新,欢迎留言)

    本文参考以下博客 Roaming和Local的区别 C Users 用户名 AppData 1 Local和Roaming之间的区别 xff1a Local 比较大 xff0c 非漫游应用数据 Roaming 一般是漫游应用数据 2 Roa
  • STM32运行FreeRTOS

    使用ARM Keil 的 Keil uVision IDE xff0c 在 STM32上运行 FreeRTOS 内核 物料清单 软件 在创建新项目之前 xff0c 我们必须安装软件包 下面是打印屏幕 xff0c 其中包含如何执行此操作的步骤
  • ESP32实践FreeRTOS

    将部分代码作为应用程序中的任务独立执行可以简化大型复杂问题的设计 当有多个 CPU 时 xff0c 任务支持还允许选定的功能并行运行 本文将调查 Arduino 框架对 ESP32 系列设备的 FreeRTOS 任务支持 除了少数例外 xf
  • 黑马程序员—5—Java基础:多态学习笔记和学习心得体会

    lt ahref 61 34 http www itheima com 34 target 61 34 blank 34 gt android 培训 lt a gt lt ahref 61 34 http www itheima com 3
  • 图像去噪算法简介

    一 xff0c 背景 随着各种数字仪器和数码产品的普及 xff0c 图像和视频已成为人类活动中最常用的信息载体 xff0c 它们包含着物体的大量信息 xff0c 成为人们获取外界原始信息的主要途径 然而在图像的获取 传输和存贮过程中常常会受
  • Android 7 Nougat 源码目录结构

    code style margin 0px auto font family none padding 0px color inherit background color transparent art Android Runtime x

随机推荐

  • 【无人驾驶规划】BOSS无人车规划算法

    无人驾驶规划 BOSS无人车规划算法 1 boss运动规划结构2 轨迹生成2 1 状态约束2 2 车辆模型2 3 控制参数化2 4 初始化轨迹2 5 轨迹优化 3 on road模式规划3 1 路径生成3 2 轨迹生成3 3 轨迹速度配置3
  • 这也太全面了 阿里王牌级“Docker全线笔记”,Github已标星80k+,我太爱

    写在开头 司汤达说过 xff1a 一个人只要强烈地坚持不懈地追求 xff0c 他就能达到目的 Docker的创始人Solomon Hykes就是以这样的精神 xff0c 在docker即将坚持不下去的时候 xff0c 选择的不是放弃 xff
  • 如何在keil5中新建.c和.h文件?

    有两种方法 xff1a 方法1 在keil5内部添加两个文件分别为 c和 h文件 xff0c 可以保存在一个新建的文件夹里 xff08 前提是此文件夹是在keil5内部保存时新建的文件夹 xff0c 而不是在keil5软件外自己新建的文件夹
  • CMake(十二):构建类型

    本章和下一章涉及两个密切相关的主题 构建类型 在某些IDE工具中也称为构建配置或构建方案 是一种高级控件 xff0c 它选择不同的编译器和链接器行为集 构建类型的操作是本章的主题 xff0c 而下一章将介绍控制编译器和链接器选项的更具体细节
  • CMake:构建、链接静态库和动态库

    CMake 构建 链接静态库和动态库 导言一 多目录多文件CMake构建方式1 项目结构2 message h3 message cpp4 hello world cpp5 CMakeLists txt6 构建及编译 二 静态库和动态库简介
  • msckf_mono构建运行方法

    背景 博主是在读Davide Scaramuzza投稿到ICRA 2018的VIO综述文章 A Benchmark Comparison of Monocular Visual Odometry Algorithms for Flying
  • IMU相关技术资料整理

    关于IMU噪声参数 xff1a IMU噪声参数模型的参考文档 xff1a https github com ethz asl kalibr wiki IMU Noise Model针对消费级IMU器件的噪声参数进行适度的不确定性放大 xff
  • Shell中空格引起的血案

    最近开始写点shell脚本 xff0c 对linux命令还是比较熟悉的 xff0c 但是shell脚本却没写过 xff0c 没想 xff0c 刚开始写 xff0c 就郁闷重重 各种语法错误 xff01 xff01 xff01 最简单的自定义
  • OpenCV-Python视频分析(移动物体检测,物体追踪)

    1 概述 该文章介绍OpenCV Python中关于视频分析的两个主要内容 xff0c 分别为 xff1a x1f41f 背景差分法移动物体检测 x1f41f Meanshift和Camshift算法物体追踪 PS xff1a 视频分析还要
  • 最新2014欢聚时代(YY)软件研发笔试题

    今天上午刚考完 C C 43 43 题目难度你们感受一下 xff01 总分80 43 60 61 140 题目上的答案请忽略
  • python 计算经纬度之间的距离

    def get distance lon1 lat1 lon2 lat2 lon1 lat1 lon2 lat2 61 map radians lon1 lat1 lon2 lat2 radians 角度转弧度 d lon 61 lon2
  • python多线程爬虫教学,清晰易懂。

    首先需要知道什么是多线程 xff0c 多线程的作用 首先举个例子 xff0c 并发和并行 xff1a 并发 xff1a 并发 xff0c 在操作系统中 xff0c 是指一个时间段中有几个程序都处于已启动运行到运行完毕之间 xff0c 且这几
  • Matlab 读取txt文本中的数据

    使用matlab读取txt文本中的数据 数据最好有一定的规律 我们可以使用函数importdata来导入数据 下面使用一个例子来说明该函数的使用 start path C 设置默认文件夹 filename pathname uigetfil
  • 2018-07-25-github-如何在Github上面创建Release

    github release 看别的Github项目都有一条类似timeline 时间线 的版本列表 xff0c 如下图 xff0c 所以在Github上面摸索了一下 xff0c 弄好了记录一下 创建一个Release TestBefore
  • SSH登录卡在‘Last login‘提示界面的一种原因

    以前解决过SSH登录卡顿的问题 xff0c 它一般来源于 xff1a GSSAPIAuthentication UseDNS 以上设置项被默认打开或意外打开 而这次遇到的问题不是卡顿 xff0c 而是卡在 Last login xff0c
  • 【云原生之Docker实战】使用Docker部署openwrt软路由

    云原生之Docker实战 使用Docker部署openwrt软路由 一 openwrt介绍 二 检查本地docker状态 1 查看docker版本 2 查看docker信息 3 查看本地docker网络 三 安装docker compose
  • 值得收藏:图解算法——动态规划系列

    个人博客导航页 xff08 点击右侧链接即可打开个人博客 xff09 xff1a 大牛带你入门技术栈 小浩 xff1a 宜信科技中心攻城狮一枚 xff0c 热爱算法 xff0c 热爱学习 xff0c 不拘泥于枯燥编程代码 xff0c 更喜欢
  • TensorFlow之循环神经网络&自然语言处理 学习总结

    作者 xff1a jliang https blog csdn net jliang3 junliang 20190303 说明 xff1a 以下所有代码使用版本TensorFlow1 4 0或1 12 0版本 import tensorf
  • Docker镜像容器的迁移问题

    本文是本人项目踩坑经验 xff0c 如有错漏请见谅 xff01 背景需求 xff1a 一个已经配置好的容器 xff08 无build文件 xff09 需要部署到生产环境中 xff0c 容器内有程序绑定了宿主环境的硬件信息 需求部署后能让第三
  • 视觉里程计1 高翔

    小白 xff08 我 xff09 本着学习 xff0c 提高自我 xff0c 增加知识的想法 xff0c 决定认真分析高翔博士slam 在此立下一个flag xff1a 每周进行知识总结 xff08 CSDN xff09 xff1b 每周要