Kinect 开发 —— 近距离探测
如何将Kinect设备作为一个近距离探测传感器。为了演示这一点,我们处理的场景可能在以前看到过。就是某一个人是否站在Kinect前面,在Kinect前面移动的是人还是什么其他的物体。当我们设置的触发器超过一定的阈值,我们就发起另一个处理线程。类似的触发器如当用户走进房间时,我们打开房间里面的灯。对于商业广告系统,当展示牌前面没有人时,可以以“attract”模式展现内容,而当人靠近展示牌时,则展现一些更多的可供交互的内容。和仅仅编写交互性强的应用程序不同,我们可以编写一些能够感知周围环境的应用程序。
Kinect甚至可以被我们改造成一个安全的摄像头,当某些重要的特征发生时,我们可以记录下Kinect看到的景象。在晚上,我在门前放了一些食物,住在哪儿的猫可以吃到。最近我开始怀疑有其他的动物在偷吃我们家猫的食物。我将Kinect作为一个运动探测和视频录像机放在门口,这样就可以知道真实发生的情况了。如果你喜欢一些自然景像,你可以通过简单的设置来实现长时间的录像来获取其他动物的出现情况。虽然在探测到有动物靠近时开启视频影像录制可以节省磁盘空间,但是识别有动物靠近可能需要花费很长的时间。如果像我这样,你可以打开影像录制功能,这样你能够看到长时间的景象变化,比如风吹叶落的声音。Kinect作为一种显示增强的工具,其不仅仅可以作为应用程序的输入设备,一些新的Kinect的可能应用正在迅速发掘出来。
简单的近距离探测
建立一个近距离探测应用,当有人站在Kinect设备前面时,打开视频影像录制。自然,当有用户进入到Kinect的视野范围时需要触发一些列的操作。最简单的实现近距离探测的方法是使用KinectSDK中的骨骼探测功能。
首先创建一个名为KinectProximityDetectionUsingSkeleton的WPF应用程序,添加Microsoft.Kinect.dll和对System.Drawing命名空间的引用。将ImageExtensions.cs类文件拷贝到项目中,并添加对ImageManipulationExtensionMethods命名空间的引用。主界面元素非常简单,我们只是添加了一个名为rgbImage的Image对象来从Kinect影像数据中获取并显示数据。
<Grid >
<Image Name="rgbImage" Stretch="Fill"/>
</Grid>
下面的代码显示了一些初始化代码。大部分的代码都是在为Image提供数据源。在MainWindows的构造函数中,对_kinectSensor对象进行了初始化,并注册影像数据流和骨骼数据流响应事件。这部分代码和以前我们写的代码类似。所不同的是,我们添加了一个布尔型的_isTracking来表示是否我们的近距离探测算法识别到了有人进入视野。如果有,则更新影像数据流,更新image对象。如果没有,我们略过影像数据流,给Image控件的Source属性赋null值。
Microsoft.Kinect.KinectSensor _kinectSensor;
bool _isTracking = false; public MainWindow()
{
InitializeComponent(); this.Unloaded += delegate{
_kinectSensor.ColorStream.Disable();
_kinectSensor.SkeletonStream.Disable();
}; this.Loaded += delegate
{
_kinectSensor = Microsoft.Kinect.KinectSensor.KinectSensors[0];
_kinectSensor.ColorFrameReady += ColorFrameReady;
_kinectSensor.ColorStream.Enable(); _kinectSensor.Start();
};
} void ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{ if (_isTracking)
{
using (var frame = e.OpenColorImageFrame())
{
if (frame != null)
rgbImage.Source = frame.ToBitmapSource();
};
}
else
rgbImage.Source = null;
} private void OnDetection()
{
if (!_isTracking)
_isTracking = true;
} private void OnDetectionStopped()
{
_isTracking = false;
}
为了能够处理_isTracking标签,我们需要注册KienctSensor.SkeletonFrameReady事件。SkeletonFrameReady事件类似心脏跳动一样驱动程序的运行。只要有物体在Kinect前面,SkeletonFrameReady事件就会触发。在我们的代码中,我们需要做的是检查骨骼数据数组,判断数组中是否有骨骼数据处在追踪状态中。代码如下。
有时候我们不需要抛出事件。我们有一个内建的机制能够通知我们有人体进入到了Kinect视野范围内,但是,我们没有一个机制能够告诉在什么时候人走出了视野或者不在追踪状态。为了实现这一功能,不管是否探测到了用户,我们开启一个计时器,这个计时器的功能是存储最后一次追踪到的事件的时间,我们检查当前时间和这一时间的时间差,如果时差超过某一个阈值,就认为我们失去了对物体的追踪,我们应该结束当前的近距探测。
int _threshold = ;
DateTime _lastSkeletonTrackTime;
DispatcherTimer _timer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent(); this.Unloaded += delegate{
_kinectSensor.ColorStream.Disable();
_kinectSensor.SkeletonStream.Disable();
}; this.Loaded += delegate
{
_kinectSensor = Microsoft.Kinect.KinectSensor.KinectSensors[];
_kinectSensor.ColorFrameReady += ColorFrameReady;
_kinectSensor.ColorStream.Enable(); _kinectSensor.SkeletonFrameReady += Pulse;
_kinectSensor.SkeletonStream.Enable();
_timer.Interval = new TimeSpan(, , );
_timer.Tick += new EventHandler(_timer_Tick); _kinectSensor.Start();
};
}
void _timer_Tick(object sender, EventArgs e)
{ if (DateTime.Now.Subtract(_lastSkeletonTrackTime).TotalMilliseconds > _threshold)
{
_timer.Stop();
OnDetectionStopped();
}
} private void Pulse(object sender, SkeletonFrameReadyEventArgs e)
{
using (var skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame == null || skeletonFrame.SkeletonArrayLength == )
return; Skeleton[] skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons); for (int s = ; s < skeletons.Length; s++)
{
if (skeletons[s].TrackingState == SkeletonTrackingState.Tracked)
{
OnDetection(); _lastSkeletonTrackTime = DateTime.Now; if (!_timer.IsEnabled)
{
_timer.Start();
}
break;
}
}
}
}
使用景深数据进行近距离探测
使用骨骼追踪进行近距离探测是近距离探测的基础,当没有一个人进入到视野中,并进行交互时,电子广告牌进入“StandBy”模式,在这种情况下,我们只是简单的播放一些视频。不幸的是,骨骼追踪不能很好的捕捉类似在我家后面的门廊上的偷食物的浣熊或者是在旷野中的大脚野人的图像。这是因为骨骼追踪的算法是针对人类的关键特征以及特定的人体类型进行设计的。超出人体的范围,在Kinect镜头前骨骼追踪会失败或者是追踪会变的时断时续。
为了处理这一情况,我们可以使用Kinect的深度影像数据,而不能依靠骨骼追踪。深度影像数据也是近距离探测的一种基本类型。如下代码所示,程序运行中必须配置或者获取彩色影像和深度影像数据流,而不是骨骼数据流。
相比骨骼追踪数据,使用景深数据作为近距探测算法的基础数据有一些优点。首先只要传感器在运行,那么深度影像数据就是连续的。这避免了需要另外设置一个计时器来监控在探测过程是否意外终止。另外,我们可以对我们要探测的对象离Kinect的距离设置一个最小和最大的距离阈值。当物体离Kinect的距离比这个最小的阈值还要小,或者超过最大阈值的范围时,将_isTracking设置为false。下面的代码中,我们探测距离Kinect 1米至1.2米的对象。通过分析深度影像数据的每一个像素来判断是否有像元落在该距离范围内。如果有一个像元落在该范围内,那么停止对影像的继续分析,将isTracking设置为true。ColorFrameReady事件处理探测到物体的事件,然后使用彩色影像数据来更新image对象。
void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
bool isInRange = false;
using (var imageData = e.OpenDepthImageFrame())
{
if (imageData == null || imageData.PixelDataLength == )
return;
short[] bits = new short[imageData.PixelDataLength];
imageData.CopyPixelDataTo(bits);
int minThreshold = ;
int maxThreshold = ; for (int i = ; i < bits.Length; i += imageData.BytesPerPixel)
{
var depth = bits[i] >> DepthImageFrame.PlayerIndexBitmaskWidth; if (depth > minThreshold && depth < maxThreshold)
{
isInRange = true;
OnDetection();
break;
}
}
} if (!isInRange)
OnDetectionStopped();
}
相比骨骼数据,使用深度影像数据进行近距离探测的最后一个好处是速度较快。即使在比我们对景深数据处理更低的级别上进行骨骼追踪,骨骼追踪仍需要有完整的人体出现在Kinect视野中。同时Kinect SDK需要利用决策树分析整个人体影像数据,并将识别出来的结果和骨骼识别预设的一些特征参数进行匹配,以判断是否是人体而不是其他物体。使用景深影像数据算法,我们只需要查找是否有一个像元点落在指定的深度值范围内,而不用分析整个人体。和之前的骨骼追中算法不同,代码中深度值探测算法只要有物体落在Kinect传感器的视野范围内,都会触发OnDetection方法。
对近距离探测的改进
当然,使用景深数据进行近距离探测也有一些缺点。最小和最大深度阈值必须明确定义,这样才能避免_isTracking永远为true的情况。深度影像允许我们放松只能对人体进行近距离探测的这一限制,但是这一放松有点过了,使得即使一些静止不动的物体可能也会触发近距离探测。在实现一个运动测试来解决这一问题之前,我们可以实现一个探测条件不紧也不松的近距离探测。
下面的代码展示了如何结合深度影像数据中的深度值数据和游戏者索引位数据来实现一个近距离探测器。如果骨骼追踪算法符合你的需求,同时你又想将探测的对象限定在距离传感器的最大最小距离阈值范围内,这种方法是最好的选择。这在露天的广告牌中也很有用,比如可以在广告牌前设置一个区域范围。当有人进入到这一范围时触发交互。当人进入到距离装有Kinect的广告牌1米至1.5时触发另一种交互,当人离广告牌够近以至于可以触摸到时,触发另外一种交互。要建立这种类型的近距离探测,需要在MainWindows的构造函数中开启骨骼追踪功能,使得能够使用景深影像的深度数据和游戏者索引位数据。这些都做好了之后,可以改写之前例子中的DepthFrameReady事件,来对距离阈值进行判断,并检查是否有游戏者索引位数据存在。代码如下:
void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
bool isInRange = false;
using (var imageData = e.OpenDepthImageFrame())
{
if (imageData == null || imageData.PixelDataLength == )
return;
short[] bits = new short[imageData.PixelDataLength];
imageData.CopyPixelDataTo(bits);
int minThreshold = ;
int maxThreshold = ; for (int i = ; i < bits.Length; i += imageData.BytesPerPixel)
{
var depth = bits[i] >> DepthImageFrame.PlayerIndexBitmaskWidth;
var player = bits[i] & DepthImageFrame.PlayerIndexBitmask; if (player > && depth > minThreshold && depth < maxThreshold)
{
isInRange = true;
OnDetection();
break;
}
}
} if(!isInRange)
OnDetectionStopped();
}
Kinect 开发 —— 近距离探测的更多相关文章
- Kinect 开发 —— ColorBasic
创建一个Kincet项目通常需要: 1. 创建一个VS项目,一般为了展示通常创建一个wpf项目. 2. 添加Microsoft.Kinect.dll引用,如果是早期版本的SDK,这个名称可能不同. 3 ...
- Kinect开发文章目录
整理了一下去年为止到现在写的和翻译的Kinect的相关文章,方便大家查看.另外,最近京东上微软在搞活动, 微软 Kinect for Windows 京东十周年专供礼包 ,如果您想从事Kinect开发 ...
- Kinect开发资源汇总
Kinect开发资源汇总 转自: http://www.sigvc.org/bbs/forum.php?mod=viewthread&tid=254&highlight=kinec ...
- Kinect开发学习笔记之(一)Kinect介绍和应用
Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...
- Kinect开发笔记之二Kinect for Windows 2.0新功能
这是本博客翻译文档的第一篇文章.笔者已经苦逼的竭尽全力的在翻译了.但无奈英语水平也是非常有限.不正确或者不妥当不准确的地方必定会有,还恳请大家留言或者邮件我以批评指正.我会虚心接受. 谢谢大家. ...
- Kinect 开发 —— 杂一
Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime ...
- Kinect 开发 —— 控制PPT播放
实现Kinect控制幻灯片播放很简单,主要思路是:使用Kinect捕捉人体动作,然后根据识别出来的动作向系统发出点击向前,向后按键的事件,从而使得幻灯片能够切换. 这里的核心功能在于手势的识别,我们在 ...
- Kinect 开发 —— 全息图
Kinect的另一个有趣的应用是伪全息图(pseudo-hologram).3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动.如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用 ...
- Kinect 开发 —— 进阶指引(上)
本文将会介绍一些第三方类库如何来帮助处理Kinect传感器提供的数据.使用不同的技术进行Kinect开发,可以发掘出Kinect应用的强大功能.另一方面如果不使用这些为了特定处理目的而开发的一些类库, ...
随机推荐
- angular route 与 django urls 冲突怎么解决?
app.js var app = angular.module('app', [ 'ngResource', 'ngRoute', // 'ui.bootstrap', // 'ngResource' ...
- mybatis如何成功插入后获取自增长的id
使用mybatis向数据库中插入一条记录,如何获取成功插入记录的自增长id呢? 需要向xml配置中加上一下两个配置: <insert id="add" useGenerate ...
- Mojo For Chromium Developers1
Mojo For Chromium Developers Overview This document contains the minimum amount of information neede ...
- JS文字特效:彩色滚动变幻效果,只适合少量的文字。(过多对页面有影响)
JS代码如下: 代码具体是在哪里的我不知道但是我的有道云上有.如有哪位朋友知道,还望联系下,添加出处. <div id="chakhsu"></div> & ...
- PostgreSQL指定用户可访问的数据库pg_hba.conf
进入指定目录: # cd /var/lib/pgsql/9.3/data/ 使用vi编辑pg_hba.conf文件 # vi pg_hba.conf 以上配置为所有IP及网关都允许访问,使用MD5认证 ...
- unity SystemInfo类 获得电量battery
我觉得用Unity 开发最爽的地方, 不是unity跨平台,而是用其他语言,要用很复杂的逻辑才能完成的功能,unity用一两句代码就能搞定 就比如说获取Android 系统的电量,不用发广播,不用申请 ...
- 题解 CF327C 【Magic Five】
这道题带坑,假如没有发现肯定会爆. 首先先搜索一遍0和5,储存在数组a里面. 那么应当有2 ^ a1 +2 ^ a2 +...+ 2 ^ an. 然而这道题没那么简单,数串还可以重复k次. 因此,需要 ...
- Hadoop学习总结(1)——大数据以及Hadoop相关概念介绍
一.大数据的基本概念 1.1.什么是大数据 大数据指的就是要处理的数据是TB级别以上的数据.大数据是以TB级别起步的.在计算机当中,存放到硬盘上面的文件都会占用一定的存储空间,例如: 文件占用的存储空 ...
- BZOJ3875: [Ahoi2014&Jsoi2014]骑士游戏
[传送门:BZOJ3875] 简要题意: 给出n种怪物,每种怪物都带有三个值,S[i],K[i],R[i],分别表示对他使用普通攻击的花费,使用魔法攻击的花费,对他使用普通攻击后生成的其他怪物. 每种 ...
- vue --- cli build 后的项目,图片路径出错
今天在插入背景图片过程中,遇到了路径错误的问题,通过网上查询,找到了解决的办法,但是大部分都没有讲造成这种问题的原因,故我简单地总结了一下,并加入了一些自己的理解,欢迎共同探讨~ 当用vue-cli自 ...