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

使用 Kinect 进行地面检测

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2019 年 1 月 28 日

CPOL

4分钟阅读

viewsIcon

8486

使用 Kinect 进行地面检测

Kinect 主要用于身体和面部追踪应用。但很少有人知道,Kinect 也是一个非常出色的地面检测传感器!

原生的 Kinect SDK 为我们提供了准确识别 3D 空间中特定平面是否为地面的所有必要信息。我们还可以获取 Kinect 传感器安装的高度等信息。我们甚至可以测量 3D 空间中一点到地面的距离。所有这些信息都可能对现代增强现实应用产生巨大影响。

在今天的教程中,我将向您展示以下内容:

  • 如何检测地面裁剪平面
  • 如何估算 Kinect 传感器的高度
  • 如何测量一个点到地面的距离

这是我们将要开发的应用程序的快照

必备组件

要运行本文提供的代码和示例,您需要以下组件:

源代码

演示的源代码托管在GitHub上。此外,所有这些功能都是Vitruvius的一部分。Vitruvius 是最流行的 Kinect 框架,可以帮助您轻松创建 Kinect 应用。因此,如果您赶时间,只需下载 Vitruvius并将其集成到您的应用程序中即可。

检测地面裁剪平面

Kinect SDK 中已经内置了一些地面检测功能。请看 `FloorClipPlane` 属性。`FloorClipPlane` 是 `BodyFrame` 类的一个成员。很少有人知道它的存在,但它是开发运动应用程序时最有用的组件之一。

这是访问 `FloorClipPlane` 属性的方法

using (BodyFrame frame = e.FrameReference.AcquireFrame())
{
    if (frame != null)
    {
        Vector4 floorClipPlane = frame.FloorClipPlane;
    }
}

如您所见,`FloorClipPlane` 是一组 4 个浮点数值(`Vector4`):`X`、`Y`、`Z` 和 `W`。

  • `X`、`Y` 和 `Z` 值表示平面在 3D 空间中的方向。
  • `W` 值表示平面与坐标系原点之间的距离。

实际上,Vector4 结构表示平面的数学方程。您可以在Wolfram MathWorld上阅读更多相关信息。

在我们的示例中,我们将把 `FloorClipPlane` 向量封装到一个方便的 `Floor` C# 类中。

public class Floor
{
    public float X { get; internal set; }
    public float Y { get; internal set; }
    public float Z { get; internal set; }
    public float W { get; internal set; }

    public Floor(Vector4 floorClipPlane)
    {
        X = floorClipPlane.X;
        Y = floorClipPlane.Y;
        Z = floorClipPlane.Z;
        W = floorClipPlane.W;
    }
}

Kinect 传感器高度 – 神奇的 W

正如我们所见,`W` 值表示地面与坐标系原点之间的距离。Kinect 坐标系的原点是**设备本身**!因此,`FloorClipPlane` 的 `W` 参数描述了 Kinect 传感器所处的位置**高度**!

使用 `W` 值,您可以为用户提供反馈。

Vector4 floorClipPlane = frame.FloorClipPlane;
float height = floorClipPlane.W;

if (height < 1f) // 1 meter
{
    Debug.WriteLine("The sensor is positioned too low!");
}

视野

当 `W` 值为 `0` 时,表示视野受限。这是一种非常简单的方法来了解是否有任何物体(如桌子、椅子等)挡住了视野。

if (height == 0f)
{
    Debug.WriteLine("The field of view is limited.");
}

Kinect 传感器倾斜角度

除了检测传感器高度外,我们还可以检测设备的倾斜角度。我们只需要使用地面平面的方向即可。

public double Tilt
{
    get
    {
        return Math.Atan(Z / Y) * (180.0 / Math.PI);
    }
}

测量距离

在我之前的一篇文章中,我解释了如何使用简单的数学方程测量 3D 空间中两个点之间的距离

现在,我们需要测量 3D 空间中一个点到一个平面的距离。这比较棘手,但我们可以通过几何学轻松解决。

检测到的地面是一个已知距离(`W`)和方向(`X`、`Y`、`Z`)的平面。3D 空间中的一个点是一组 `X`、`Y` 和 `Z` 坐标。

// Plane (X, Y, Z, W)
Floor floor = new Floor(frame.FloorClipPlane);

// Point (X, Y, Z)
CameraSpacePoint point = body.Joints[JointType.WristLeft].Position;

要测量点到平面的距离,我们需要使用点到平面距离公式

我们如何将这个公式转化为编程代码?让我为您做数学计算。

public double DistanceFrom(CameraSpacePoint point)
{
   double numerator = X * point.X + Y * point.Y + Z * point.Z + W;
   double denominator = Math.Sqrt(X * X + Y * Y + Z * Z);

   return numerator / denominator;
}

将此方法添加到您的 *Floor.cs* 类中。这样就可以了!您现在可以获取任何点的 3D 位置,将其作为参数传递给上述方法,并找到它到地面的距离。

double distance = floor.DistanceFrom(point);

供您参考,这是完整的 *Floor.cs* 类。

public class Floor
{
    public float X { get; internal set; }
    public float Y { get; internal set; }
    public float Z { get; internal set; }
    public float W { get; internal set; }

    public Floor(Vector4 floorClipPlane)
    {
        X = floorClipPlane.X;
        Y = floorClipPlane.Y;
        Z = floorClipPlane.Z;
        W = floorClipPlane.W;
    }

    public float Height
    {
        get { return W; }
    }

    public double Tilt
    {
        get { return Math.Atan(Z / Y) * (180.0 / Math.PI); }
    }

    public double DistanceFrom(CameraSpacePoint point)
    {
        double numerator = X * point.X + Y * point.Y + Z * point.Z + W;
        double denominator = Math.Sqrt(X * X + Y * Y + Z * Z);

        return numerator / denominator;
    }
}

好了,各位!您现在可以使用 *Floor.cs* 类来实现很酷的功能!在我的 C# 示例代码中,我还添加了许多扩展方法,让您可以**绘制**地面点,甚至找到任何其他点的**投影**。

历史

  • 2019 年 1 月 28 日:初始版本
© . All rights reserved.