vSLAM重读(5): vSLAM中对双目相机的数据处理及与单目相对比

1. 双目相机概述

  • 双目立体视觉模型

    双目模型求取深度

    • 双目立体相机分别校准可参考 ROS_单目相机_分别校准
  • 双目立体匹配算法案例

    https://www.cnblogs.com/riddick/p/8486223.html
    https://www.cnblogs.com/zyly/p/9373991.html

  • 双目相机的特性

    1.双目相机有左右两个视野图,所以有了参数基线

    • 基线的特性

      1.当系统的硬件结构固定不变,则通过外参校准的T中的位移量可对比参考基线长;且工作距离越大,测量精度越低。

      2.当基线增大时,FOV中水平角在增大,其对精度的影响是非线性的。

  • 双目相机的矫正

    • 相机内参标定

      相机内参标定,获取相机坐标系与图像坐标系之间的投影关系,如(fx, fy, cx, cy, k1, k2, k3, 等)

    • 相机外参标定

      相机外参反应的是摄像机坐标系和世界坐标系之间的旋转R+T关系,双目相机外参主要获取两个相机之间“基线”

  • 双目相机的立体匹配算法

    在双目相机中特征点的匹配与单目类似,用光流法跟踪特征,选取匹配点。

    然后对匹配的特征点对计算本质矩阵,再分解矩阵获得旋转矩阵R和平移矩阵t;

    • 基于局部的块匹配 - BM(Block Matching StereoBM)

    • 半全局块匹配 - SGBM(Semi-Global-Block-Matching)

    SGBM算法要远远优于BM算法。

2. 单目相机+双目相机+深度相机(结构光)+TOF对比

  • 单目无法确认深度

单目SLAM不受环境大小的影响,因此既可以用于室内,又可以用于室外。

  • 双目相机

双目相机标定配置较为复杂(why?)(好像还有一个对准,有点不太记得…欢迎补充):

1. 双目相机的各个单独的镜头需要内参校准;
2. 双目相机的各个单独的镜头需要外参校准;
3. 双目相机两个相机之间需要校准;
4. 双目相机的两个相机校准之后还要与出厂的基线对齐,若误差较大则校准失败。

双目相机的优势: 它不管在静止和运动下都可以直接估计场景的深度值。其深度量程受双目的基线和分辨率限制。

另外,使用双目相机去计算视差,还原深度值,比较耗时(如SGBM立体匹配)。

  • 结构光测量 (主动式测量:可以直接获取距离值)

3D结构光投射的是散斑或编码图案,接收模组需要拍摄到清晰的图案才能计算出深度。

而随着距离的增加,投出的图案或出现模糊,或出现亮度能量上的衰减,导致深度图不完整,出现破洞,甚至于失效,所以3D结构光并不适用于远距离深度信息采集。

结构光在室外容易受到强光的影响,效果很差。因为光斑成像很容易受到环境的干扰。
结构光的测量距离一般较近(0.1~10m)如realsense D435
  • TOF(飞行时间测距法) (主动式测量:可以直接获取距离值)

TOF是通过红外光发射器发射调制后的红外光脉冲,不停地打在物体表面,经反射后被接收器接收,通过相位的变化来计算时间差,进而结合光速计算出物体深度信息

不受环境光照的影响,室内室外都可行。TOF测量的距离一般较远(0.4~130m) 如VLP16

3. 视差图和深度图的填充方法

以视差图dispImg为例。计算图像的积分图integral,并保存对应积分图中每个积分值处所有累加的像素点个数n(空洞处的像素点不计入n中,因为空洞处像素值为0,对积分值没有任何作用,反而会平滑图像)。

采用多层次均值滤波。首先以一个较大的初始窗口去做均值滤波(积分图实现均值滤波就不多做介绍了,可以参考我之前的一篇博客),将大区域的空洞赋值。然后下次滤波时,将窗口尺寸缩小为原来的一半,利用原来的积分图再次滤波,给较小的空洞赋值(覆盖原来的值);依次类推,直至窗口大小变为3x3,此时停止滤波,得到最终结果。

多层次滤波考虑的是对于初始较大的空洞区域,需要参考更多的邻域值,如果采用较小的滤波窗口,不能够完全填充,而如果全部采用较大的窗口,则图像会被严重平滑。因此根据空洞的大小,不断调整滤波窗口。先用大窗口给所有空洞赋值,然后利用逐渐变成小窗口滤波覆盖原来的值,这样既能保证空洞能被填充上,也能保证图像不会被过度平滑

void insertDepth32f(cv::Mat& depth)
{
    const int width = depth.cols;
    const int height = depth.rows;
    float* data = (float*)depth.data;
    cv::Mat integralMap = cv::Mat::zeros(height, width, CV_64F);
    cv::Mat ptsMap = cv::Mat::zeros(height, width, CV_32S);
    double* integral = (double*)integralMap.data;
    int* ptsIntegral = (int*)ptsMap.data;
    memset(integral, 0, sizeof(double) * width * height);
    memset(ptsIntegral, 0, sizeof(int) * width * height);
    for (int i = 0; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 0; j < width; ++j)
        {
            int id2 = id1 + j;
            if (data[id2] > 1e-3)
            {
                integral[id2] = data[id2];
                ptsIntegral[id2] = 1;
            }
        }
    }
    // 积分区间
    for (int i = 0; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 1; j < width; ++j)
        {
            int id2 = id1 + j;
            integral[id2] += integral[id2 - 1];
            ptsIntegral[id2] += ptsIntegral[id2 - 1];
        }
    }
    for (int i = 1; i < height; ++i)
    {
        int id1 = i * width;
        for (int j = 0; j < width; ++j)
        {
            int id2 = id1 + j;
            integral[id2] += integral[id2 - width];
            ptsIntegral[id2] += ptsIntegral[id2 - width];
        }
    }
    int wnd;
    double dWnd = 2;
    while (dWnd > 1)
    {
        wnd = int(dWnd);
        dWnd /= 2;
        for (int i = 0; i < height; ++i)
        {
            int id1 = i * width;
            for (int j = 0; j < width; ++j)
            {
                int id2 = id1 + j;
                int left = j - wnd - 1;
                int right = j + wnd;
                int top = i - wnd - 1;
                int bot = i + wnd;
                left = max(0, left);
                right = min(right, width - 1);
                top = max(0, top);
                bot = min(bot, height - 1);
                int dx = right - left;
                int dy = (bot - top) * width;
                int idLeftTop = top * width + left;
                int idRightTop = idLeftTop + dx;
                int idLeftBot = idLeftTop + dy;
                int idRightBot = idLeftBot + dx;
                int ptsCnt = ptsIntegral[idRightBot] + ptsIntegral[idLeftTop] - (ptsIntegral[idLeftBot] + ptsIntegral[idRightTop]);
                double sumGray = integral[idRightBot] + integral[idLeftTop] - (integral[idLeftBot] + integral[idRightTop]);
                if (ptsCnt <= 0)
                {
                    continue;
                }
                data[id2] = float(sumGray / ptsCnt);
            }
        }
        int s = wnd / 2 * 2 + 1;
        if (s > 201)
        {
            s = 201;
        }
        cv::GaussianBlur(depth, depth, cv::Size(s, s), s, s);
    }
}

4. 相对于单目, 双目相机的劣势?

1.配置及标定比较复杂,两个镜头都需要单独标定内参和外参矩阵,然后将两个相机联合校准计算基线,并与出厂参数进行对照,
    若相差较大,则需要重新校准;

2.双目(900--1600)成本相对于单目相机(50--200)贵;

3.双目相机是被动式数据获取,单目相机是主动式数据获取; 双目通过视差可以获取深度值,而单目需要运动才能获取深度信息;

4.双目在计算立体配准获取视差时(像素级计算,若想图像块计算则会模糊深度值),需要消耗较大的计算量。而单目不需要大量或者GPU计算;

5.所以可能就是因为从成本、计算量、实时性等方面考虑, 目前单目落地应用相比于双目要多一些。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
最早的SLAM雏形是在军事(核潜艇的海底定位)上的应用,主要传感器是军用雷达。SLAM技术发展到如今已经几十年,目前以激光雷达作为主传感器的SLAM技术比较稳定、可靠,仍然是主流的技术方案。但随着最近几年计算机视觉技术的快速发展,SLAM技术越来越多的应用于家用机器人、无人机、AR设备,基于视觉的Visual SLAM(简称VSLAM)逐渐开始崭露头角。VSLAM的技术框架主要包括传感器数据预处理、前端、后端、回环检测、建图。技术框架如下: 本方案的eXLAM-80TOF模组是独立的双目VSLAM模组,通过USB3.0接口来传输,体积小巧,可以嵌入到机器人应用,并可以提供定制开发,广泛应用于AR/VR、扫地机器人等行业,使得客户的产品有了空间定位和导航的能力,使产品更智能、更实用。eXLAM-80TOF模组提供标准的双目帧率高达100Hz的毫米级精度的SLAM服务上增加了TOF深度摄像头方案,提供224x172的深度分辨率,帧率最高可达100Fps,识别深度达到5m+,并且无需依赖Host端计算,可直接输出深度数据和点云数据,带有TOF的方案为三维空间信息获取的提供更高性能的方案,可以作用于3D重建、距离测量、导航避障,手势识别。eXLAM-80TOF双目模组可以让普通的机器人插上AI的翅膀,实现更多智慧功能。 应用场景: eXLAM-80TOF双目模组可以集成在AR/VR头盔实现戴着VR头显的玩家的头部回转动作,即上下、左右、前后回转动作,还有身体的上下、左右、前后动作; eXLAM-80TOF双目模组可以集成在扫地机器人,实现扫地机器人的路劲规划、避障功能。 eXLAM-80TOF双目模组可以集成在服务机器人,实现送餐机器人自动送餐、接引机器人自动带路等功能。 eXLAM-80TOF双目模组可以集成在仓储机器人,实现在物流仓库自动分拣、备货功能。 eXLAM-80TOF双目模组可以集成在无人机,实现在空的手势识别、跟踪等功能。 【主要特点】◆本地计算:空间建模及定位运算不需借助服务器. ◆功能丰富:支持多种机器视觉功能. ◆小尺寸: 长度只有80mm,宽度只有不到1圆硬币大小,可嵌入各类移动设备 ◆目前支持系统:Ubuntu16.04 / Windows10 ◆部署简单:USB3.0简单对接即可. ◆可定制:可以根据客户需求进行客制化 方案来源于大大通

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱发呆de白菜头

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

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

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

打赏作者

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

抵扣说明:

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

余额充值