惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Fortinet All Blogs
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
小众软件
小众软件
有赞技术团队
有赞技术团队
雷峰网
雷峰网
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
AWS News Blog
AWS News Blog
C
Cisco Blogs
美团技术团队
T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
人人都是产品经理
人人都是产品经理
宝玉的分享
宝玉的分享
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
W
WeLiveSecurity
D
DataBreaches.Net
博客园 - 司徒正美
Blog — PlanetScale
Blog — PlanetScale
IT之家
IT之家
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
Google DeepMind News
Google DeepMind News
T
The Blog of Author Tim Ferriss
Know Your Adversary
Know Your Adversary
NISL@THU
NISL@THU
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Vercel News
Vercel News
月光博客
月光博客
T
Tailwind CSS Blog
H
Help Net Security
aimingoo的专栏
aimingoo的专栏
P
Proofpoint News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Spread Privacy
Spread Privacy
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
V
V2EX
WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
Recent Announcements
Recent Announcements

博客园 - 马宁

OpenXLive支持 Windows Phone上的SNS 分享 OpenXLive的多语言支持 Windows 8开发初体验 - C#版菜谱 OpenXLive Push Notification Hosting服务开发指南 在Windows Phone应用中添加OpenXLive数据分析功能 马宁的Windows Phone 7.1初体验(三)——Tile 马宁的Windows Phone 7.1初体验(二)——Push Notification Kinect for Windows SDK开发初体验(三)骨骼追踪 Kinect for Windows SDK开发初体验(二)操作Camera Kinect for Windows SDK开发初体验(一)环境配置 马宁的Windows Phone 7.1初体验——XNA与Silverlight集成 如何将OpenXLive添加到WP7 Silverlight游戏中 Game Center,移动游戏社交平台的勘探报告 OpenXLive——开启Windows Phone 7游戏社交平台新时代 Windows Phone Marketplace发布攻略 Windows Phone7中的IronRuby 马宁的Windows Phone 7开发教程(4)——XNA显示中文字体 马宁的Windows Phone 7开发教程(3)——XNA下使用MessageBox和软键盘 Windows Phone XNA 4.0 3D游戏开发
Kinect for Windows SDK开发初体验(四)景深数据
马宁 · 2011-08-25 · via 博客园 - 马宁

作者:马宁

终于可以坐下来继续这个系列了,在微博和博客园里,已经有无数人催过了,实在抱歉,一个人的精力毕竟是有限的,但我会抽出一切可用的时间,尽可能尽快完成。

这一章我们来说说景深数据Depth Data,这是Kinect的Depth Camera为我们提供的全新功能,以往的技术只能够通过图像识别来完成的一些工作,我们可以借助景深来帮我们完成了。比如,前景与背景的分离,以前只能将背景设置为蓝屏或者绿屏,但是现在有了景深数据,我们就可以很容易地将前景物体从背景中分离出来。当然,需要特别说明的是,Depth Camera技术是由以色列公司PrimeSense提供的。

程序布局

在这一章里,我们要完成的工作非常简单,根据物体距离Kinect的远近,设置成不同的颜色。首先,我们要创建一个新的WPF工程,然后添加一个Image控件:

<Image Height="240" HorizontalAlignment="Left" Margin="62,41,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="320" />

然后是MainWindow.xaml.cs中的核心代码,这部分代码与之前的代码大体一致,所以不做过多解释了:

//Kinect RuntimeRuntime 

Runtime nui = new Runtime(); 

private void Window_Loaded(object sender, RoutedEventArgs e)

{

//UseDepthAndPlayerIndex and UseSkeletalTracking

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

//register for event

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

//DepthAndPlayerIndex ImageType

nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240,

ImageType.DepthAndPlayerIndex);

}

private void Window_Closed(object sender, EventArgs e)

{

nui.Uninitialize();

}

唯一需要大家注意的是,我们在初始化函数中传递的参数是RuntimeOptions.UseDepthAndPlayerIndex,这表示景深信息中会包含PlayerIndex的信息。接下来,我们就要花点时间来理解DepthAndPlayerIndex的实际结构。

理解DepthAndPlayerIndex

先来看DepthFrameReady事件处理函数,如下:

void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)

{

// Convert depth information for a pixel into color information 

byte[] ColoredBytes = GenerateColoredBytes(e.ImageFrame); 

// create an image based on the colored bytes 

PlanarImage image = e.ImageFrame.Image;

image1.Source = BitmapSource.Create( 

image.Width, image.Height, 96, 96, PixelFormats.Bgr32, 

null, ColoredBytes, image.Width * PixelFormats.Bgr32.BitsPerPixel / 8); 

}

DepthFrameReady事件会返回一个ImageFrame对象,其中会包含一个PlanarImage对象。PlanarImage对象会包含一个byte[]数组,这个数组中包含每个像素的深度信息。这个数组的特点是,从图像左上角开始、从左到右,然后从上到下。

该数组中每个像素由两个bytes表示,我们需要通过位运算的办法来获取每个像素的位置信息。

如果是Depth Image Type,将第二个bytes左移8位即可。

Distance (0,0) = (int)(Bits[0] | Bits[1] << 8 );
 

如果是DepthAndPlayerIndex Image Type,第一个bytes右移三位去掉Player Index信息,第二个bytes左移5位。

Distance (0,0) =(int)(Bits[0] >> 3 | Bits[1] << 5);
 

DepthAndPlayerIndex image类型的第一个bytes前三位包括Player Index信息。Player Index最多包含六个可能值:

0, 没有玩家;1,玩家1;2,玩家2,以此类推。

我们可以用下面的方法来获取Player Index信息:

private static int GetPlayerIndex(byte firstFrame)

{

//returns 0 = no player, 1 = 1st player, 2 = 2nd player...

return (int)firstFrame & 7; 

}

设置颜色

接下来,我们创建一个bytes数组,用来存储颜色值。

if (distance <= 900)

{

//we are very close

colorFrame[index + BlueIndex] = 255;

colorFrame[index + GreenIndex] = 0;

colorFrame[index + RedIndex] = 0;

}

if (GetPlayerIndex(depthData[depthIndex]) > 0)

{

//we are the farthest

colorFrame[index + BlueIndex] = 0;

colorFrame[index + GreenIndex] = 255;

colorFrame[index + RedIndex] = 255;

}

当然,我们最好是设置几个边界值,来定义不同距离的不同颜色:

//equal coloring for monochromatic histogram

var intensity = CalculateIntensityFromDepth(distance);

colorFrame[index + BlueIndex] = intensity;

colorFrame[index + GreenIndex] = intensity;

colorFrame[index + RedIndex] = intensity;

const float MaxDepthDistance = 4000; // max value returned

const float MinDepthDistance = 850; // min value returned

const float MaxDepthDistanceOffset = MaxDepthDistance - MinDepthDistance;

public static byte CalculateIntensityFromDepth(int distance)

{

//formula for calculating monochrome intensity for histogram

return (byte)(255 - (255 * Math.Max(distance - MinDepthDistance, 0) / (MaxDepthDistanceOffset)));

}

最后,把所有代码放在一起,我们设定的颜色值为:

蓝色,小于900;900到2000,绿色;大于2000,红色

代码如下:

        private byte[] GenerateColoredBytes(ImageFrame imageFrame)
        {    
            int height = imageFrame.Image.Height;    
            int width = imageFrame.Image.Width;     
            
            //Depth data for each pixel    
            Byte[] depthData = imageFrame.Image.Bits;      
            
            //colorFrame contains color information for all pixels in image    
            //Height x Width x 4 (Red, Green, Blue, empty byte)    
            Byte[] colorFrame = new byte[imageFrame.Image.Height * imageFrame.Image.Width * 4];     
            
            //Bgr32  - Blue, Green, Red, empty byte    
            //Bgra32 - Blue, Green, Red, transparency     
            //You must set transparency for Bgra as .NET defaults a byte to 0 = fully transparent     
            //hardcoded locations to Blue, Green, Red (BGR) index positions           
            const int BlueIndex = 0;    
            const int GreenIndex = 1;    
            const int RedIndex = 2;     
            var depthIndex = 0;    
            
            for (var y = 0; y < height; y++)    
            {                
                var heightOffset = y * width;         
                
                for (var x = 0; x < width; x++)        
                {            
                    var index = ((width - x - 1) + heightOffset) * 4;             
                    
                    //var distance = GetDistance(depthData[depthIndex], depthData[depthIndex + 1]);            
                    var distance = GetDistanceWithPlayerIndex(depthData[depthIndex], depthData[depthIndex + 1]);             
                    
                    if (distance <= 900)            
                    {                
                        //we are very close                
                        colorFrame[index + BlueIndex] = 255;                
                        colorFrame[index + GreenIndex] = 0;                
                        colorFrame[index + RedIndex] = 0;                   
                    }            
                    else if (distance > 900 && distance < 2000)            
                    {                
                        //we are a bit further away                
                        colorFrame[index + BlueIndex] = 0;                
                        colorFrame[index + GreenIndex] = 255;                
                        colorFrame[index + RedIndex] = 0;            
                    }            
                    else if (distance > 2000)            
                    {                
                        //we are the farthest                
                        colorFrame[index + BlueIndex] = 0;                
                        colorFrame[index + GreenIndex] = 0;                
                        colorFrame[index + RedIndex] = 255;            
                    }             
                    
                    //Color a player            
                    if (GetPlayerIndex(depthData[depthIndex]) > 0)            
                    {                
                        //we are the farthest                
                        colorFrame[index + BlueIndex] = 0;                
                        colorFrame[index + GreenIndex] = 255;                
                        colorFrame[index + RedIndex] = 255;            
                    }             
                    
                    //jump two bytes at a time            
                    depthIndex += 2;        
                
                }    
            }     
            
            return colorFrame;
        }

程序的现实效果如下图:

clip_image001

写到最后

到这里,我们就将Kinect SDK中NUI的基本内容介绍完了,接下来,我们要介绍Audio部分,或者借助一些实际的例子,来看一下Kinect SDK的实际应用。