使用 Kinect 进行地面检测
使用 Kinect 进行地面检测
Kinect 主要用于身体和面部追踪应用。但很少有人知道,Kinect 也是一个非常出色的地面检测传感器!
原生的 Kinect SDK 为我们提供了准确识别 3D 空间中特定平面是否为地面的所有必要信息。我们还可以获取 Kinect 传感器安装的高度等信息。我们甚至可以测量 3D 空间中一点到地面的距离。所有这些信息都可能对现代增强现实应用产生巨大影响。
在今天的教程中,我将向您展示以下内容:
- 如何检测地面裁剪平面
- 如何估算 Kinect 传感器的高度
- 如何测量一个点到地面的距离
这是我们将要开发的应用程序的快照
必备组件
要运行本文提供的代码和示例,您需要以下组件:
- Kinect for XBOX v2 传感器及适配器(或Kinect for Windows v2 传感器)
- Kinect for Windows v2 SDK
- Windows 8.1 或更高版本
- Visual Studio 2013 或更高版本
- 专用的 USB 3 端口
源代码
演示的源代码托管在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 日:初始版本