65.9K
CodeProject 正在变化。 阅读更多。
Home

理解Kinect坐标映射

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (5投票s)

2014年5月6日

CPOL

3分钟阅读

viewsIcon

44670

理解Kinect坐标映射

这是我在收到博客订阅者的一些良好反馈后发布的另一篇文章。 似乎很多人在创建Kinect项目时都有一个共同的问题:他们如何才能正确地将数据投射到颜色和深度流之上。

正如您可能知道的那样,Kinect将一些传感器集成到一个设备中

  • 一个RGB彩色摄像头 – 版本1中为640×480,版本2中为1920×1080
  • 一个深度传感器 – v1中为320×240,v2中为512×424
  • 一个红外传感器 – v2中为512×424

这些传感器具有不同的分辨率,并且没有完美对齐,因此它们的视野区域有所不同。 显而易见的是,例如,RGB摄像头覆盖的区域比深度和红外摄像头更广。 此外,从一个摄像头可见的元素可能从其他摄像头不可见。 这就是不同传感器如何查看相同区域的方式

在此处观看视频.

一个示例

假设我们要在彩色图像之上投射人体关节。 人体跟踪是使用深度传感器执行的,因此身体点的坐标 (X, Y, Z) 仅与深度帧正确对齐。 如果您尝试将相同的身体关节坐标投射到彩色帧之上,您会发现骨骼完全错位

Kinect Coordinate Mapping wrong

CoordinateMapper (坐标映射器)

当然,微软意识到了这一点,因此SDK附带了一个方便的实用程序,名为 CoordinateMapperCoordinateMapper 的工作是识别来自3D空间的一个点是否对应于颜色或深度2D空间中的一个点——反之亦然。 CoordinateMapperKinectSensor 类的属性,因此它与每个 Kinect 传感器实例紧密相关。

使用 CoordinateMapper

让我们回到我们的例子。 这是访问人体关节坐标的 C# 代码

foreach (Joint joint in body.Joints)
{
    // 3D coordinates in meters
    CameraSpacePoint cameraPoint = joint.Position;
    float x = cameraPoint.X;
    float y = cameraPoint.Y;
    float z = cameraPoint.Z;
}

注意:请参阅我之前的文章(Kinect 版本 2:概述),了解如何找到身体关节。

这些坐标是 3D 点,打包到 CameraSpacePoint 结构中。 每个 CameraSpacePoint 都有 X、Y 和 Z 值。 这些值以 为单位测量。

视觉元素的尺寸以像素为单位测量,因此我们需要以某种方式将现实世界的 3D 值转换为 2D 屏幕像素。 Kinect SDK 提供了另外两个用于 2D 点的 structColorSpacePoint 和 DepthSpacePoint

使用 CoordinateMapper,将 CameraSpacePoint 转换为 ColorSpacePointDepthSpacePoint 非常容易

ColorSpacePoint colorPoint = _sensor.CoordinateMapper.MapCameraPointToColorSpace(cameraPoint);
DepthSpacePoint depthPoint = _sensor.CoordinateMapper.MapCameraPointToDepthSpace(cameraPoint);

这样,一个 3D 点就被映射到一个 2D 点,因此我们可以将其投射到颜色 (1920×1080) 和深度 (512×424) 位图之上。

如何绘制关节?

您可以使用 Canvas 元素、DrawingImage 对象或您喜欢的任何其他方式绘制关节。

这是您可以在 Canvas 上绘制关节的方式

public void DrawPoint(ColorSpacePoint point)
{
    // Create an ellipse.
    Ellipse ellipse = new Ellipse
    {
        Width = 20,
        Height = 20,
        Fill = Brushes.Red
    };

    // Position the ellipse according to the point's coordinates.
    Canvas.SetLeft(ellipse, point.X - ellipse.Width / 2);
    Canvas.SetTop(ellipse, point.Y - ellipse.Height / 2);

    // Add the ellipse to the canvas.
    canvas.Children.Add(ellipse);
}

类似地,您可以在深度帧之上绘制一个 DepthSpacePoint。 您还可以在两个点之间绘制骨骼(线条)。 这是完美坐标映射在彩色图像之上的结果

Kinect Coordinate Mapping right

注意:请参阅我之前的文章(Kinect v2 颜色、深度和红外流),了解如何创建相机位图。

从 GitHub 下载源代码并享受

在本教程中,我使用了 Kinect for Windows 版本 2 代码,但是,所有内容也适用于较旧的传感器和 SDK 1.8。 以下是您应该注意的相应类和结构名称。 如您所见,关于所用命名约定有一些小的更改,但核心功能是相同的。

版本 1 版本 2
SkeletonPoint CameraSpacePoint
ColorImagePoint ColorSpacePoint
DepthImagePoint DepthSpacePoint
© . All rights reserved.