马宁的嵌入式开发研究

Windows Phone, XNA, Windows Embedded, Windows Mobile
posts - 80, comments - 676, trackbacks - 17, articles - 0

 

作者:马宁

Kinect SDK出来之后,不到24小时,很多Geek们已经将自己的示例发布到网上去了。可见,好东西肯定会被大家认可的,不好的东西投入再多的宣传也没用。

这一篇我们就要正式进入Kinect的编程世界了,介绍我们如何从Camera获取图像信息。先来介绍一下Kinect的整体结构,省得大家在后边的介绍中被某些名词弄晕。

image_thumb[3]

Kinect一共有三个Camera,其中中间的一个是RGB Camera,用来获取640x480的彩色图像,每秒钟最多获取30帧图像;两侧是两个景深(3D Depth)传感器,用来检测玩家的相对位置,原理和人眼立体成像是一样的,不过这两个传感器使用的是红外线,所以说奥巴马玩不了Kinect的人一定是居心叵测。Kinect两侧是麦克风,下边还有一个可移动底座,用来调整Kinect的仰角。

Kinect开发环境

今天我们主要是操作RGB Camera和Depth Sensor,首先,我们要完成Kinect开发环境的配置:

第一步,创建WPF工程

打开Visual Studio 2010,创建一个WPF工程,名叫KinectWpfDemo:

21

当然,由于Kinect SDK中包含基于.NET的程序集,除了WPF外,我们使用.NET WinForm或XNA框架都可以,目前还没有人在Silverlight平台上实验成功。

第二步,添加Kinect程序集的引用

在Solution Explorer中,右键单击KinectWpfDemo,在右键菜单中选择“Add Reference…”。在弹出的对话框中,我们在.NET标签页里,选择“Microsoft.Research.Kinect”程序集。如下图所示:

22

第三步,添加Coding4Fun Kinect Toolkit

这是一个可选项,不过为了之后的编程方便,建议大家添加一个。Coding4Fun Kinect Toolkit的下载地址:

http://c4fkinect.codeplex.com/

解压缩后,一共有五个文件,针对WinForm、WPF平台,还有一个Microsoft.Expression.Drawing.dll。我们通过Add Reference,将Coding4Fun.Kinect.Wpf.dll添加进来。

23

获取RGB Camera数据

第四步,添加控件

双击打开MainWindow.xaml,在设计器中添加两个Image控件,一个用于显示RGB图像,另一个用于显示Depth信息。

第五步,引用命名空间

打开MainWindow.xaml.cs文件,在文件头部添加对于Kinect对象的引用:

using Microsoft.Research.Kinect.Nui;

using Microsoft.Research.Kinect.Audio;

using Coding4Fun.Kinect.Wpf;

回到MainWindow.xaml的设计器中,在属性窗口中选择Event,找到Loaded和Closed两个方法,分别双击,添加两个事件的处理函数:

25

在MainWindow.xaml.cs文件的MainWindow类中,声明Runtime的变量:

Runtime nui;

然后,在Loaded事件的处理函数中添加Runtime初始化的代码:

private void Window_Loaded(object sender, RoutedEventArgs e)

{

nui = new Runtime();

nui.Initialize(RuntimeOptions.UseColor| RuntimeOptions.UseDepth | RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);

}

接下来是Closed事件中关闭Runtime的代码:

private void Window_Closed(object sender, EventArgs e)

{

nui.Uninitialize();

}

Runtime对象是Kinect SDK中最主要的一个类,所有针对Kinect的操作都由Runtime类进行了封装。Runtime的构造函数没有接受任何参数,但有一个显式的初始化函数Initialize,接受RuntimeOptions参数,指定调用Kinect的哪些功能。其中RuntimeOptions.UseColor表示使用RGB Camera,而RuntimeOptions.UseDepth则表示使用Depth传感器。

初始化工作完成之后,我们要通过RGB Camera来获取实时的图像数据了。我们首先要声明一个事件处理方法,来接收视频数据的信息:

nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);

然后是事件处理函数:

void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)

{

PlanarImage imageData = e.ImageFrame.Image;

image1.Source = BitmapSource.Create(imageData.Width, imageData.Height, 96, 96,

PixelFormats.Bgr32, null, imageData.Bits, imageData.Width * imageData.BytesPerPixel);

//image1.Source = e.ImageFrame.ToBitmapSource();

}

提示:Getting Started上提供的Sample Code有误,需要将最后一个参数中的data.Width改为imageData.Width才可以正常运行。

VideoFrameReady事件会传递一个ImageFrameReadyEventArgs参数给事件处理函数,其中的ImageFrame会包含关于图片的各种信息,比如Type变量指定了图像是来自RGB还是Depth,Resolution变量指定了分辨率,而Image中以byte[]数组的方式保存了图像的真实数据。

然后的工作就是根据PlanarImage中包括的数据来创建一个Bitmap对象,然后将其传递给Image控件,显示到WPF程序的界面上。

最后,我们还要在构造函数里打开视频流,来获取视频数据:

nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);

第一个参数是ImageStreamType,用来指定打开的设备流类型;第二个参数是PoolSize,指定缓冲区的数量,至少为2,保证一个Buffer进行绘制,另一个Buffer进行数据填充;第三个参数指定Camera的分辨率;第四个参数则是获取的图片类型。

显示效果如下图所示:

24 - Copy

上面的示例代码,没有使用Coding4Fun的Helper类,如果使用的话,则代码如下:

void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)

{

image1.Source = e.ImageFrame.ToBitmapSource();

e.ImageFrame.ToBitmapSource().Save("catpure.jpg", ImageFormat.Jpeg);

}

Helper类使用了C#的Extension Methods,为ImageFrame增加了一些转换方法。我们还可以将图像保存为文件,考虑到文件系统存储的效率文件,建议大家不用每张都存。

获取Depth信息

接下来我们要获取Depth信息了,过程与RGB Camera类似。首先要确保Runtime对象被初始化时,已经添加了RuntimeOptions.UseDepth的属性,否则设备无法正常打开。

然后,添加获取Depth数据的事件处理,并打开Depth的数据流,这次的分辨率是320x240:

nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrameReady);

nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.Depth);

下面是事件处理函数,在另外一个Image函数里,显示Depth图像:

void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)

{

image2.Source = e.ImageFrame.ToBitmapSource(); 

}

偷懒,所以使用了Coding4Fun的Helper类。程序运行的效果如下:

24

写到最后

这一篇中,我们完成了Kinect开发环境的配置、添加了Coding4Fun Kinect Toolkit、从RGB Camera和Depth Sensor中获取了图像信息。

接下来,我们就要进入Kinect动作捕捉部分了。

Feedback

#1楼  回复 引用 查看   

2011-06-18 19:47 by 李永京      
关注Kinect,希望楼主多多发文~~

#2楼[楼主]  回复 引用 查看   

2011-06-18 20:12 by 马宁      
谢谢,我会抽时间把整个系列写完的。我正琢磨着利用Kinect做点啥好玩的应用,一时还没有想法。不知道大家有什么好建议没有?

#3楼  回复 引用 查看   

2011-06-18 20:22 by Aga.J      
每次微软出了什么新东西,马宁老师都会先拿来练练..哈哈

#4楼  回复 引用 查看   

2011-06-18 20:26 by nothing better      
引用马宁:谢谢,我会抽时间把整个系列写完的。我正琢磨着利用Kinect做点啥好玩的应用,一时还没有想法。不知道大家有什么好建议没有?

想法会慢慢会有的别着急,希望楼主把系列文章写全,可以当作入门教学。

#5楼[楼主]  回复 引用 查看   

2011-06-18 20:27 by 马宁      
这次是蓄谋已久,年初就买了XBox Kinect的套装,后来还专门请同事从美国带回来一个USB转接口,本来想用OpenKinect,后来听说官方要出Kinect SDK,所以就等了几个月。
Kinect这项技术绝对会影响未来十年的IT行业,我们拭目以待吧。

#6楼  回复 引用 查看   

2011-06-18 21:14 by 装配脑袋      
有c++的sdk吧?

#7楼  回复 引用 查看   

2011-06-18 21:19 by BillGan      
"不好的东西投入再多的宣传也没用" 这个肯定说得极端了。

#8楼  回复 引用 查看   

2011-06-18 21:36 by nothing better      
引用马宁:
这次是蓄谋已久,年初就买了XBox Kinect的套装,后来还专门请同事从美国带回来一个USB转接口,本来想用OpenKinect,后来听说官方要出Kinect SDK,所以就等了几个月。
Kinect这项技术绝对会影响未来十年的IT行业,我们拭目以待吧。

麻烦问一下USB转接口是不是Kinect AC Adapter/ Power Supply 这个啊?

#9楼[楼主]  回复 引用 查看   

2011-06-18 21:54 by 马宁      
@nothing better
对,没错就是那个东西,我在上一篇文章里说过了。

#10楼[楼主]  回复 引用 查看   

2011-06-18 21:55 by 马宁      
@装配脑袋
有C++的SDK,基于COM接口的。

#11楼  回复 引用 查看   

2011-06-18 22:01 by 银光小子      
唉 .....
可惜我没钱.... 烦躁

#12楼  回复 引用 查看   

2011-06-18 22:08 by nothing better      
@马宁
哦~!谢谢哈~!这东西现在可以在淘宝上购买了。。呵呵~!

#13楼  回复 引用 查看   

2011-06-18 22:09 by nothing better      
引用马宁:
@装配脑袋
有C++的SDK,基于COM接口的。

为何不用c#来开发呢?

#14楼  回复 引用 查看   

2011-06-18 22:13 by nothing better      
引用银光小子:
唉 .....
可惜我没钱.... 烦躁

严重的同感,,那玩意儿太贵了。。。

#15楼  回复 引用 查看   

2011-06-18 22:15 by 银光小子      
引用nothing better:
引用银光小子:
唉 .....
可惜我没钱.... 烦躁

严重的同感,,那玩意儿太贵了。。。

Kinect不贵啊 1000可以搞到呢

#16楼  回复 引用 查看   

2011-06-18 22:15 by 银光小子      
引用nothing better:
引用银光小子:
唉 .....
可惜我没钱.... 烦躁

严重的同感,,那玩意儿太贵了。。。

Kinect不贵啊 1000可以搞到呢

#17楼[楼主]  回复 引用 查看   

2011-06-18 22:16 by 马宁      
@nothing better
我估计脑袋是想在他自己的语言里调用Kinect,所以才这么问的。

#18楼  回复 引用 查看   

2011-06-18 22:19 by nothing better      
引用银光小子:
引用nothing better:
引用银光小子:
唉 .....
可惜我没钱.... 烦躁

严重的同感,,那玩意儿太贵了。。。

Kinect不贵啊 1000可以搞到呢

我在淘宝上看了一下1150块。。难道这个价格不贵吗?难道我太草根了??

#19楼  回复 引用 查看   

2011-06-18 22:21 by nothing better      
引用马宁:
@nothing better
我估计脑袋是想在他自己的语言里调用Kinect,所以才这么问的。

恩。。 也有可能。。

#20楼  回复 引用 查看   

2011-06-19 07:34 by shenzhen      
一直在关注楼主的文章,请问我如果买全套的话是不是比较适合啊?我指的是以后玩到深入一点的话.(套装指的是包括xbox主机和手柄)

#21楼  回复 引用 查看   

2011-06-19 08:58 by 太阳照大神      
国内哪里有卖单独Kinect的地方?

#22楼  回复 引用 查看   

2011-06-19 13:09 by nothing better      
引用太阳照大神:国内哪里有卖单独Kinect的地方?

在淘宝上有卖的。。

#23楼  回复 引用 查看   

2011-06-19 13:18 by Rain.      
我在淘宝上买的,和电源适配器一起,一共762,需要的请PM我,在这里发有广告的嫌疑。仅仅是 Kinect.不包括 XBOX 360哦。762是顺风包邮价。蛮适合的

#24楼[楼主]  回复 引用 查看   

2011-06-19 13:35 by 马宁      
@shenzhen
买XBOX 360 silm套装的确会比较合算,但是需要额外单买一个USB转接口。因为Kinect的接口是缺了一个角的USB,可以直接插在新的XBOX 360主机上。而单卖的Kinect里会自带这个USB转接口,不需要单独购买。
试自己的情况而定吧。

#25楼  回复 引用 查看   

2011-06-19 17:54 by nothing better      
引用Rain.:我在淘宝上买的,和电源适配器一起,一共762,需要的请PM我,在这里发有广告的嫌疑。仅仅是 Kinect.不包括 XBOX 360哦。762是顺风包邮价。蛮适合的

你在哪里搜索到的那么便宜啊?

#26楼  回复 引用 查看   

2011-06-20 09:31 by Leepy      
请问:我的笔记本Inter Core 2 Duo T5750 2.00GHZ 处理器 可以跑Kinect SDK吗?

#27楼  回复 引用 查看   

2011-06-20 09:39 by kuku_zhang      
马老师,这边设备是一个Kinect 还需不需要其他的呢, XBOX 360是不是必须的购买呢。这两个东西一直搞不清楚是什么回事。

#28楼  回复 引用 查看   

2011-06-20 09:45 by Rain.      
@kuku_zhang
引用kuku_zhang:马老师,这边设备是一个Kinect 还需不需要其他的呢, XBOX 360是不是必须的购买呢。这两个东西一直搞不清楚是什么回事。

我不是马老师。
但是开发kinect for windows 我知道 XBOX 360是不需要购买的。
但是我建议你购买,XBOX 360 + Kinect还是值得购买的。

#29楼  回复 引用 查看   

2011-06-20 09:51 by kuku_zhang      
@Rain.
好的,谢谢啦。

#30楼  回复 引用 查看   

2011-06-20 09:56 by Rain.      
@Leepy
我的破X200都能跑。
CPU:SL9400 1.86GHZ 4G内存

#31楼  回复 引用 查看   

2011-06-20 09:57 by Rain.      
@kuku_zhang
购买KINECT时,别忘记买电源适配器啊。

#32楼  回复 引用 查看   

2011-06-21 08:10 by nothing better      
引用Leepy:请问:我的笔记本Inter Core 2 Duo T5750 2.00GHZ 处理器 可以跑Kinect SDK吗?

可以运行起来。但速度不敢保障~!

#33楼  回复 引用 查看   

2011-06-23 16:14 by Holyen      
hi~请教博主
image1.Source = BitmapSource.Create(imageData.Width, imageData.Height, 96, 96,
PixelFormats.Bgr32, null, imageData.Bits, imageData.Width * imageData.BytesPerPixel);

这里 PixelFormats.Bgr32 报错.没有这个枚举

#34楼  回复 引用 查看   

2011-07-01 11:50 by 嘎嘎在燃烧      
请教楼主后面的教程还有么

#35楼  回复 引用 查看   

2011-07-03 17:04 by huang9012      
马宁老是,能不能把每次写好的源代码放一下,你那个摄像头教程,我照样敲了10遍了,老是提示:调用的目标发生了异常。我都快崩溃了,LZ 要是看到能不能发一些邮箱也行:752020225@qq.com。万分感谢加跪谢了

#36楼  回复 引用 查看   

2011-07-04 00:22 by huang9012      
为什么我显示的是空白的,没有图像显示呢?

#37楼  回复 引用 查看   

2011-07-12 23:20 by 我要进Cisco      
我之前是搞c++的,没看过c#。请问kinect开发初体验(二)中,这句代码添加在哪里啊?我添加到哪里都报错。代码是:

nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);

万分感谢!

#38楼  回复 引用 查看   

2011-08-11 19:06 by rujingyu      
不错

#39楼  回复 引用 查看   

2011-08-25 12:52 by 敌法师      
楼主可以把自己的工程文件打包外放一下吗?多谢了,按照您文章中的指示,我总是会出现调用异常,好郁闷啊。

#40楼  回复 引用 查看   

2011-09-21 08:05 by hymjava      
我也感到了,也非常希望楼主可以把自己的工程文件打包外放一下.

#41楼  回复 引用 查看   

2011-10-19 19:27 by Sloudy      
能不能把源代码完整的给出来?
按照上面的步骤操作遇到各种问题。。。

#42楼  回复 引用 查看   

2011-11-16 00:16 by pele      
按楼主的代码写起来没错误,但是到了下面这句就会出现异常
nui.DepthStream.Open(ImageStreamType.Depth, 2,ImageResolution.Resolution320x240,ImageType.Depth);
请问问题出在哪里? 我是一个初学者,请多多关照

#43楼  回复 引用 查看   

2011-11-24 19:38 by uufoly      
@pele
nui.Initialize(RuntimeOptions.UseColor| RuntimeOptions.UseDepth | RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);

这里少写了| RuntimeOptions.UseDepth吗?

#44楼  回复 引用 查看   

2012-01-01 17:41 by 枫叶——锋      
楼主:想问一下kinect能得到具体的距离信息吗?比如说事例中的手距摄像头多远?如何提取这一数据?

#45楼  回复 引用 查看   

2012-01-14 15:51 by 范德罗      
马哥,咋在rgb图像中把人物扣出来呀??
问题和这位小伙类似:
http://www.cnkinect.com/thread-4504-1-1.html
谢谢,请教!!!

#46楼  回复 引用 查看   

2012-02-07 18:41 by 斌伯      
想问问楼主是用xbox版的kinect还是windows版的?windows版贵了很多,但增添了近距模式,xbox版是否没有这个功能?xbox版的能够直接用微软的sdk么?

#47楼  回复 引用 查看   

2012-02-08 11:25 by mike_zou      
想问一下,如何完成
"第四步,添加控件
双击打开MainWindow.xaml,在设计器中添加两个Image控件,一个用于显示RGB图像,另一个用于显示Depth信息。"
能否详细一些,谢谢!

#48楼  回复 引用 查看   

2012-02-09 10:32 by Kinect新手      
求指点
image1.Source = e.ImageFrame.ToBitmapSource();为什么这条语句我实现不了啊,说是没有ToBitmapSource()的定义??求指点