Xungerrrr's Blog

用Azure Kinect DK进行深度测量

深度相机与云计算能碰出怎么样的火花?Azure Kinect DK上手试玩。

Word count: 3.5kReading time: 12 min
2019/09/27 Share

你可能曾经听说过Kinect,它最初是由微软推出的一款体感外设,主要用在Xbox上,为游戏带来体感交互功能。在2019年,微软更新了Kinect的产品线,推出了全新的Azure Kinect DK。与之前的Kinect不同,Azure Kinect DK并不是针对普通消费者和游戏场景推出,而是专注于商用领域的应用开发,并且强调与AI的融合。

目前,现有的Kinect for Windows v2应用程序不能直接与Azure Kinect DK配合工作,需要移植到新的SDK。因此,开发者需要了解和学习使用新的SDK。下面,我们先了解一下Azure Kinect DK的基本内容,然后围绕深度测量这一主题来进行探索和学习。

Azure Kinect DK概述

Azure Kinect DK是微软推出的一款开发人员工具包,由配有先进AI传感器的Kinect设备和配套的软件开发工具包(SDK)组成。

Kinect设备

Azure Kinect DK硬件主要包含以下的内容:

  1. 100万像素深度传感器,具有宽、窄视场角(FOV)选项,可获取场景的深度数据
  2. 7麦克风阵列,可用于远场语音和声音捕获
  3. 1200万像素RGB摄像头,提供和深度数据匹配的彩色图像数据流
  4. 加速计和陀螺仪(IMU),可用于传感器方向和空间跟踪
  5. 外部同步引脚,可轻松同步多个Kinect设备的传感器数据流

与Kinect for Windows相比,Azure Kinect设备具有更高的硬件规格,同时具备音频、视频、深度和运动传感器,可以全方位感知环境,构建丰富的解决方案。在本文中,我们只关注深度相机和RGB相机的使用。

软件开发工具包

Azure Kinect DK的开发环境包含以下的内容:

  • 用于访问低级别传感器和设备的传感器SDK
  • 用于跟踪3D人体的人体跟踪SDK
  • 用于启用麦克风访问和基于Azure云的语音服务的语音认知服务SDK

此外,我们还可以结合使用Azure提供的认知视觉服务,为应用赋予强大的视觉感知能力。在本文中,我们只使用了传感器SDK和Azure认知视觉服务。

深度相机的原理

深度相机有很多种,Azure Kinect配备的深度相机使用了调幅连续波(AMCW)进行时差测距(ToF)。相机向场景中发射近红外(IR)频谱中的调制光,然后测量光线经场景反射后返回的时间差,从而获取到场景的深度信息。深度相机将原始的调制IR图像传输到电脑主机,电脑通过GPU加速的深度引擎软件将原始信号转换为深度图。深度图是图像每个像素的一组Z坐标值,以毫米为单位。

Azure Kinect的深度相机支持窄视场(NFOV)和宽视场(WFOV)两种视场模式。窄视场适合X、Y维度范围较小,但Z维度范围较大的场景。宽视场适合X、Y维度范围较大,但Z维度范围较小的场景。如下图,左为窄视场,右为宽视场。

深度测量

准备工作

要使用Azure Kinect DK,首先需要下载和安装传感器SDK

安装完成后,我们通过一份示例代码来演示深度测量的过程。从GitHub下载这里用到的C#示例代码。

获取图像

深度测量的第一步是获取图像。通常,深度测量需要用到彩色照片,以便人们直观地理解深度信息与场景内容的对应关系,因此,我们首先要从Kinect设备中获取彩色图像。目录1 - AcquiringImages中的代码演示了这一过程。一般来说,从Kinect中获取图像(彩色图像或深度图),可以分为以下四个步骤。

  1. 找到并打开设备

    1
    2
    // Open the default device
    this.kinect = Device.Open();
  2. 配置并启动相机

    这一步主要进行相机的初始化配置,例如颜色空间、分辨率、深度取景模式等等。

    1
    2
    3
    4
    5
    6
    7
    8
    // Configure camera modes
    this.kinect.StartCameras(new DeviceConfiguration
    {
    ColorFormat = ImageFormat.ColorBGRA32,
    ColorResolution = ColorResolution.R1080p,
    DepthMode = DepthMode.NFOV_2x2Binned,
    SynchronizedImagesOnly = true
    });
  3. 从设备获取捕获(Capture)

    1
    Capture capture = await Task.Run(() => { return this.kinect.GetCapture(); })
  4. 从捕获中获取图像

    1
    var color = capture.Color;

捕获和图像的关系是什么呢?简单来说,捕获包含了图像。图像是以关联的方式捕获的,每一个捕获包含了一个时间戳所对应的一组深度图、IR图像和彩色图像。下面是从捕获中获取的一张彩色图像。

图像转换

深度相机和彩色相机是相互独立的传感器,因此它们有各自独立的坐标系,视角和视点也会有所不同。通常,我们希望将两种图像的数据结合起来使用,以方便理解深度信息。图像转换的目的就是通过一定的变换,将一个相机的视点转换到另一个相机的视点上。

传感器SDK为我们提供了这样的转换函数。目录2 - TransformDepthToColor中的代码演示了从深度相机到彩色相机的视点转换。这个过程可以大致分为以下三个步骤。

  1. 首先,加载Azure Kinect的图像转换引擎

    1
    2
    /// Azure Kinect transformation engine
    private readonly Transformation transform = null;
  2. 初始化一个空图像,用来存放转换后的深度图

    1
    2
    Image transformedDepth = new Image(
    ImageFormat.Depth16, colorWidth, colorHeight, colorWidth * sizeof(UInt16))
  3. 调用SDK函数DepthImageToColorCamera,传入捕获和空图像进行转换

    1
    this.transform.DepthImageToColorCamera(capture, transformedDepth);

这样就可以将深度图像变换到彩色相机的视点上,使深度图和彩色图的像素能够一一对应。下面是转换后的深度图。

有了转换后的深度图像和对应的彩色图像,我们就可以开始进行深度测量了。通过深度图的像素值,我们就可以获取彩色图上任意一点(x, y)的深度了!像这样:

1
transformedDepth.GetPixel<ushort>(y, x)

简单的深度测量应用

图像分割

利用深度信息,一个简单的应用是前景背景的分割。目录3 - SegmentColor中的代码演示了分割图像前景的过程。

由于拥有深度信息,我们可以设置一个距离阈值(如1000,单位为毫米)。当像素的深度值小于阈值,则认为其属于前景,保持像素颜色不变。反之则属于背景,将像素的颜色值置为0。这样就实现了简单的前景分割。

1
2
3
4
5
6
7
8
9
for (int i = 0; i < this.colorHeight * this.colorWidth; i++)
{
if (depthPixels[i] < 1000 &&
depthPixels[i] != 0)
{
continue;
}
colorPixels[i] = 0;
}

这样就能将前景分割出来啦。

测量物体的距离

有了丰富的场景数据,如果能加上一点图像理解的能力就更好了。使用微软Azure的认知服务,能够很方便地为应用添加智能。在这里,我们使用Azure上的计算机视觉服务,可以直接使用预训练好的通用视觉模型,为应用增加视觉感知能力。

目录4 - CognitiveServices中的工程演示了一个测量人体距离的应用。要测量人体距离,当然需要先进行人体检测。使用认知视觉服务,对彩色图片进行分析,可以轻松进行物体检测。当在图片中检测到人体时,利用深度信息就可以计算出摄像头到人的距离了。为了方便拍摄,我对识别的目标做了一点小修改,将识别人体改为识别背包。同时,为了方便理解,我将视觉服务返回的物体位置用红色矩形标记了出来。

如果你想要自己跑这个程序,需要有有效的Azure订阅,并且创建一个计算机视觉资源。之后,还要将代码中的subscriptionKey和Endpoint替换为自己资源中的信息。

应用的逻辑可以划分为以下几个步骤:

  1. 实例化计算机视觉客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Create the computer vision client
    computerVision = new ComputerVisionClient(
    new ApiKeyServiceClientCredentials(subscriptionKey),
    new System.Net.Http.DelegatingHandler[] { })
    {
    // You must use the same region as you used to get  
    // your subscription keys.
    Endpoint = "YourEndpoint"
    };
  2. 转换深度图像到彩色相机视点

    1
    this.transform.DepthImageToColorCamera(capture, transformedDepth);
  3. 分析图像,获取背包物体的包围盒

    在图像分析的结果里,有一个物体的集合,里面包含了检测出的所有物体。每一个物体都有一个属性和表示位置的矩形,这里我用”Luggage and bags”属性来检测背包,并且将矩形绘制出来。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    _ = computerVision.AnalyzeImageInStreamAsync(stream, MainWindow.features).ContinueWith((Task<ImageAnalysis> analysis) =>
    {
    try
    {
    foreach (var item in analysis.Result.Objects)
    {
    if (item.ObjectProperty == "Luggage and bags")
    {
    this.boundingBox = item.Rectangle;
    rectangle.Rect = new Rect(this.boundingBox.X, this.boundingBox.Y, this.boundingBox.W, this.boundingBox.H);
    }
    }
    }
    catch (System.Exception ex)
    {
    this.StatusText = ex.ToString();
    }
    }, TaskScheduler.FromCurrentSynchronizationContext());
  4. 取包围盒的中心点的深度值,得到摄像头到背包的距离

    从计算过程来看,x和y分别是矩形中心的横坐标和纵坐标。通过获取这个坐标的深度值,就得到了背包的距离。

    1
    2
    3
    4
    5
    6
    7
    if (boundingBox != null)
    {
    int y = (boundingBox.Y + boundingBox.H / 2);
    int x = (boundingBox.X + boundingBox.W / 2);

    this.StatusText = "The bag is: " + transformedDepth.GetPixel<ushort>(y, x) + "mm away";
    }

最终的显示效果是这样的,红色矩形标识了背包的位置,下方的文字显示背包距离摄像头601毫米。

通过下面的3D图像能更容易理解这个过程。首先,计算机视觉服务在二维图片中识别出了一个背包,用矩形标记了背包的位置。我们可能会将这个矩形想象成一个平面图形,即图中的黄色矩形。但是,从深度相机(红色圆点)的角度来看,这个矩形包含了三维中的一个锥形空间,即图中的红色区域。红色圆点到白色曲面上不同点的距离,组成了场景的深度信息。通过获取矩形中心点的深度值,我们实际上获得了图中蓝色线段的长度。

应用场景

从上面的例子可以看到,传感器SDK提供了对硬件传感器流的低级访问,使用SDK可以获得一些基础数据,例如深度图、音频流和陀螺仪数据等。利用转换后的深度图,我们可以进行深度测量、图像分割,结合Azure认知服务还可以测量特定物体的距离。在实际的商用领域中,深度测量能有怎样的应用场景呢?下面给出一些设想和实现思路。

物流信息自动识别

在物流仓库,可以结合Azure的计算机视觉服务,自动测量包裹的尺寸。将Kinect设置在物流流水线上,持续将捕获画面上传到云端进行分析。当有包裹经过时,云端会返回物体识别的结果,包括包裹的边缘位置信息。利用包裹的边缘位置,深度相机可以获取包裹四个顶点的深度值,然后计算出包裹的长宽大小。根据测量的大小,可以统计出所有包裹的尺寸,合理设置车辆的装箱方案。

此外,可以结合文本识别服务,实现光学字符识别(OCR),自动识别出包裹的运单信息,快速分发包裹。例如,某物流公司的运单信息都贴在包裹的一个指定位置上。当有包裹经过时,我们将包裹图片上传到文本识别服务。云服务可以针对运单信息的部分进行字符识别,并返回识别结果。这样,可以自动将包裹分类,提高物流管理速度。

环境三维重建

仅通过一个Kinect设备在一个角度进行采集,获得的数据是不足够的。在某些情况下,深度测量会出现失效,例如多径干扰、信号饱和或信号强度过低。通过多个Kinect设备,多次采集场景数据,能够避免出现测量死角。

将多次测量的深度数据整合起来,甚至可以重建场景的三维模型。这对于文物保存、建筑评估等领域是非常有用的。

总结

Azure Kinect DK和之前的Kinect for Windows有什么不同?一方面,Azure Kinect有着更高规格的硬件,例如更强的陀螺仪和更丰富的深度相机模式,更适合于工业使用。另一方面,Azure Kinect将基本功能集成在两个SDK中,而更高级的功能,例如人脸追踪、语音识别等,则通过与Azure认知服务连接来实现。通过Azure云计算,能够更快地进行数据分析和处理,服务的部署也更方便。

从上手来看,目前Azure Kinect DK主要涉及Azure认知服务的视觉和语音服务,但是,深度相机和云的结合还不是很密切。深度信息的分析和处理,例如深度图的生成,都是在本地运算生成。官网给出的样例中,视觉服务只用于分析彩色图片,没有利用到深度图片。将深度数据与认知服务结合,可能会有更多的应用前景,例如,利用深度数据的变化预测物体的运动轨迹。相信随着SDK的不断完善,Azure Kinect DK会在工业落地实际应用中发挥更大的潜力。

CATALOG
  1. 1. Azure Kinect DK概述
    1. 1.1. Kinect设备
    2. 1.2. 软件开发工具包
  2. 2. 深度相机的原理
  3. 3. 深度测量
    1. 3.1. 准备工作
    2. 3.2. 获取图像
    3. 3.3. 图像转换
    4. 3.4. 简单的深度测量应用
      1. 3.4.1. 图像分割
      2. 3.4.2. 测量物体的距离
  4. 4. 应用场景
    1. 4.1. 物流信息自动识别
    2. 4.2. 环境三维重建
  5. 5. 总结