使用 Kinect 传感器识别坐姿






4.78/5 (11投票s)
识别专注、不专注、睡觉和举手姿势。
引言
许多专家预测,不久的将来,信息技术将迎来一场新的革命。这场革命将与计算机分割、跟踪和理解人类姿势、手势和情感表达的新能力有关。为此,计算机必须开始使用新型视频传感器来提供3D视频。Kinect传感器就是这类新型传感器中的第一个。Kinect传感器有两个摄像头:一个传统的彩色视频摄像头和一个测量深度、位置和运动的红外线传感器。Kinect传感器大约在一年前作为Xbox 360游戏系统的传感器推出,但几乎立即就有许多软件开发人员开始尝试使用它来识别人类姿势和手势。有关更多信息,请访问www.kinecthacks.com。
我的文章致力于坐姿识别的研究。坐姿识别基于人体骨骼跟踪。有三个软件包可以使用Kinect传感器进行人体骨骼跟踪:OpenNi/PrimeSense Nite库、Microsoft Kinnect Research SDK和Libfreenet库。我使用了前两个。在此基础上,我开发了C# WPF应用程序,并将彩色视频流和骨骼图像结合起来。
这些应用程序运行在Microsoft Windows 7和.NET Framework 4.0下。编译它们需要Microsoft Visual Studio 2010。你可以在www.kinecthacks.com上找到安装OpenNi/PrimeSense Nite库和Microsoft Kinect Research SDK的说明。
背景
坐姿识别算法基于人体骨骼跟踪,并获取人体肩部(S)、臀部(H)和膝盖(K)位置的三维坐标(xs, ys, zs)、(xh, yh, zh)和(xk, yk, zk)。
坐姿与臀部到膝盖的连线HK和臀部到肩部的连线HS之间的角度a有关。
我们将区分左侧身体部分的角度a——“中心臀部到左膝”向量与“中心臀部到中心肩部”向量之间的角度,以及右侧身体部分的角度a——“中心臀部到左膝”向量与“中心臀部到中心肩部”向量之间的角度。
根据角度a和手部姿势,可以得出并分类人体坐姿为以下四种类型之一:睡觉、专注、举手和不专注,如下表所示。
角度a | 手部姿势 | 坐姿 |
0 ~ 40 | down | 睡觉 |
40~80 | down | 不专注 |
80~100 | down | 专注 |
up | 举手 | |
100~180 | down | 不专注 |
Using the Code
我在组合彩色视频流和骨骼图像时遇到了两个问题。
第一个问题是如何在一个窗口的同一个控件中简单地定位它们。为此,我为两个应用程序都使用了一个简单的WPF窗体,其中包含一个StatusBar
控件和一个Grid
面板。Grid
面板包含一个大小相同的Image
控件和一个Canvas
控件。
<Window x:Class="RecognitionPose.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="User tracking with Microsoft SDK" Height="600"
Width="862" Loaded="Window_Loaded"
DataContext="{Binding}">
<DockPanel LastChildFill="True">
<StatusBar Name="statusBar"
MinHeight="40" DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock Name="textBlock"
Background="LemonChiffon"
FontSize='10'> Ready </TextBlock>
</StatusBarItem>
</StatusBar>
<Grid DockPanel.Dock="Top">
<Image Name="imgCamera" Width="820"
ClipToBounds="True" Margin="10,0" />
<Canvas Width="820" Height="510"
Name="skeleton" ClipToBounds="True"/>
</Grid>
</DockPanel>
</Window>
处理OpenNI/PrimeSense Nite和Microsoft SDK的第二个问题是刷新视频帧和骨骼帧的事件不是同步发生的。
针对这个问题,对于Microsoft SDK的情况,我在SkeletonFrameReady
事件处理程序中,在imgCamera
和骨骼控件刷新后,调用我Recognition
类的主方法RecognizePose
。SkeletonFrameRead
事件处理程序通过将当前视频帧复制到平面图像临时变量来简单地与VideoFrameReady
事件处理程序同步。
planarImage = ImageFrame.Image;
然后在SkeletonFrameReady
事件处理程序中,将此临时变量复制到imgCamera.Source
。
imgCamera.Source = BitmapSource.Create(planarImage.Width, planarImage.Height,
194,194,PixelFormats.Bgr32, null, planarImage.Bits,
planarImage.Width * planarImage.BytesPerPixel);
对于OpenNi/PrimeSense Nite的情况,我使用NuiVision库https://codeproject.org.cn/Articles/169161/Kinect-and-WPF-Complete-body-tracking(由Vangos Pterneas撰写)来同步视频帧和骨骼识别事件。我在该库的UsersUpdated
事件处理程序中调用RecognizePose
方法。
对于坐姿识别,主要问题是找到人体相对于Kinect传感器的距离和角度,在此范围内识别是稳定的。为此,我在应用程序设置中添加了五个参数来控制算法的行为:
isDebug
-如果为true,则在状态栏上显示当前人体位置的信息;confidenceAngle
-控制左右两侧身体角度a之间的差异;如果该角度大于给定级别,我们假设识别不稳定。standPoseFactor
-控制坐姿和站姿之间的差异;如果当前人体高度乘以该因子大于站姿时的初始人体高度,我们假设当前姿势也是站姿。isAutomaticChoiceAngle
-在自动定义角度a(选择最接近摄像头的角度,为true)和计算左右两侧身体角度a的平均值(为false)之间进行选择;shiftAngle
-从角度a中减去一个角度偏移量,以消除骨骼识别错误。
我发现最稳定的坐姿识别发生在这些参数取以下值时:
confidenceAngle=50度;
standPoseFactor=1.1;
isAutomaticChoiceAngle=true;
shiftAngle=20。
Kinect传感器放置在地面上,Kinect传感器与坐着的人体之间的距离约为2米,人体相对于传感器的旋转角度为45度。
坐姿人体位置的优点是,Kinect传感器可以持续跟踪识别所需的人体部位:
- 两个膝盖;
- 一个臀部;
- 两个肩部;
- 两只手;
- head
对于其他人体位置,则并非如此。例如,对于正面位置,传感器实际上不跟踪臀部;对于侧面位置,传感器只跟踪身体的一侧:右侧或左侧。
关注点
我制作了两个关于使用这两个应用程序的视频。
- http://www.youtube.com/watch?v=OIoVTSreR0w(使用Microsoft Research Kinect SDK进行识别)
- http://www.youtube.com/watch?NR=1&v=1-etFuPg7J4(使用PrimeSense Nite库进行识别)
从视频中可以看出,这两个软件包的识别效果都很好。然而,通过扩大识别稳定的坐姿人体位置区域,这些应用程序可以得到显著的改进。为此,我们必须使用两个或更多Kinect传感器,而不是一个。
我认为这些应用程序可以用于任何需要控制坐姿下的人体行为的领域。对于人体状态变得不专注或睡觉的情况,可以通过添加一些反馈来增强应用程序,例如发送警报、通知或紧急信号。另一方面,这些应用程序可用于大学收集学生在研讨会和实验室期间活动情况的统计数据。这些应用程序将计算学生在研讨会期间专注或不专注的平均时间,他们举手的次数,并且教授可以在与学生的个人工作中利用这些统计数据。