读书人

Kinect for Windows SDK开发入门(五):

发布时间: 2012-10-10 13:58:11 作者: rapoo

Kinect for Windows SDK开发入门(五):景深数据处理 下

1. 简单的景深影像处理

在上篇文章中,我们讨论了如何获取像素点的深度值以及如何根据深度值产生影像。在之前的例子中,我们过滤掉了阈值之外的点。这就是一种简单的图像处理,叫阈值处理。使用的阈值方法虽然有点粗糙,但是有用。更好的方法是利用机器学习来从每一帧影像数据中计算出阈值。Kinect深度值最大为4096mm,0值通常表示深度值不能确定,一般应该将0值过滤掉。微软建议在开发中使用1220mm(4’)~3810mm(12.5’)范围内的值。在进行其他深度图像处理之前,应该使用阈值方法过滤深度数据至1220mm-3810mm这一范围内。

使用统计方法来处理深度影像数据是一个很常用的方法。阈值可以基于深度数据的平均值或者中值来确定。统计方法可以帮助确定某一点是否是噪声、阴影或者是其他比较有意义的物体,比如说用户的手的一部分。有时候如果不考虑像素的视觉意义,可以对原始深度进行数据挖掘。对景深数据处理的目的是进行形状或者物体的识别。通过这些信息,程序可以确定人体相对于Kinect的位置及动作。

1.1深度影像数据直方图

直方图是统计数据分布的一个很有效的工具。在这里我们关心的是一个景深影像图中深度值的分布。直方图能够直观地反映给定数据集中数据的分布状况。从直方图中,我们能够看出深度值出现的频率以及聚集分组。通过这些信息,我们能够确定阈值以及其他能够用来对图像进行过滤的指标,使得能够最大化的揭示深度影像图中的深度信息。为了展示这一点,接下来我们将会展示一副景深影像数据的直方图,并通过直方图,使用一些简单的技术来过滤掉我们不想要的像素点。

首先创建一个新的项目。然后根据之前文章中讲的步骤发现和初始化KinectSensor对象来进行深度影像数据处理,包括注册DepthFrameReady事件。在添加实现深度直方图之前,将UI界面更改为如下:

<Window x:Class="KinectDepthHistogram.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="MainWindow" Height="800" Width="1200" WindowStartupLocation="CenterScreen">    <Grid>        <StackPanel>            <StackPanel Orientation="Horizontal">                <Image x:Name="DepthImage" Width="640" Height="480" />                <Image x:Name="FilteredDepthImage" Width="640" Height="480" />            </StackPanel>            <ScrollViewer Margin="0,15" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">                <StackPanel x:Name="DepthHistogram" Orientation="Horizontal" Height="300" />            </ScrollViewer>        </StackPanel>    </Grid></Window>

创建直方图的方法很简单,就是创建一系列的矩形元素,然后将它添加到名为DepthHistogram的StackPanel元素中,由于DepthHistogram对象的Orientation属性设置为Horizontal,所以这些矩形会水平排列。大多数应用程序计算直方图只是用来进行中间过程处理用,如果想要将直方图展现出来,则需要在绘图上面做些工作。下面的代码展现了如何绘制直方图:

private void KinectDevice_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e){    using (DepthImageFrame frame = e.OpenDepthImageFrame())    {        if (frame != null)        {            frame.CopyPixelDataTo(this._DepthPixelData);            CreateBetterShadesOfGray(frame, this._DepthPixelData);            CreateDepthHistogram(frame, this._DepthPixelData);        }    }}private void CreateDepthHistogram(DepthImageFrame depthFrame, short[] pixelData){    int depth;    int[] depths = new int[4096];    double chartBarWidth = Math.Max(3, DepthHistogram.ActualWidth / depths.Length);    int maxValue = 0;    DepthHistogram.Children.Clear();    //计算并获取深度值.并统计每一个深度值出现的次数    for (int i = 0; i < pixelData.Length; i++)    {        depth = pixelData[i] >> DepthImageFrame.PlayerIndexBitmaskWidth;        if (depth >= LoDepthThreshold && depth <= HiDepthThreshold)        {            depths[depth]++;        }    }    //查找最大的深度值    for (int i = 0; i < depths.Length; i++)    {        maxValue = Math.Max(maxValue, depths[i]);    }    //绘制直方图    for (int i = 0; i < depths.Length; i++)    {        if (depths[i] > 0)        {            Rectangle r = new Rectangle();            r.Fill = Brushes.Black;            r.Width = chartBarWidth;            r.Height = DepthHistogram.ActualHeight * (depths[i] / (double)maxValue);            r.Margin = new Thickness(1, 0, 1, 0);            r.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;            DepthHistogram.Children.Add(r);        }    }}

绘制直方图时,创建一个数组来存储所有可能的深度值数据,因此数组的大小为4096。第一步遍历深度图像,获取深度值,然后统计深度值出现的次数。因为设置了最高最低的距离阈值,忽略了0值。下图显示了深度值影像的直方图,X轴表示深度值,Y轴表示深度值在图像中出现的次数。

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

当站在Kinect前后晃动时,下面的直方图会不停的变化。图中后面最长的几个线条表示墙壁,大约离摄像头3米左右,前面的几个小的线条是人体,大概离摄像头2米左右,下面那副图中,我手上拿了一个靠垫,可以发现直方图与之前的直方图相比发生了一些变化。

这两幅图中,可以看到直方图都集中在两个地方,前面的一小撮和后面的那一大坨。所以根据直方图可以看出,前面那个表示人体,后面那个代表房间的墙壁,在结合一些图像处理技术,就大致可以把人体和背景区分开来了。

1.2 一些图像处理相关的知识

本文不打算详细讲解图像处理的相关知识。只是讨论如何获取原始的深度数据,以及理解数据的用途。很多情况下,基于Kinect的应用程序不会对深度数据进行很多处理。如果要处理数据,也应该使用一些类库诸如OpenCV库来处理这些数据。深度影像处理经常要耗费大量计算资源,不应该使用诸如C#这类的高级语言来进行影像处理。

Note: OpenCV(Open Source Computer Vision)库是是一个经常用来处理和计算影像数据的算法类库。这个类库也包含点云库(Point Cloud Library, PCL) 和机器人操作系统(Robot Operating System, ROS),这些都涉及到了大量的深度数据处理。有兴趣的可以研究一下OpenCV库。

应用程序处理深度数据目的是用来确定人体在Kinect视场中的位置。虽然Kinect SDK中的骨骼追踪在这方面功能更强大,但是在某些情况下还是需要从深度数据中分析出人物所处的位置。在下节中,我们将会分析人体在深度影像中的范围。在开始之前,有必要了解和研究一下图像处理中常用的一些算法,有时候这些对特征提取非常有帮助。

读书人网 >windows

热点推荐