您的位置:首页 > 其它

KinectSDK 正式版(一)图像、景深数据获取。

2012-02-10 17:36 232 查看
上篇描述了一下Kinect for windows SDK的正式版的一部分提升,这篇主要来介绍一下正式版的SDK的图像方面的功能,以及部分强大的API支持。

第一步:创建了一个WPF程序,并将Microsoft.Kinect添加入引用。



第二步:然后在页面上简单的拖拽了两个按钮一个下拉列表。这里的两个按钮分别是启动程序和获取现在机器上的Kinect设备,而下拉列表中用来显示获取到的Kinect的名字。如上篇博客中介绍的一样目前Kinectfor windows支持四个Kinect同时连接到电脑上并接受信号进行分析。所以这里准备了一个下拉列表来获取所有连接的Kinect的设备。



MainWindow.xaml文件中添加了代码:

<Button Content="获取Kinect" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" /><ComboBox Height="23" HorizontalAlignment="Left" Margin="93,12,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" /><Button Content="启动" Height="23" HorizontalAlignment="Left" Margin="416,12,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button2_Click" />

后置文件中添加了代码:

private void button1_Click(object sender, RoutedEventArgs e){    KinectSensorCollection ksc = KinectSensor.KinectSensors;    foreach (var item in ksc)    {        this.comboBox1.Items.Add(item.UniqueKinectId);    }}private void button2_Click(object sender, RoutedEventArgs e){    KinectSensor ks = KinectSensor.KinectSensors[this.comboBox1.SelectedIndex];    ks.Start();}

运行一下,点击获取kinect按钮后的效果如图:



第三步,加入两个图片控件,一个用来显示颜色图像,一个用来显示景深图像。
MainWindow.xaml文件中添加了代码:

<Image Height="150" HorizontalAlignment="Left" Margin="13,41,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="200" />
<Image Height="150" HorizontalAlignment="Left" Margin="291,41,0,0" Name="image2" Stretch="Fill" VerticalAlignment="Top" Width="200" />

并修改了启动按钮的点击事件:

private void button2_Click(object sender, RoutedEventArgs e)
{
KinectSensor ks = KinectSensor.KinectSensors[this.comboBox1.SelectedIndex];
//添加颜色图像获取事件
ks.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(ks_ColorFrameReady);
//设置启动模式,ColorImageFormat枚举中包含5个值
ks.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
//添加景深图像获取事件
ks.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(ks_DepthFrameReady);
//设置启动模式,DepthImageFormat枚举中包含4个值
ks.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
ks.Start();
}
颜色图像获取事件为:
void ks_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
ColorImageFrame cif = e.OpenColorImageFrame();
if (cif != null)
{
//准备装图像数据的数组
byte[] imagesource = new byte[cif.PixelDataLength];
//获取图像数据
cif.CopyPixelDataTo(imagesource);
//转换后放到控件上
image1.Source = BitmapSource.Create(cif.Width, cif.Height, 96, 96, PixelFormats.Bgr32, null, imagesource, cif.Width * cif.BytesPerPixel);
}
}

景深图像获取事件为:
void ks_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
DepthImageFrame dif = e.OpenDepthImageFrame();
if (dif != null)
{
//准备装图像数据的数组
short[] imagesourceS = new short[dif.PixelDataLength];
dif.CopyPixelDataTo(imagesourceS);
int length=dif.Width * dif.Height * ((PixelFormats.Bgr32.BitsPerPixel + 7) / 8);
byte[] imagesourceB = new byte[length];
//景深数据转换成byte
imagesourceB = this.ConvertDepthFrame(imagesourceS, ((KinectSensor)sender).DepthStream, imagesourceB, length);

//生成图片放到控件上
WriteableBitmap outputBitmap = new WriteableBitmap(dif.Width,dif.Height,96,96,PixelFormats.Bgr32,null);

this.image2.Source = outputBitmap;

outputBitmap.WritePixels(new Int32Rect(0, 0, dif.Width, dif.Height),imagesourceB,dif.Width * ((PixelFormats.Bgr32.BitsPerPixel + 7) / 8),0);
}
}

景深图像转换方法:
private byte[] ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream, byte[] depthFrame32, int length)
{
int RedIndex = 2;
int GreenIndex = 1;
int BlueIndex = 0;

int[] IntensityShiftByPlayerR = { 1, 2, 0, 2, 0, 0, 2, 0 };
int[] IntensityShiftByPlayerG = { 1, 2, 2, 0, 2, 0, 0, 1 };
int[] IntensityShiftByPlayerB = { 1, 0, 2, 2, 0, 2, 0, 2 };

int tooNearDepth = depthStream.TooNearDepth;
int tooFarDepth = depthStream.TooFarDepth;
int unknownDepth = depthStream.UnknownDepth;

for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < length; i16++, i32 += 4)
{
int player = depthFrame[i16] & DepthImageFrame.PlayerIndexBitmask;
int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth;
byte intensity = (byte)(~(realDepth >> 4));

if (player == 0 && realDepth == 0)
{
depthFrame32[i32 + RedIndex] = 255;
depthFrame32[i32 + GreenIndex] = 255;
depthFrame32[i32 + BlueIndex] = 255;
}
else if (player == 0 && realDepth == tooFarDepth)
{
depthFrame32[i32 + RedIndex] = 66;
depthFrame32[i32 + GreenIndex] = 0;
depthFrame32[i32 + BlueIndex] = 66;
}
else if (player == 0 && realDepth == unknownDepth)
{
depthFrame32[i32 + RedIndex] = 66;
depthFrame32[i32 + GreenIndex] = 66;
depthFrame32[i32 + BlueIndex] = 33;
}
else
{
depthFrame32[i32 + RedIndex] = (byte)(intensity >> IntensityShiftByPlayerR[player]);
depthFrame32[i32 + GreenIndex] = (byte)(intensity >> IntensityShiftByPlayerG[player]);
depthFrame32[i32 + BlueIndex] = (byte)(intensity >> IntensityShiftByPlayerB[player]);
}
}
return depthFrame32;
}

运行效果如图:



哈哈,有趣的是出现了六指,也许在光线不好的位置kinect的景深数据还是有些出入的,光线良好的位置数据准确度是很高的。

OK了,现在本篇要介绍的部分已经完成了,如果阅读后发现什么问题可以留言,或者发送邮件到:57512434@qq.com,看到后会第一时间回复的。
以上是颜色获取以及景深数据获取的代码,希望能给大家些帮助,这篇就先到这里,对了多补充一下,截图来看下刚刚项目的output :



这是因为示例使用的kinect是 xbox用的,不是专门的kinect for windows设备,所以会有这个提示。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: