你可能曾经听说过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硬件主要包含以下的内容:
- 100万像素深度传感器,具有宽、窄视场角(FOV)选项,可获取场景的深度数据
- 7麦克风阵列,可用于远场语音和声音捕获
- 1200万像素RGB摄像头,提供和深度数据匹配的彩色图像数据流
- 加速计和陀螺仪(IMU),可用于传感器方向和空间跟踪
- 外部同步引脚,可轻松同步多个Kinect设备的传感器数据流
与Kinect for Windows相比,Azure Kinect设备具有更高的硬件规格,同时具备音频、视频、深度和运动传感器,可以全方位感知环境,构建丰富的解决方案。在本文中,我们只关注深度相机和RGB相机的使用。
软件开发工具包
Azure Kinect DK的开发环境包含以下的内容:
此外,我们还可以结合使用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
2// Open the default device
this.kinect = Device.Open();配置并启动相机
这一步主要进行相机的初始化配置,例如颜色空间、分辨率、深度取景模式等等。
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
});从设备获取捕获(Capture)
1
Capture capture = await Task.Run(() => { return this.kinect.GetCapture(); })
从捕获中获取图像
1
var color = capture.Color;
捕获和图像的关系是什么呢?简单来说,捕获包含了图像。图像是以关联的方式捕获的,每一个捕获包含了一个时间戳所对应的一组深度图、IR图像和彩色图像。下面是从捕获中获取的一张彩色图像。
图像转换
深度相机和彩色相机是相互独立的传感器,因此它们有各自独立的坐标系,视角和视点也会有所不同。通常,我们希望将两种图像的数据结合起来使用,以方便理解深度信息。图像转换的目的就是通过一定的变换,将一个相机的视点转换到另一个相机的视点上。
传感器SDK为我们提供了这样的转换函数。目录2 - TransformDepthToColor中的代码演示了从深度相机到彩色相机的视点转换。这个过程可以大致分为以下三个步骤。
首先,加载Azure Kinect的图像转换引擎
1
2/// Azure Kinect transformation engine
private readonly Transformation transform = null;初始化一个空图像,用来存放转换后的深度图
1
2Image transformedDepth = new Image(
ImageFormat.Depth16, colorWidth, colorHeight, colorWidth * sizeof(UInt16))调用SDK函数DepthImageToColorCamera,传入捕获和空图像进行转换
1
this.transform.DepthImageToColorCamera(capture, transformedDepth);
这样就可以将深度图像变换到彩色相机的视点上,使深度图和彩色图的像素能够一一对应。下面是转换后的深度图。
有了转换后的深度图像和对应的彩色图像,我们就可以开始进行深度测量了。通过深度图的像素值,我们就可以获取彩色图上任意一点(x, y)的深度了!像这样:
1 | transformedDepth.GetPixel<ushort>(y, x) |
简单的深度测量应用
图像分割
利用深度信息,一个简单的应用是前景背景的分割。目录3 - SegmentColor中的代码演示了分割图像前景的过程。
由于拥有深度信息,我们可以设置一个距离阈值(如1000,单位为毫米)。当像素的深度值小于阈值,则认为其属于前景,保持像素颜色不变。反之则属于背景,将像素的颜色值置为0。这样就实现了简单的前景分割。
1 | for (int i = 0; i < this.colorHeight * this.colorWidth; i++) |
这样就能将前景分割出来啦。
测量物体的距离
有了丰富的场景数据,如果能加上一点图像理解的能力就更好了。使用微软Azure的认知服务,能够很方便地为应用添加智能。在这里,我们使用Azure上的计算机视觉服务,可以直接使用预训练好的通用视觉模型,为应用增加视觉感知能力。
目录4 - CognitiveServices中的工程演示了一个测量人体距离的应用。要测量人体距离,当然需要先进行人体检测。使用认知视觉服务,对彩色图片进行分析,可以轻松进行物体检测。当在图片中检测到人体时,利用深度信息就可以计算出摄像头到人的距离了。为了方便拍摄,我对识别的目标做了一点小修改,将识别人体改为识别背包。同时,为了方便理解,我将视觉服务返回的物体位置用红色矩形标记了出来。
如果你想要自己跑这个程序,需要有有效的Azure订阅,并且创建一个计算机视觉资源。之后,还要将代码中的subscriptionKey和Endpoint替换为自己资源中的信息。
应用的逻辑可以划分为以下几个步骤:
实例化计算机视觉客户端
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"
};转换深度图像到彩色相机视点
1
this.transform.DepthImageToColorCamera(capture, transformedDepth);
分析图像,获取背包物体的包围盒
在图像分析的结果里,有一个物体的集合,里面包含了检测出的所有物体。每一个物体都有一个属性和表示位置的矩形,这里我用”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());取包围盒的中心点的深度值,得到摄像头到背包的距离
从计算过程来看,x和y分别是矩形中心的横坐标和纵坐标。通过获取这个坐标的深度值,就得到了背包的距离。
1
2
3
4
5
6
7if (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会在工业落地实际应用中发挥更大的潜力。