realsense SDK2.0学习::(三)D435深度图片对齐到彩色图片-代码实现

D435深度图片对齐到彩色图片


深度图片对齐彩色图片,就是我们有深度图和彩色图,要知道彩色图中像素点所对应的深度值,需要利用深度图以及相机参数进行转换,本文先以进行原理推导,再给出实际运行代码

 一、确定所需变量

深度图Id深度摄像头获取
彩色图IcRBG摄像头获取

深度摄像头内参K_{d}

自行标定或直接realsense sdk2.0 获取 

RGB摄像头内参K_{c}自行标定或直接realsense sdk2.0 获取 

同一场景下A深度摄像头外参T_{w2d} 

【世界坐标系转换到深度摄像头坐标系的转换矩阵】

标定

同一场景下A彩色摄像头外参T_{w2c}

【世界坐标系转换到彩色摄像头坐标系的转换矩阵】

标定

深度摄像头到彩色摄像头的转移矩阵T_{d2c}

【深度摄像头坐标系转换到彩色摄像头坐标系的转换矩阵】

T_{w2d}T_{w2c}计算获取

或者直接从realsense sdk2.0 获取 

深度图下某点像素P_{dc}P_{u,v}^{d}

深度图下某点像素按深度还原到深度坐标系下的空间点\dot{P}_{dc}

 

彩色图下某点像素P_{cc}P_{u,v}^{c}

由世界坐标系转换到彩色坐标系下的空间点\dot{P}_{cc}

 
深度图转换到世界坐标系下的点P_{w} 

二、大概原理

目的:将深度坐标系下的点转换到彩色坐标系下

基本步骤:

(1)将深度图的像素点还原到深度坐标系下

(2)深度坐标系下的深度点还原到世界坐标系

(3)世界坐标系的深度点转换到彩色坐标系下

(4)彩色坐标系的深度点映射到Z=1的平面上,即与彩色图像的像素点对应起来

这里引用https://blog.csdn.net/jay463261929/article/details/53582800的一张原理图:

三、 公式演算

(1)先进行第一步,将深度图的像素点P_{u,v}^{d}还原到深度坐标系下

         \dot{P}_{dc}=ZK_{d}^{-1}P_{u,v}^{d}

(2)第二步:将深度空间坐标系的深度点\dot{P}_{dc}转换到世界坐标系下

        P_{w}=T_{w2d}^{-1}\dot{P}_{dc}

(3)第三步:将世界坐标系的深度点P_{w}转换到彩色摄像头坐标系

        \dot{P}_{cc}=T_{w2c} P_{w}

(4)第四步:将彩色摄像头坐标系下的深度点\dot{P}_{cc}映射到Z=1的彩色平面上

       P_{u,v}^{c}=K_{c}(\dot{P}_{cc}/z)

  • 其中,
  • (\dot{P}_{cc}/z)表示按z轴归一化,即该点的xyz都分别除以z值

(5)以上四步,就完成了深度平面图的点转换到彩色平面上,给彩色平面上的像素点增加一个信息通道{深度}

(6)实际处理中,一般把第二第三步直接结合起来,即获取一个从深度摄像头坐标系到彩色摄像头坐标系的欧氏变换矩阵T_{d2c}

具体推算如下:

      \dot{P}_{cc}=T_{w2c} P_{w}=T_{w2c}T_{w2d}^{-1} \dot{P}_{dc}

那么,有:

      T_{d2c}=T_{w2c}T_{w2d}^{-1}

根据高翔的《视觉SLAM十四讲》,欧氏变换矩阵T形式如下:

T=\begin{bmatrix} R & t \\ 0 & 1 \end{bmatrix}       T^{-1}=\begin{bmatrix} R^{-1} & -R^{-1}t \\ 0 & 1 \end{bmatrix} 

其中:

  • R为旋转矩阵,是单位正交的,所以其转置=其逆
  • t为轴的平移量

     T_{d2c}=T_{w2c} T_{w2d}^{-1}=\begin{bmatrix} R_{w2c}R_{w2d}^{-1}& t_{w2c}- R_{w2c}R_{w2d}^{-1} t_{w2d}\\ 0& 1 \end{bmatrix}

有了这个,就可以直接将深度摄像头空间坐标系下的点转换到彩色摄像头空间坐标系下了


代码部分:

#include <iostream>

using namespace std;
#include <sstream>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace cv;

#include<librealsense2/rs.hpp>
#include<librealsense2/rsutil.h>
//获取深度像素对应长度单位(米)的换算比例
float get_depth_scale(rs2::device dev)
{
    // Go over the device's sensors
    for (rs2::sensor& sensor : dev.query_sensors())
    {
        // Check if the sensor if a depth sensor
        if (rs2::depth_sensor dpt = sensor.as<rs2::depth_sensor>())
        {
            return dpt.get_depth_scale();
        }
    }
    throw std::runtime_error("Device does not have a depth sensor");
}
//深度图对齐到彩色图函数
Mat align_Depth2Color(Mat depth,Mat color,rs2::pipeline_profile profile){
    //声明数据流
    auto depth_stream=profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
    auto color_stream=profile.get_stream(RS2_STREAM_COLOR).as<rs2::video_stream_profile>();

    //获取内参
    const auto intrinDepth=depth_stream.get_intrinsics();
    const auto intrinColor=color_stream.get_intrinsics();

    //直接获取从深度摄像头坐标系到彩色摄像头坐标系的欧式变换矩阵
    //auto  extrinDepth2Color=depth_stream.get_extrinsics_to(color_stream);
    rs2_extrinsics  extrinDepth2Color;
    rs2_error *error;
    rs2_get_extrinsics(depth_stream,color_stream,&extrinDepth2Color,&error);

    //平面点定义
    float pd_uv[2],pc_uv[2];
    //空间点定义
    float Pdc3[3],Pcc3[3];

    //获取深度像素与现实单位比例(D435默认1毫米)
    float depth_scale = get_depth_scale(profile.get_device());
//    uint16_t depth_max=0;
//    for(int row=0;row<depth.rows;row++){
//        for(int col=0;col<depth.cols;col++){
//            if(depth_max<depth.at<uint16_t>(row,col))
//                depth_max=depth.at<uint16_t>(row,col);
//        }
//    }
    int y=0,x=0;
    //初始化结果
    Mat result=Mat::zeros(color.rows,color.cols,CV_8UC3);
    //对深度图像遍历
    for(int row=0;row<depth.rows;row++){
        for(int col=0;col<depth.cols;col++){
            //将当前的(x,y)放入数组pd_uv,表示当前深度图的点
            pd_uv[0]=col;
            pd_uv[1]=row;
            //取当前点对应的深度值
            uint16_t depth_value=depth.at<uint16_t>(row,col);
            //换算到米
            float depth_m=depth_value*depth_scale;
            //将深度图的像素点根据内参转换到深度摄像头坐标系下的三维点
            rs2_deproject_pixel_to_point(Pdc3,&intrinDepth,pd_uv,depth_m);
            //将深度摄像头坐标系的三维点转化到彩色摄像头坐标系下
            rs2_transform_point_to_point(Pcc3,&extrinDepth2Color,Pdc3);
            //将彩色摄像头坐标系下的深度三维点映射到二维平面上
            rs2_project_point_to_pixel(pc_uv,&intrinColor,Pcc3);

            //取得映射后的(u,v)
            x=(int)pc_uv[0];
            y=(int)pc_uv[1];
//            if(x<0||x>color.cols)
//                continue;
//            if(y<0||y>color.rows)
//                continue;
            //最值限定
            x=x<0? 0:x;
            x=x>depth.cols-1 ? depth.cols-1:x;
            y=y<0? 0:y;
            y=y>depth.rows-1 ? depth.rows-1:y;

            //将成功映射的点用彩色图对应点的RGB数据覆盖
            for(int k=0;k<3;k++){
                //这里设置了只显示1米距离内的东西
                if(depth_m<1)
                result.at<cv::Vec3b>(y,x)[k]=
                        color.at<cv::Vec3b>(y,x)[k];
            }
        }
    }
    return result;
}

int main()
{
    const char* depth_win="depth_Image";
    namedWindow(depth_win,WINDOW_AUTOSIZE);
    const char* color_win="color_Image";
    namedWindow(color_win,WINDOW_AUTOSIZE);

    //深度图像颜色map
    rs2::colorizer c;                          // Helper to colorize depth images

    //创建数据管道
    rs2::pipeline pipe;
    rs2::config pipe_config;
    pipe_config.enable_stream(RS2_STREAM_DEPTH,640,480,RS2_FORMAT_Z16,30);
    pipe_config.enable_stream(RS2_STREAM_COLOR,640,480,RS2_FORMAT_BGR8,30);

    //start()函数返回数据管道的profile
    rs2::pipeline_profile profile = pipe.start(pipe_config);

    //定义一个变量去转换深度到距离
    float depth_clipping_distance = 1.f;

    //声明数据流
    auto depth_stream=profile.get_stream(RS2_STREAM_DEPTH).as<rs2::video_stream_profile>();
    auto color_stream=profile.get_stream(RS2_STREAM_COLOR).as<rs2::video_stream_profile>();

    //获取内参
    auto intrinDepth=depth_stream.get_intrinsics();
    auto intrinColor=color_stream.get_intrinsics();

    //直接获取从深度摄像头坐标系到彩色摄像头坐标系的欧式变换矩阵
    auto  extrinDepth2Color=depth_stream.get_extrinsics_to(color_stream);

    while (cvGetWindowHandle(depth_win)&&cvGetWindowHandle(color_win)) // Application still alive?
    {
        //堵塞程序直到新的一帧捕获
        rs2::frameset frameset = pipe.wait_for_frames();
        //取深度图和彩色图
        rs2::frame color_frame = frameset.get_color_frame();//processed.first(align_to);
        rs2::frame depth_frame = frameset.get_depth_frame();
        rs2::frame depth_frame_4_show = frameset.get_depth_frame().apply_filter(c);
        //获取宽高
        const int depth_w=depth_frame.as<rs2::video_frame>().get_width();
        const int depth_h=depth_frame.as<rs2::video_frame>().get_height();
        const int color_w=color_frame.as<rs2::video_frame>().get_width();
        const int color_h=color_frame.as<rs2::video_frame>().get_height();

        //创建OPENCV类型 并传入数据
        Mat depth_image(Size(depth_w,depth_h),
                                CV_16U,(void*)depth_frame.get_data(),Mat::AUTO_STEP);
        Mat depth_image_4_show(Size(depth_w,depth_h),
                                CV_8UC3,(void*)depth_frame_4_show.get_data(),Mat::AUTO_STEP);
        Mat color_image(Size(color_w,color_h),
                                CV_8UC3,(void*)color_frame.get_data(),Mat::AUTO_STEP);
        //实现深度图对齐到彩色图
        Mat result=align_Depth2Color(depth_image,color_image,profile);

        //显示
        imshow(depth_win,depth_image_4_show);
        imshow(color_win,color_image);
        imshow("result",result);
        waitKey(10);
    }
    return 0;
}

实现效果:

  • 28
    点赞
  • 204
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
### 回答1: Realsense SDK 2.0 是英特尔公司推出的一款深度相机开发工具包,可以用于开发各种基于深度相机的应用程序。学习 Realsense SDK 2.0 需要掌握深度相机的原理和使用方法,以及相关的编程知识和技能。可以通过阅读官方文档、参加培训课程、查阅相关书籍等方式进行学习。同时,还需要具备一定的计算机视觉和机器学习等方面的知识,以便更好地应用 Realsense SDK 2.0 进行开发。 ### 回答2: RealSense SDK2.0是英特尔公司推出的一款深度学习软件开发工具包,专门用于开发支持英特尔RealSense摄像头的应用程序。利用该工具包,用户可以轻松地将RealSense摄像头的深度感知功能集成到自己的应用程序中,实现场景感知、动作识别、手势控制、面部表情识别等多种功能。 学习RealSense SDK2.0需要具备一定的编程基础,熟悉C++、C#、Python等编程语言,同时还需要了解深度学习、计算机视觉等相关知识。具体的学习步骤如下: 1. 安装RealSense SDK2.0:从英特尔官网下载RealSense SDK2.0,并按照安装步骤进行安装。 2. 熟悉RealSense SDK2.0 API:RealSense SDK2.0提供了丰富的API,包括深度图像获取、人体骨骼识别、手势识别、面部表情识别等功能,需要深入了解并进行实际操作。 3. 开发实际应用程序:在熟悉API后,可以进行实际的应用程序开发。例如,基于RealSense SDK2.0开发的人脸识别系统、动作捕捉系统等。 4. 学习RealSense SDK2.0案例:英特尔官网提供了丰富的RealSense SDK2.0应用案例,可以通过学习这些案例,更好地了解RealSense SDK2.0的使用方法和开发技巧。 总之,学习RealSense SDK2.0需要具备一定的编程基础和相关知识,并需要在实际应用程序开发中进行深入学习和实践。 ### 回答3: RealSense SDK2.0是Intel公司出品的一款开发工具包,用于支持使用Intel RealSense技术进行开发。该工具包提供了一套完整的工具链,开发人员可以使用它来创建实时的3D摄像头解决方案,使设备具有感知环境和深化了解用户的能力。它主要包括了许多功能强大的API和库,使得开发人员可以使用这些API和库,来访问RealSense 3D深度摄像头的数据并将其应用在各种开发领域中。 在使用RealSense SDK2.0学习时,需要首先掌握一些基础知识,如深度图像、RGB图像、位置追踪等。此外,还需要掌握如何使用真实的数据来处理视频流、创建人脸和手势识别、物体追踪、语音识别和跟踪等功能。同时,为了提高开发效率,还需要掌握如何使用一些高级工具和技术,例如RealSense Viewer、RealSense Depth Quality Tool、RealSense Explorer、RealSense Emotion Detection、RealSense Player等。 在应用中,RealSense SDK2.0非常适用于各种场景,可以应用于虚拟现实、移动机器人、医学成像、安全监控、互动游戏、屏幕投影等领域。该SDK具有高性能、高精度和易于使用等优点,能够为开发人员提供更好的用户体验和更好的开发体验。 要学习RealSense SDK2.0,需要掌握计算机视觉、深度学习、机器学习等相关领域的基础知识,以便更好地处理和分析数据。此外,还需要掌握常用的编程语言,如C++、Python等,以便更好地开发应用程序。最后,需要注意实践。只有通过实践,才能更好地了解RealSense SDK2.0,并将其应用到实际的场景中。
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值