和其他摄像机一样,近红外摄像机也有视场。Kinect摄像机的视野是有限的,如下图所示:

如图,红外摄像机的视场是金字塔形状的。离摄像机远的物体比近的物体拥有更大的视场横截面积。这意味着影像的高度和宽度,比如640X480和摄像机视场的物理位置并不一一对应。但是每个像素的深度值是和视场中物体离摄像机的距离是对应的。深度帧数据中,每个像素占16位,这样BytesPerPixel属性,即每一个像素占2个字节。每一个像素的深度值只占用了16个位中的13个位。如下图:

获取每一个像素的距离很容易,但是要直接使用还需要做一些位操作。可能大家在实际编程中很少情况会用到位运算。如上图所示,深度值存储在第3至15位中,要获取能够直接使用的深度数据需要向右移位,将游戏者索引(Player Index)位移除。后面将会介绍游戏者索引位的重要性。下面的代码简要描述了如何获取像素的深度值。代码中pixelData变量就是从深度帧数据中获取的short数组。PixelIndex基于待计算像素的位置就算出来的。SDK在DepthImageFrame类中定义了一个常量PlayerIndexBitmaskWidth,它定义了要获取深度数据值需要向右移动的位数。在编写代码时应该使用这一常量而不是硬编码,因为未来随着软硬件水平的提高,Kinect可能会增加能够同时识别人数的个数,从而改变PlayerIndexBitmaskWidth常量的值。

 Int32 pixelIndex = (Int32)(p.X + ((Int32)p.Y * frame.Width));
Int32 depth = this.depthPixelDate[pixelIndex] >> DepthImageFrame.PlayerIndexBitmaskWidth;

显示深度数据最简单的方式是将其打印出来。我们要将像素的深度值显示到界面上,当鼠标点击时,显示鼠标点击的位置的像素的深度值。第一步是在主UI界面上添加一个TextBlock:

<Window x:Class="KinectDepthImageDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="KinectDepthImage" Height="" Width="" WindowStartupLocation="CenterScreen">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="PixelDepth" FontSize="" HorizontalAlignment="Left" />
<Image x:Name="DepthImage" Width="" Height="" ></Image>
</StackPanel>
</Grid>
</Window>

接着我们要处理鼠标点击事件。在添加该事件前,需要首先添加一个私有变量lastDepthFrame来保存每一次DepthFrameReady事件触发时获取到的DepthFrame值。因为我们保存了对最后一个DepthFrame对象的引用,所以事件处理代码不会马上释放该对象。然后,注册DepthFrame 图像控件的MouseLeftButtonUp事件。当用户点击深度图像时,DepthImage_MouseLeftButtonUp事件就会触发,根据鼠标位置获取正确的像素。最后一步将获取到的像素值的深度值显示到界面上,代码如下:

void kinectSensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
if (lastDepthFrame!=null)
{
lastDepthFrame.Dispose();
lastDepthFrame = null;
}
lastDepthFrame = e.OpenDepthImageFrame();
if (lastDepthFrame != null)
{
depthPixelDate = new short[lastDepthFrame.PixelDataLength];
lastDepthFrame.CopyPixelDataTo(depthPixelDate);
depthImageBitMap.WritePixels(depthImageBitmapRect, depthPixelDate, depthImageStride, );
}
}
private void DepthImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(DepthImage);
if (depthPixelDate != null && depthPixelDate.Length > )
{
Int32 pixelIndex = (Int32)(p.X + ((Int32)p.Y * this.lastDepthFrame.Width));
Int32 depth = this.depthPixelDate[pixelIndex] >> DepthImageFrame.PlayerIndexBitmaskWidth;
Int32 depthInches = (Int32)(depth * 0.0393700787);
Int32 depthFt = depthInches / ;
depthInches = depthInches % ;
PixelDepth.Text = String.Format("{0}mm~{1}'{2}", depth, depthFt, depthInches);
}
}

有一点值得注意的是,在UI界面中Image空间的属性中,宽度和高度是硬编码的。如果不设置值,那么空间会随着父容器(From窗体)的大小进行缩放,如果空间的长宽尺寸和深度数据帧的尺寸不一致,当鼠标点击图片时,代码就会返回错误的数据,在某些情况下甚至会抛出异常。像素数组中的数据是固定大小的,它是根据DepthImageStream的Enable方法中的DepthImageFormat参数值来确定的。如果不设置图像控件的大小,那么他就会根据Form窗体的大小进行缩放,这样就需要进行额外的计算,将鼠标的在Form中的位置换算到深度数据帧的维度上。这种缩放和空间转换操作很常见,在后面的文章中我们将会进行讨论,现在为了简单,对图像控件的尺寸进行硬编码。

结果如下图,由于截屏时截不到鼠标符号,所以用红色点代表鼠标位置,下面最左边图片中的红色点位于墙上,该点距离Kinect 2.905米,中间图的点在我的手上,可以看出手离Kinect距离为1.221米,实际距离和这个很相近,可见Kinect的景深数据还是很准确的。

上面最右边图中白色点的深度数据为-1mm。这表示Kinect不能够确定该像素的深度。在处理上数据时,这个值通常是一个特殊值,可以忽略。-1深度值可能是物体离Kinect传感器太近了的缘故。

Kinect 深度测量原理的更多相关文章

  1. Kinect for Windows SDK开发入门(四):景深数据处理 上

    原文来自:http://www.cnblogs.com/yangecnu/archive/2012/04/04/KinectSDK_Depth_Image_Processing_Part1.html ...

  2. Kinect 开发 —— 硬件设备解剖

    Kinect for Xbox: 360 不支持“近景模式” 三只眼睛 —— 红外投影机,RGB摄像头,红外深度投影头  —— 色彩影像中的每个像素分别与深度影像中的一个像素对应 四只耳朵 —— L形 ...

  3. Kinect v2控制鼠标原理分析和源码

    https://blog.csdn.net/baolinq/article/details/54381284 此程序为利用Kinect v2实现用手指隔空控制鼠标,是我另一个项目的一部分,因为在另外那 ...

  4. C#动手实践:Kinect V2 开发(2):数据源工作原理及红外源Demo

    Kinect体系架构

  5. 使用HTML5开发Kinect体感游戏

    一.简介 我们要做的是怎样一款游戏? 在前不久成都TGC2016展会上,我们开发了一款<火影忍者手游>的体感游戏,主要模拟手游章节<九尾袭来 >,用户化身四代,与九尾进行对决, ...

  6. Kinect for Windows SDK开发入门(十九):Kinect Fusion

        Kinect for Windows SDK1.7中引入了Kinect Fusion功能.在1.8的SDK中对该功能进行了改进和强化,Kinect Fusion能够使得我们使用Kinect f ...

  7. Kinect 总结---Kinect基本认识

    玩了Kinect也有差不多一年的时间了,觉得Kinect是个挺好玩挺有未来的玩意.但是很经常做完了一次,下次又得重新看源码,没有把Kinect里的知识总结起来变为自己的知识,所以特意重新总结一下自己使 ...

  8. 利用Kinect将投影变得可直接用手操控

    Finally 总算是到了这一天了!假期里算法想不出来,或者被BUG折磨得死去活来的时候,总是YY着什么时候能心情愉快地坐在电脑前写一篇项目总结,今天总算是抽出时间来总结一下这神奇的几个月. 现在回过 ...

  9. 【翻译】Kinect v2程序设计(C++) Depth编

    Kinect SDK v2预览版,取得Depth数据的方法说明. 上一节,介绍了通过使用Kinect for Windows SDK v2预览版(以下简称为,Kinect SDK v2预览版)从Kin ...

随机推荐

  1. GCE 部署 ELK 7.1可视化分析 nginx

    目录 一.准备 1.1.服务器环境准备 二.安装 ES 2.1.遇到小问题 三.安装 Kibana 四.安装 Logstash 一.准备 我这边有一个网站放在了 Google VM 上面,所以打算在购 ...

  2. WhatsApp Group vs WhatsApp Broadcast for Business

    WhatsApp Group vs WhatsApp Broadcast for Business By Iaroslav Kudritskiy If you've read our Ultimate ...

  3. POJ2513 【并查集+欧拉路径+trie树】

    题目链接:http://poj.org/problem?id=2513 Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total ...

  4. hanlp分词工具应用案例:商品图自动推荐功能的应用

    本篇分享一个hanlp分词工具应用的案例,简单来说就是做一图库,让商家轻松方便的配置商品的图片,最好是可以一键完成配置的. 先看一下效果图吧: 商品单个推荐效果:匹配度高的放在最前面 这个想法很好,那 ...

  5. flink两种安装方式

    Flink Standalone 集群 HA 配置 1. HA 集群环境规划 使用三台节点实现两主两从集群(由于笔记本性能限制,不能开启太多虚拟机,其实使用三 台和四台机器在安装配置上没有本质区别) ...

  6. [游戏复刻] Super Mario Brothers(1985. Famicom)

    10/20 第一版,导入了地图,设置了碰撞块

  7. 小白学PYTHON时最容易犯的6个错误

    最近又在跟之前的同学一起学习python,一起进步,发现很多测试同学在初学python的时候很容易犯一些错误,特意总结了一下.其实这些错误不仅是在学python时会碰到,在学习其他语言的时候也同样会碰 ...

  8. Scrapy爬虫-win7下创建运行项目

    开始的时候,我只安装了python3.5,安装不了scrapy库,网上搜了一下说是scrapy不支持python3.x 然后,我就又安装了python2.7 为了,默认使用2.7,我在环境变量path ...

  9. Go-函数高级使用-条件分支-包管理-for循环-switch语句-数组及切片-与或非逻辑符

    目录 科普 python 注释 # 函数高级 if else if else 包管理 下载第三方包 比较热门的框架 for 循环 for 循环的几种写法 switch 语句 数组及数组切片 数组迭代 ...

  10. cygwin gcc 编译windowsAPI 报错的一个解决方案

    一开始按照linux的习惯去编译一个使用了windowsAPI的程序 结果提示: $ i686-pc-cygwin-g++ screen_catch.cscreen_catch.c: In funct ...