专栏首页无雨森的技术分享KinectAzureDK编程实战_PCL

KinectAzureDK编程实战_PCL

前几篇文章,我讲了如何用 OpenCV 操作并可视化 Kinect 的 RGB + IR + Depth 图像。但是 OpenCV 只能用来操作 2D 图像。对于三维情况,主要就是三维重建,比如基于图片集的离线三维重建——SfM(Structured from Motion)等。在 OpenCV 的 rgbd 模块中实现了一个实时的三维重建 Kinect Fusion。说到三维重建,对于计算机视觉、计算机图形学主要从业者,用的很多的是 PCL(Point Cloud Library)。几乎所有的实时、离线三维重建开源系统都是基于 PCL 对实时点云的处理。

我们还是从一个例子讲如何实现 Kinect Azure DK 的 grabber。对于 2代 Kinect 来说,我们看 PCL 中的 grabber 怎么用。

首先声明一个基于 pcl::visualization::PCLVisualizer 的 viewer。并设置 visualizer 的摄像机参数,对应于 OpenGL 中的 gluLookat 函数。

viewer->setCameraPosition( 0.0, 0.0, -2.5, 0.0, 0.0, 0.0 );

前三个坐标表示,相机在世界坐标中的位置。后三个坐标表示,相机向上方向在世界坐标系中的方向。

在一个可视化环境中,可视化 Kinect 数据的同时,还要接收 Kinect 输出的数据。这必然涉及到多线程同步。

我们需要用一个线程来可视化,一个线程用来接收数据。在增强现实系统中,经常会用这种方式,OpenGL可视化当前场景,OpenCV实时图像处理。如我曾经在知乎上回答的问题。

想用OpenCV做AR该如何入手? https://www.zhihu.com/question/26983174/answer/35328819

如上代码,我声明了一个 mutex,作为互斥量,控制 Kinect 数据同一时间只能可视化或者处理。

boost::mutex mutex;

这个 mutex 同时处理实时点云。

boost::function<void(const pcl::PointCloud<PointType>::ConstPtr&)> function =
  [&cloud, &mutex](const pcl::PointCloud<PointType>::ConstPtr& ptr) 
{
  boost::mutex::scoped_lock lock(mutex);

  /* Point Cloud Processing */

  cloud = ptr->makeShared();
};

然后,我们声明一个 grabber 对象。

boost::shared_ptr<pcl::Grabber> grabber = boost::make_shared<pcl::Kinect2Grabber>();

pcl 的 grabber 实现了一个类似于 Qt 的 signal/slots 模式,用于完成 "raw data数据获取"“生成点云” 之间的通信。

声明一个 connection。

boost::signals2::connection connection = grabber->registerCallback( function );

当 grabber 接收到 raw data 就调用上面说到的回调函数用来处理点云。

然后就是启动 grabber。

grabber->start();

可视化线程。

while (!viewer->wasStopped()) 
{
  // Update Viewer
  viewer->spinOnce();
  boost::mutex::scoped_try_lock lock(mutex);
  if (lock.owns_lock() && cloud) 
  {
    // Update Point Cloud
    if (!viewer->updatePointCloud(cloud, "cloud")) 
    {
      viewer->addPointCloud(cloud, "cloud");
    }
  }
}

当 viewer 窗口关闭的时候,关闭 grabber,并断开 raw data 数据获取与生成点云之间的 connection。

if( connection.connected())
{
    connection.disconnect();
}

相对应的,我们来看我们自己写的 Kinect Azure DK 的 grabber 的用法。

这里有几处不同。

因为这一代 Kinect 初始化,需要配置一个变量 k4a_device_configuration_t config

所以,在声明 grabber 的同时,需要初始化这个变量。如上篇文章,我们初始化摄像头的帧率,彩色摄像头分辨率,深度摄像头分辨率,是否同步 RGB+Depth 图像等等。

boost::shared_ptr<pcl::Grabber> grabber = 
    boost::make_shared<pcl::KinectAzureDKGrabber>(0, 
    K4A_DEPTH_MODE_NFOV_UNBINNED, 
    K4A_IMAGE_FORMAT_COLOR_BGRA32, K4A_COLOR_RESOLUTION_720P);

PCL 的 Visualizer 需要初始化可视化环境中摄像机的参数。实际上,Visualizer 可视化环境中摄像机对应实际场景中 Kinect 的深度摄像头。

我们可以获取 Kinect深度摄像头的内外参。

并传入 PCL 的 Visualizer。

viewer->setCameraParameters(intrinsics_eigen, extrinsics_eigen);

设置,viewer 的摄像机参数与 Kinect 深度摄像头摄像机参数一致。

这样设置的好处就是,我们可以看到 在深度摄像头视角下的三维世界

如上gif,可以看到窗口一开始展示给我们的是类似于平面的结构。但当我们用鼠标操作时,就看到原来是三维的点云。说明我们一开始看到的就是深度摄像头视角下的点云。

下面我们看 Kinect Azure DK 的 grabber 类。

k4a_grabber.h

代码借鉴于 PCL 内的 openni grabber。

绝大部分代码都和 openni grabber类似,当然没有 openni grabber 写的大而全。我这里只是简略地实现。

这里只有一类函数最重要——转换 RGB + Depth 图像为彩色点云的函数。

按照 Kinect Azure DK 的开源SDK中的 sample

Azure Kinect Transformation Example https://github.com/microsoft/Azure-Kinect-Sensor-SDK/tree/v1.1.0/examples/transformation

我们把 depthImage 和 colorImage 通过 Kinect SDK 中的内置函数转为 k4a::image 形式的点云。

首先,我们先把 depthImage 转到彩色摄像头的空间。

transformation.depth_image_to_color_camera(depthImage, &transformed_depth_image);

如下图。

根据微软 Kinect 文档

函数 k4a_transformation_depth_image_to_color_camera() 将深度图从深度相机的视点转换为彩色相机的视点。 此函数旨在生成所谓的 RGB-D 图像,其中,D 表示录制深度值的附加图像通道。 在下图中可以看到,k4a_transformation_depth_image_to_color_camera() 的彩色图像和输出如同它们取自同一视点(即,彩色相机的视点)。 https://docs.microsoft.com/zh-cn/azure/Kinect-dk/use-image-transformation

重要的是,这个函数内部的实现方式是GPU加速的。我们不需要关心微软是怎么实现的。

此转换函数比单纯针对每个像素调用 k4a_calibration_2d_to_2d() 更为复杂。 它将深度相机几何结构中的三角网格扭曲成彩色相机的几何结构。 使用三角网格可以避免转换的深度图像出现孔洞。Z 缓冲区确保正确处理遮挡物。 默认已为此函数启用 GPU 加速。 https://docs.microsoft.com/zh-cn/azure/Kinect-dk/use-image-transformation

而且,微软也建议,相比于另一个“镜像”函数 k4a_transformation_color_image_to_depth_camera()

由于此方法会在转换的彩色图像中产生孔洞,并且不会处理遮挡物,因此我们建议改用函数 k4a_transformation_depth_image_to_color_camera() https://docs.microsoft.com/zh-cn/azure/Kinect-dk/use-image-transformation

接下来就是生成 PCL 格式的点云,这里我们生成的是 PoinXYZRGB 格式的点云,即包含点云每个点的三维坐标 (x, y z) 和颜色信息 (r, g, b)。

在上述代码中,需要说明的是这部分代码。

Eigen::Matrix3f m;
m = Eigen::AngleAxisf(-M_PI, Eigen::Vector3f::UnitZ());

声明了一个旋转矩阵,绕 Z 轴,顺时针方向旋转 180 度。

为什么会多这么一句呢?

我们来看 Kinect 的坐标系统。

如上图,右手坐标系,X 轴向左,Y轴向下,Z轴朝向用户。

但是我们的可视化环境是 PCL 的 Visualizer 类。这个类基于 VTK,而 VTK 是基于 OpenGL 的渲染。

所以,我们的可视化窗口的坐标系统应该是符合 OpenGL 的坐标系统。而OpenGL 窗口的坐标系统是 X 轴向右,Y轴向上,Z轴朝向用户。

刚好是把Kinect的深度摄像头坐标系绕 Z 轴,顺时针方向旋转 180 度。

如果没有这句话,我们的窗口会出现什么情况呢?

点云倒着显示在窗口。

所以,我们需要将点云旋转,以适应 PCL Visualizer的窗口坐标系统。

另外,Kinect 输出的深度数据单位是 mm。我们需要把数据都除 1000,换算成 m 以适应窗口坐标系统。

后面,我会讲解如何用 OpenGL 通过多线程的方式显示背景纹理的方式显示 RGB 或 IR 或 Depth 图像。

敬请期待。

商业合作:

E-mail: forestsen@vip.qq.com

本文分享自微信公众号 - 无雨森的技术分享(forestsen_tech)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • iOS给图片添加滤镜&使用openGLES动态渲染图片

    滤镜有哪些可选可以参看以下文章:http://www.jianshu.com/p/3e2cca585ccc

    周希
  • android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】

    转自:https://www.cnblogs.com/deman/p/5584198.html

    用户3033338
  • WebGL简易教程(五):图形变换(模型、视图、投影变换)

    通过之前的教程,对WebGL中可编程渲染管线的流程有了一定的认识。但是只有前面的知识还不足以绘制真正的三维场景,可以发现之前我们绘制的点、三角形的坐标都是[-1...

    charlee44
  • OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转

      因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我就先把基本的小demo给写好当做前期测试。

    徐飞机
  • Android 如何实现气泡选择动画

    跨平台用户体验统一正处于增长趋势:早些时候 iOS 和安卓有着不同的体验,但是最近在应用设计以及交互方面变得越来越接近。从安卓 Nougat 的底部导航到分屏特...

    CCCruch
  • 初学Qt(二) 中高级功能列举

    上一次和大家聊了聊Qt的三大基类,信号和槽的使用以及重新实现一些事件等话题。如果在学习Qt之前有一定的C语言编程,可能对响应界面操作还会有些不习惯。这次聊一聊Q...

    用户5908113
  • KinectAzureDK编程实战_OpenGL 显示 Kinect 数据

    这是关于如何用 PCL 打开 Kinect Azure DK,并可视化彩色点云。对应的文章是我半个月前写的《KinectAzureDK编程实战_PCL》。

    无雨森
  • 如何用 OpenCV+OpenGL 在 Android 平台实现一个简单的 AR 应用

    前几篇文章,我分别写了如何用 OpenGL 1在 Kinect Azure DK 平台实现一个简单的 AR 程序。

    无雨森
  • OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html

    徐飞机
  • As-rigid-as possible shape manipulation: 第一步算法的C++代码实现

    我们在这里输入的是obj文件,obj文件最重要的两个元素:点和面。对于一个简单的模型,如下图。

    无雨森

扫码关注云+社区

领取腾讯云代金券