第二讲:双目vio视觉前端以及后端重投影残差

2023-05-16

双目vio视觉前端以及后端重投影残差(vins双目)

本次主要讲解vio双目系统的视觉前端部分和后端融合的重投影残差部分,以vins切入做为分析,并赋代码注释解析。
主要包含以下五部分内容 
 1)双目特征点提取;
 2)特征点光流跟踪;
 3)特征点三角化;
 4)pnp求解相机帧间运动;
 5)后端优化之视觉特征点重投影残差Bundle Adjustment(BA)

1. 特征提取

1.1 左右目时间对齐

imu回调函数:void imu_callback(const sensor_msgs::ImuConstPtr &imu_msg);
将收到的数据存储到相应的buffer中,accBuf, gyrBuf

图像回调函数:
void img0_callback(const sensor_msgs::ImageConstPtr &img_msg)->左目
void img1_callback(const sensor_msgs::ImageConstPtr &img_msg)->左目

时间对齐后存储图像数据

特征点id 相机id
map<int, vector<pair<int, Eigen::Matrix<double, 7, 1>>>> featureFrame;

其中Matrix<double, 7, 1> 7个数据分别代表:
归一化坐标:x, y, z(z=1)
像素坐标:p_u, p_v
帧间像素移动速度: velocity_x, velocity_y;

1.2 特征点检测

通过调用opencv库函数进行角点检测cv::goodFeaturesToTrack(),并保证每一帧图像有150(150是可调参数)个特征点,当光流跟踪少于150个,就会运行该函数提取特征补充到150个。
cv::goodFeaturesToTrack(),它不仅支持Harris角点检测,也支持Shi Tomasi算法的角点检测。但是,该函数检测到的角点依然是像素级别的,若想获取更为精细的角点坐标,则需要调用cv::cornerSubPix()函数进一步细化处理,即亚像素。

	void cv::goodFeaturesToTrack(
		cv::InputArray image, // 输入图像(CV_8UC1 CV_32FC1)
		cv::OutputArray corners, // 输出角点vector
		int maxCorners, // 最大角点数目
		double qualityLevel, // 质量水平系数(小于1.0的正数,一般在0.01-0.1之间)
		double minDistance, // 最小距离,小于此距离的点忽略
		cv::InputArray mask = noArray(), // mask=0的点忽略
		int blockSize = 3, // 使用的邻域数
		bool useHarrisDetector = false, // false ='Shi Tomasi metric'
		double k = 0.04 // Harris角点检测时使用
	);

2. 特征点光流跟踪

函数:featureFrame = featureTracker.trackImage(t, _img, _img1);

2.1 光流跟踪

光流跟踪:
光流法主要用于寻找不同图片间的特征点对应关系,表示每个像素在相邻帧间相对位置的位移向量。Lucas-Kanade 稀疏光流法只依赖于围绕关键点的小窗口推断出的局部信息。这导致了Lucas-Kanade算法不能检测到物体的快速运动到窗口外部的点。这个缺点可以通过改进的金字塔LK光流法解决。
vins中使用金字塔LK光流法:由于像素运动过大可能导致不满足光流法的窗口假设,无法跟踪到对应的特征点,所以采用光流金字塔:
在这里插入图片描述
第0层为原始图像,每一层向上对图像像素宽高缩小两倍,呈金字塔形状。首先计算最高层的光流大小,做为初始值计算次高层的光流大小…以此类推到原始图像即可。

cv::calcOpticalFlowPyrLK(prev_img, cur_img, prev_pts, cur_pts, status, err, cv::Size(21, 21), 1, 
            cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 30, 0.01), cv::OPTFLOW_USE_INITIAL_FLOW);	

vins中Level=1,表示使用两层金字塔。

2.2 vins中对应特征点提取跟踪代码流程解析

1)首先时间对齐后从 image_buffer 图像取出,重新分布亮度来来改变图像对比度(只适用于灰度图像)。这样能更好的检测出角点。

    // 自适应直方图均衡(CLAHE)
    {
        cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0, cv::Size(16, 16));
        clahe->apply(cur_img, cur_img);
        if(!rightImg.empty())
            clahe->apply(rightImg, rightImg);
    }

2)在第一帧图像的情况下:
首先对左目图像提取150个特征点,并存储特征点到cur_pts中:
在mask值为0处不进行角点检测,所以第一次设置图像mask并没有起作用。

cv::goodFeaturesToTrack(cur_img, n_pts, MAX_CNT - cur_pts.size(), 0.01, MIN_DIST, mask);//且在mask值为0处不进行角点检测。

接下来对检测出来的角点进行去畸变并求出像素运动速度(第一帧速度为0):

cur_un_pts = undistortedPts(cur_pts, m_camera[0]);//去畸变
pts_velocity = ptsVelocity(ids, cur_un_pts, cur_un_pts_map, prev_un_pts_map);//计算像素速度

右目对左目的图像进行光流跟踪,并存储特征点到cur_right_pts中:

cv::calcOpticalFlowPyrLK(cur_img, rightImg, cur_pts, cur_right_pts, status, err, cv::Size(21, 21), 3);

然后使用反向光流跟踪,即左目再跟踪右目的特征点,如果两次跟踪特征点均存在,则得以保留,否则将在cur_pts,cur_right_pts中删除掉。

最后将特征点保存到数据结构中map<int, vector<pair<int, Eigen::Matrix<double, 7, 1>>>> featureFrame;

3)在不是第一帧图像的情况下:
在这里插入图片描述首先进行前后两帧特征点跟踪(针对左目,右目前后两帧不需要),并且进行反向光流跟踪。

cv::calcOpticalFlowPyrLK(prev_img, cur_img, prev_pts, cur_pts, status, err, cv::Size(21, 21), 3);
        // reverse check
        if(FLOW_BACK)
        {
            vector<uchar> reverse_status;
            vector<cv::Point2f> reverse_pts = prev_pts;
            cv::calcOpticalFlowPyrLK(cur_img, prev_img, cur_pts, reverse_pts, reverse_status, err, cv::Size(21, 21), 1, 
            cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, 30, 0.01), cv::OPTFLOW_USE_INITIAL_FLOW);
            //cv::calcOpticalFlowPyrLK(cur_img, prev_img, cur_pts, reverse_pts, reverse_status, err, cv::Size(21, 21), 3); 
            for(size_t i = 0; i < status.size(); i++)
            {
                if(status[i] && reverse_status[i] && distance(prev_pts[i], reverse_pts[i]) <= 0.5)
                {
                    status[i] = 1;
                }
                else
                    status[i] = 0;
            }
        }

当跟踪到的特征点数特征点少于设定值时,进行特征点检测补充到特定值:
根据第一帧图像设置的掩模(mask),在特征点黑色区域内不再进行特征点重复检测,不仅提高算法执行速度,而且能够使得特征点尽量均匀分布。

if(inputImageCnt % 2 == 0)
        {
            mBuf.lock();
            featureBuf.push(make_pair(t, featureFrame));
            mBuf.unlock();
        }
queue<pair<double, map<int, vector<pair<int, Eigen::Matrix<double, 7, 1> > > > > > featureBuf;

最后将提取的特征点,放到 featureBuf 中;
结构体从左到右分别是时间戳,特征点id,相机id,
Matrix<double, 7, 1>是归一化坐标,像素坐标,归一化坐标系下像素运动速度。
在这里插入图片描述

3. 特征点三角化

之所以把三角化放在前面,是因为相机第一帧的位置由imu初始化得到,并且后续的帧间pnp算法恢复帧间运动需要用到特征点在 world 系的位置,所以当第一帧图像来的时候可以根据左右目的特征跟踪,来三角化特征点。当之后的特征点被多帧图像跟踪到时,采用最小二乘进行三角化。

在vins中,并没有采用相似原理去获得特征点深度,使用方法如下:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述注意:代码中的T是代表 world 系到 camera 系,所以需要取逆。
对应代码如下:

void FeatureManager::triangulatePoint(Eigen::Matrix<double, 3, 4> &Pose0, Eigen::Matrix<double, 3, 4> &Pose1,
                        Eigen::Vector2d &point0, Eigen::Vector2d &point1, Eigen::Vector3d &point_3d)
{
    Eigen::Matrix4d design_matrix = Eigen::Matrix4d::Zero();
    design_matrix.row(0) = point0[0] * Pose0.row(2) - Pose0.row(0);
    design_matrix.row(1) = point0[1] * Pose0.row(2) - Pose0.row(1);
    design_matrix.row(2) = point1[0] * Pose1.row(2) - Pose1.row(0);
    design_matrix.row(3) = point1[1] * Pose1.row(2) - Pose1.row(1);
    Eigen::Vector4d triangulated_point;
    triangulated_point =
              design_matrix.jacobiSvd(Eigen::ComputeFullV).matrixV().rightCols<1>();
    point_3d(0) = triangulated_point(0) / triangulated_point(3);
    point_3d(1) = triangulated_point(1) / triangulated_point(3);
    point_3d(2) = triangulated_point(2) / triangulated_point(3);
}

最后通过svd求解。

当右目没有跟踪到左目的特征点时,此时需要前后两帧之间进行三角化,原理同上。

代码中还有一部分冗余,当特征点跟踪次数大于4时,此时三角化方程为超定方程,使用超定方程 最小二乘解 奇异值分解(SVD)求解。不会执行这里。

4. PNP求解相机帧间运动

这里不再阐述pnp具体算法原理,其原理类似于重投影BA的过程,证明方法可参考视觉slam 14 讲P.157
代码中调用opencv函数进行求解:

cv::solvePnP(pts3D, pts2D, K, D, rvec, t, 1);

注意参数的使用,尤其是rvec和t的使用,都是从world系到cam系,参考。。。

5. 视觉重投影残差(属于后端优化部分)

在这里插入图片描述视觉特征点重投影残差Bundle Adjustment(BA)原理:
在相机归一化平面上,将残差定义为:E = 特征点在当前帧中光流跟踪的归一化坐标 - 特征点的在该帧的重投影归一化坐标。
在这里插入图片描述Jacobian矩阵为视觉残差对两个时刻的状态变量,imu 和 camera 外参,以及逆深度求导;
使用链式求导法则,如下:
在这里插入图片描述
Jacobian 矩阵的具体形式略,可以参照vins代码自行推导;
重投影的残差需要区分图像是否为第一帧;
1)当图像为第一帧时,需要左右目做重投影残差;

bool ProjectionOneFrameTwoCamFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
{
    TicToc tic_toc;

    Eigen::Vector3d tic(parameters[0][0], parameters[0][1], parameters[0][2]);
    Eigen::Quaterniond qic(parameters[0][6], parameters[0][3], parameters[0][4], parameters[0][5]);

    Eigen::Vector3d tic2(parameters[1][0], parameters[1][1], parameters[1][2]);
    Eigen::Quaterniond qic2(parameters[1][6], parameters[1][3], parameters[1][4], parameters[1][5]);

    double inv_dep_i = parameters[2][0];

    double td = parameters[3][0];

    Eigen::Vector3d pts_i_td, pts_j_td;
    pts_i_td = pts_i - (td - td_i) * velocity_i;
    pts_j_td = pts_j - (td - td_j) * velocity_j;

    Eigen::Vector3d pts_camera_i = pts_i_td / inv_dep_i;
    Eigen::Vector3d pts_imu_i = qic * pts_camera_i + tic;
    Eigen::Vector3d pts_imu_j = pts_imu_i;
    Eigen::Vector3d pts_camera_j = qic2.inverse() * (pts_imu_j - tic2);
    Eigen::Map<Eigen::Vector2d> residual(residuals);

    double dep_j = pts_camera_j.z();
    residual = (pts_camera_j / dep_j).head<2>() - pts_j_td.head<2>();

    residual = sqrt_info * residual;

    if (jacobians)
    {
        Eigen::Matrix3d ric = qic.toRotationMatrix();
        Eigen::Matrix3d ric2 = qic2.toRotationMatrix();
        Eigen::Matrix<double, 2, 3> reduce(2, 3);

        reduce << 1. / dep_j, 0, -pts_camera_j(0) / (dep_j * dep_j),
            0, 1. / dep_j, -pts_camera_j(1) / (dep_j * dep_j);
        reduce = sqrt_info * reduce;

        Eigen::Matrix4d tmp_M = -Eigen::Matrix4d::Identity();
        tmp_M(3, 3) = 1;

        if (jacobians[0])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_ex_pose(jacobians[0]);
            Eigen::Matrix<double, 3, 7> jaco_ex;
            jaco_ex.leftCols<3>() = ric2.transpose(); 
            jaco_ex.rightCols<4>() = ric2.transpose() * Utility::QuaternionDerivation(qic, pts_camera_i);
            jacobian_ex_pose = reduce * jaco_ex;
        }
        if (jacobians[1])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_ex_pose1(jacobians[1]);
            Eigen::Matrix<double, 3, 7> jaco_ex;
            jaco_ex.leftCols<3>() = -ric2.transpose();
            jaco_ex.rightCols<4>() = Utility::QuaternionDerivation(qic2.inverse(), pts_imu_j-tic2) * tmp_M;
            jacobian_ex_pose1 = reduce * jaco_ex;
        }
        if (jacobians[2])
        {
            Eigen::Map<Eigen::Vector2d> jacobian_feature(jacobians[2]);
            jacobian_feature = reduce * ric2.transpose() * ric * pts_i * -1.0 / (inv_dep_i * inv_dep_i);
        }
        if (jacobians[3])
        {
            Eigen::Map<Eigen::Vector2d> jacobian_td(jacobians[3]);
            jacobian_td = reduce * ric2.transpose() * ric * velocity_i / inv_dep_i * -1.0  +
                          sqrt_info * velocity_j.head(2);
        }
    }
    sum_t += tic_toc.toc();

    return true;
}

2)当图像不是第一帧时,需要划窗内特征点 start_frame 和 current_frame 做重投影残差

bool ProjectionTwoFrameTwoCamFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
{
    TicToc tic_toc;
    Eigen::Vector3d Pi(parameters[0][0], parameters[0][1], parameters[0][2]);
    Eigen::Quaterniond Qi(parameters[0][6], parameters[0][3], parameters[0][4], parameters[0][5]);

    Eigen::Vector3d Pj(parameters[1][0], parameters[1][1], parameters[1][2]);
    Eigen::Quaterniond Qj(parameters[1][6], parameters[1][3], parameters[1][4], parameters[1][5]);

    Eigen::Vector3d tic(parameters[2][0], parameters[2][1], parameters[2][2]);
    Eigen::Quaterniond qic(parameters[2][6], parameters[2][3], parameters[2][4], parameters[2][5]);

    Eigen::Vector3d tic2(parameters[3][0], parameters[3][1], parameters[3][2]);
    Eigen::Quaterniond qic2(parameters[3][6], parameters[3][3], parameters[3][4], parameters[3][5]);

    double inv_dep_i = parameters[4][0];

    double td = parameters[5][0];

    Eigen::Vector3d pts_i_td, pts_j_td;
    pts_i_td = pts_i - (td - td_i) * velocity_i;
    pts_j_td = pts_j - (td - td_j) * velocity_j;

    Eigen::Vector3d pts_camera_i = pts_i_td / inv_dep_i;
    Eigen::Vector3d pts_imu_i = qic * pts_camera_i + tic;
    Eigen::Vector3d pts_w = Qi * pts_imu_i + Pi;
    Eigen::Vector3d pts_imu_j = Qj.inverse() * (pts_w - Pj);
    Eigen::Vector3d pts_camera_j = qic2.inverse() * (pts_imu_j - tic2);
    Eigen::Map<Eigen::Vector2d> residual(residuals);

    double dep_j = pts_camera_j.z();
    residual = (pts_camera_j / dep_j).head<2>() - pts_j_td.head<2>();

    residual = sqrt_info * residual;

    if (jacobians)
    {
        Eigen::Matrix3d Ri = Qi.toRotationMatrix();
        Eigen::Matrix3d Rj = Qj.toRotationMatrix();
        Eigen::Matrix3d ric = qic.toRotationMatrix();
        Eigen::Matrix3d ric2 = qic2.toRotationMatrix();
        Eigen::Matrix<double, 2, 3> reduce(2, 3);

        reduce << 1. / dep_j, 0, -pts_camera_j(0) / (dep_j * dep_j),
            0, 1. / dep_j, -pts_camera_j(1) / (dep_j * dep_j);
        reduce = sqrt_info * reduce;

        Eigen::Matrix4d tmp_M = -Eigen::Matrix4d::Identity();
        tmp_M(3, 3) = 1;

        if (jacobians[0])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_pose_i(jacobians[0]);

            Eigen::Matrix<double, 3, 7> jaco_i;
            jaco_i.leftCols<3>() = ric2.transpose() * Rj.transpose();
            jaco_i.rightCols<4>() = ric2.transpose() * Rj.transpose() * Utility::QuaternionDerivation(Qi, pts_imu_i);

            jacobian_pose_i = reduce * jaco_i;
        }

        if (jacobians[1])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_pose_j(jacobians[1]);

            Eigen::Matrix<double, 3, 7> jaco_j;
            jaco_j.leftCols<3>() = ric2.transpose() * -Rj.transpose();
            jaco_j.rightCols<4>() = ric2.transpose() * Utility::QuaternionDerivation(Qj.inverse(), pts_w-Pj) * tmp_M;

            jacobian_pose_j = reduce * jaco_j;
        }
        if (jacobians[2])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_ex_pose(jacobians[2]);
            Eigen::Matrix<double, 3, 7> jaco_ex;
            Eigen::Matrix3d tmp_R = ric2.transpose() * Rj.transpose() * Ri;
            jaco_ex.leftCols<3>() = tmp_R; 
            jaco_ex.rightCols<4>() = tmp_R * Utility::QuaternionDerivation(qic, pts_camera_i);
            jacobian_ex_pose = reduce * jaco_ex;
        }
        if (jacobians[3])
        {
            Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_ex_pose1(jacobians[3]);
            Eigen::Matrix<double, 3, 7> jaco_ex;
            jaco_ex.leftCols<3>() = -ric2.transpose();
            jaco_ex.rightCols<4>() = Utility::QuaternionDerivation(qic2.inverse(), pts_imu_j-tic2) * tmp_M;
            jacobian_ex_pose1 = reduce * jaco_ex;
        }
        if (jacobians[4])
        {
            Eigen::Map<Eigen::Vector2d> jacobian_feature(jacobians[4]);
            jacobian_feature = reduce * ric2.transpose() * Rj.transpose() * Ri * ric * pts_i_td * -1.0 / (inv_dep_i * inv_dep_i);
        }
        if (jacobians[5])
        {
            Eigen::Map<Eigen::Vector2d> jacobian_td(jacobians[5]);
            jacobian_td = reduce * ric2.transpose() * Rj.transpose() * Ri * ric * velocity_i / inv_dep_i * -1.0  +
                          sqrt_info * velocity_j.head(2);
        }
    }
    sum_t += tic_toc.toc();

    return true;
}

使用 ceres 求解即可!

下一讲 VINS 边缘化策略!

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

第二讲:双目vio视觉前端以及后端重投影残差 的相关文章

  • 计算机网络笔记:TCP三次握手和四次挥手过程

    TCP是面向连接的协议 xff0c 连接的建立和释放是每一次面向连接的通信中必不可少的过程 TCP连接的管理就是使连接的建立和释放都能正常地进行 三次握手 TCP连接的建立 三次握手建立TCP连接 若主机A中运行了一个客户进程 xff0c
  • echarts与highcharts学习及区别

    1 echarts用法更广泛 xff0c highcharts更适合特定的某些需求 1 1 echarts和highcharts初始引用 xff0c import as echarts from echarts html要有一个容器 xff
  • 啥是驱动?

    Q amp A 什么是驱动 xff1f 驱动本质上是一个软件程序 xff0c 是内核与硬件之间通信的桥梁 xff0c 为应用程序屏蔽了硬件细节 内核可以通过驱动程序去初始化 释放设备 xff0c 内核可以通过驱动程序与设备做双向的数据交互
  • 基于STM32F1系列的OV7725摄像头初步使用(用于摄像头循迹)

    最近做项目需要用到OV7725 xff0c 于是花了些时间研究 由于OV7725对于工作频率的要求较高 xff0c 因此使用带FIFO的摄像头模块 代码参考自正点原子官方 OV7725资源 引脚说明 以下时关于十八个引脚的说明 xff08
  • CAS SSO单点登录实例

    1 因为是本地模拟sso环境 xff0c 而sso的环境测试需要域名 xff0c 所以需要虚拟几个域名出来 xff0c 步骤如下 xff1a 2 进入目录C Windows System32 drivers etc 3 修改hosts文件
  • Ubuntu屏幕录像软件推荐-Kazam

    由于工作的关系 xff0c 需要经常录制一些软件的操作步骤当做教程 xff0c 现在由于使用了Ubuntu单系统平台 xff0c 以前录制的教程均不能正常运行了 xff0c 需要切换到VM xp里面使用 xff0c 造成很大的不变 xff0
  • 图像畸变矫正——透视变换

    图像畸变矫正 透视变换 由于相机制造精度以及组装工艺的偏差引入的畸变 xff0c 或者由于照片拍摄时的角度 旋转 缩放等问题 xff0c 可能会导致原始图像的失真 xff0c 如果要修复这些失真 xff0c 我们可以通过透视变换 xff0c
  • 微信JSAPI支付,微信浏览器内支付,解决微信H5支付只能在微信外浏览器支付的问题

    一 设置支付目录 请确保实际支付时的请求目录与后台配置的目录一致 xff08 现在已经支持配置根目录 xff0c 配置后有一定的生效时间 xff0c 一般5分钟内生效 xff09 xff0c 否则将无法成功唤起微信支付 在微信商户平台 xf
  • 解决python3 与 ROS中使用python2冲突的问题(亲测有效)

    文章转载于 https zhuanlan zhihu com p 27011617 方法一 xff1a conda install setuptools pip install U rosdep rosinstall generator w
  • Radmin FAQ

    故障排除提示 xff0c 技术指南 xff0c 文章方法 xff0c 反馈表等 通过主机选项连接 1 此选项使您可以在没有与要管理的计算机的直接 TCP IP 连接时通过主机进行连接 xff0c 但中间主机与目标计算机 xff08 网关等
  • 关于相机内参与外参的浅读

    学习人脸3D重建的第一天 xff0c 在首次接触3D相关的内容 xff0c 必须要搞清楚相机的成像原理 xff0c 如何将真实三维空间中的三维点与显示器 屏幕和图像等二维成像的平面映射 xff0c 以及了解该过程的推导方式和相关坐标系的换算
  • 嵌入式以及嵌入式行业的基本信息

    从技术实现上讲 xff0c 嵌入式的产品分为两大类 xff1a 一类简单的 xff0c 没有操作系统支持的 一类复杂的 xff0c 有操作系统的 就目前发展方向看 xff0c 后一种是趋势 前一种从程序实现上可分为3层 xff1a 硬件层
  • Linux i2c_driver probe被调用的流程分析(linux4.1.15)

    linux4 1 15 i2c driver probe被调用流程 span class token operator span span class token operator span span class token comment
  • linux uart 驱动中 open、read、write调用层次

    span class token comment Linux kernel release 2 6 xx span span class token comment linux uart 驱动中接收和发送函数的调用层次 xff0c 记录如下
  • Centos8 制作qcow2及使用

    制作及使用方法如下 xff1a 1 下载ios wget https archive kernel org centos vault 8 2 2004 isos x86 64 CentOS 8 2 2004 x86 64 dvd1 iso
  • 免费的期刊论文文献检索网站(收集整理)

    文献免费下载神器 xff0c 这里放5个可以直接下载SCI等论文网站 以下网站去地址栏直接搜 xff01 1 Sci Hub可谓是无人不知无人不晓 xff0c 其自开发以来 xff0c 便以星火燎原之势席卷学术界 xff0c 因为它可以免费
  • k8s 中 pod 之间的通信

    1 pod 内部通信 xff1a 通过 localhost 通信 2 同节点不同 pod 之间通信 xff1a 通过 linux 虚拟以太网设备或者是用两个虚拟接口组成的以太网接口对不同的网络命名空间连接起来通信 3 不同节点的不同 pod
  • 从零写VIO|第二节——作业:使用Allen方差工具标定IMU

    这里写目录标题 作业内容1 安装im utils1 1 安装依赖 xff1a 1 2 编译1 3 可能出的错误 2 运行 2 1 采集IMU数据 2 2 生成imu bag2 3 新建imu launch文件2 4 播放数据2 5 61 6
  • [VIO|实践]UBUNTU16.04跑MSCKF-双目代码

    编译环境 编译 新建文件夹msckf catkin ws xff0c 里面再建一个叫src的文件夹 xff0c 然后把解压好的代码集msckf放进去 命令行进入到 msckf catkin ws这一层 xff0c 进行catkin make
  • 华为系列设备优先级总结(一)

    现整理一部分华为系列交换机 路由器各项配置优先级 xff0c 欢迎各位朋友收藏备查 xff0c 若有遗漏或者是错误 xff0c 也欢迎在评论区提出交流 本文主要适合具有一定基础的网络工程师查阅参考 xff0c 阅读本文 xff0c 需要对本

随机推荐

  • OSPFv3中LSA详解(一)——概述

    今天给大家详细介绍一下OSPFv3中LSA的变化 xff0c 这也是OSPFv3相对于OSPFv2的一大重要改变 本文将详细介绍OSPFv3中9类LSA相对于OSPFv2中7类LSA的异同 阅读本文 xff0c 您需要有一定的OSPFv2和
  • OSPFv3中LSA详解(五)——Intra-Area-Prefix LSA详解

    今天继续给大家介绍OSPFv3中LSA变化 xff0c LSA的变化时OSPFv3相对于OSPFv2的一大重大改变 xff0c 本文的主要内容是OSPFv3中新增的一类LSA Intra Area Prefix LSA的详解 阅读本文 xf
  • OSPFv3中LSA详解(六)——Type3类LSA详解

    今天继续给大家介绍OSPFv3中LSA变化 xff0c LSA的变化时OSPFv3相对于OSPFv2的一大重大改变 xff0c 本文的主要内容是OSPFv3中变化的第三类LSA的详解 阅读本文 xff0c 您需要有一定的OSPF基础知识 x
  • OSPFv3中LSA详解(七)——Type4类LSA详解

    今天继续给大家介绍OSPFv3中LSA变化 xff0c LSA的变化时OSPFv3相对于OSPFv2的一大重大改变 xff0c 本文的主要内容是OSPFv3中变化的第四类LSA的详解 阅读本文 xff0c 您需要有一定的OSPF基础知识 x
  • KVM详解(六)——KVM虚拟机快照

    今天继续给大家介绍Linux运维相关知识 xff0c 本文主要内容是KVM的快照 一 KVM快照简介 KVM支持对虚拟机创建快照 xff0c 但是前提是该虚拟机镜像不可以是raw格式 xff0c 而应该是qcow2格式 但是 xff0c 如
  • Docker详解(十五)——Docker静态IP地址配置

    今天继续给大家介绍Linux运维相关知识 xff0c 本文主要内容是Docker静态IP地址配置 一 安装Docker桥接网络 在前文Docker详解 xff08 十四 xff09 Docker网络类型详解中 xff0c 我们讲解了Dock
  • 计算机硬盘备份和恢复解决方案

    问题背景 xff1a 项目需要提供一份系统使用的计算机硬盘备份和恢复方案 xff0c 方便计算机软硬件故障后快速的恢复系统 之前项目使用的工具是Macrium reflect工具 xff0c 但这个工具现在收费了 xff0c 而且功能比较多
  • Python函数详解(一)——函数的定义、调用及变量

    今天继续给大家介绍Python相关知识 xff0c 本文主要内容是Python函数的定义 调用及变量 一 Python函数的定义与调用 在Python中 xff0c 如果我们要反复的进行一种相同或者类似的代码 xff0c 那么我们就可以将这
  • vscode SSH 保存密码自动登录服务器vs code

    先在win local mac 上拿到公钥和私钥 xff0c 然后再把这公钥copy 进服务器 让ssh 身份认证转化为秘钥认证 xff08 mac也是一样的 xff09 1 创建 RSA 密钥对 第一步是在客户端机器 xff08 通常是您
  • 普罗米修斯

    普罗米修斯 xff08 Prometheus xff09 概述 Prometheus是一套开源的监控 报警 时间序列数据库的组合 xff0c 起始是由SoundCloud公司开发的 从2016年加入CNCF xff0c 2016年6月正式发
  • ROS-mavros-PX4加速度控制

    要写的飞控算法本来的输入是roll pitch以及推进力 xff0c 由于PX4不支持输入具体大小的推进力 xff0c 改用三方向加速度 xff08 可用旋转矩阵进行变换 xff09 进行控制 但是PX4的setpoint accel实际控
  • C# 委托(Delegate)与事件(Event)、Func与Action

    一 委托 1 概念 xff1a 从内存角度看 xff0c 委托是一个存储方法的容器 xff0c 当使用该容器时 xff0c 会把容器里面的方法全部执行一遍 xff0c 容器里面的方法可增 43 61 可减 61 从IL Microsoft中
  • STM32 UART串口通信IDLE空闲中断的使用步骤

    参考了各路大神的资料 xff0c 蒙蔽了半天 xff0c 终于学会了 xff0c 记录一下 xff0c 以后忘了可以回来复习参考 一 首先在stm32cube中配置打开对应uart串口的中断 二 工程main函数调用 HAL UART EN
  • 三大通信协议(1)UART

    目录 一 UART通信协议简介 二 UART通信时序 三 UART RS232 TTL关系阐述 1 简介 2 电平转换 四 实例 1 程序代码 2 仿真验证 总结 一 UART通信协议简介 UART xff08 Universal Asyn
  • CAD难学吗?

    首先 xff0c CAD程序不容易学习 这些程序不像学习Microsoft Word或Excel 大多数CAD应用程序都有较高的学习曲线 一些参数和3D CAD应用程序的学习曲线相当陡峭 由于它们的复杂性 xff0c 学习的承诺会更长 CA
  • 安卓strings.xml文件中的msgid的作用__2019.09.12

    lt string name 61 34 name 34 msgid 61 34 012345678912345 34 gt 34 name Name 34 lt string gt 是系统返回信息的标识id这个信息的唯一性 xff0c 你
  • RealSense SDK编译

    0 uname r 查看linux的内核版本 1 xff0c ls l dev sda 查看USB设备的设备文件 2 sudo dmesg tail n 50 查看是否能检测到相机 3 查看 librealsense doc install
  • Linux-磁盘管理

    第14章 Linux系统管理 磁盘管理 第14章 Linux系统管理 磁盘管理 1 磁盘的基本概念 2 磁盘的基本结构 3 磁盘的预备知识 4 磁盘基本分区Fdisk 5 磁盘基本分区Gdisk 6 磁盘挂载方式Mount 7 虚拟内存Sw
  • 网络---数据链路层

    数据链路层 一 数据链路层的信道类型 1 点对点信道 这种信道使用一对一的点对点通信方式 2 广播信道 这种信道使用一对多的广播通信方式 xff0c 因此过程比较复杂 xff0c 广播信道上连接的主机很多 xff0c 因此必须使用专用的共享
  • 第二讲:双目vio视觉前端以及后端重投影残差

    双目vio视觉前端以及后端重投影残差 vins双目 本次主要讲解vio双目系统的视觉前端部分和后端融合的重投影残差部分 xff0c 以vins切入做为分析 xff0c 并赋代码注释解析 主要包含以下五部分内容 xff11 xff09 双目特