彩色影像数据流是Kinect摄像头最基本的数据,图像相当于一般的摄像头(废话)。
本节主要是获取Kinect摄像头的彩色影像数据,在Image控件上将其展示出来。
新建WPF项目KinectColorStreamTest
通过Nuget添加Kinect的相关程序包
这里简要说明下Kinect 2.0 SDK 的结构:
Microsoft Kinect 是基础API,所有的高级命名空间全都要基于此API,不区分X86和X64(好吧是我没仔细研究,我也不知道是不区分还是都基于X86的架构)
Microsoft Kinect Fusion 是3D扫描相关的API集合
Microsoft Kinect Face Tracking 顾名思义是面部识别相关的API集合
Microsoft Kinect WPF Controls 是基于WPF的手势控制API集合
剩下的没太深入研究,不敢下定论。
我们先从Microsoft Kinect 学起,在后面将接触3D扫描或面部识别相应的API
书归正传,添加好程序包后,在MainWindow.xaml.cs里引用一下:
using Microsoft.Kinect;
在MainWindow类下做几个声明:
private KinectSensor kinect = null; //用来标记kinect摄像头的实例
private ColorFrameReader colorFrame = null; //用来处理和保存摄像头传过来的彩色影像帧数据
private WriteableBitmap colorBitmap = null; //用来向Image控件中填充彩色影像数据
private FrameDescription colorFrameDescription = null; //用来描述彩色影响帧数据形态的参数
接下来,在窗口初始化前,要做一些数据绑定,添加监听事件,MainWindow方法的代码如下:
public MainWindow()
{
this.kinect = KinectSensor.GetDefault(); //获取第一个或默认的Kinect摄像头
this.colorFrame = kinect.ColorFrameSource.OpenReader(); //打开彩色影像数据的获取接口
this.colorFrame.FrameArrived += colorFrame_FrameArrived; //建立监听事件,当有彩色影像数据帧到达时触发
this.colorFrameDescription = this.kinect.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra); //按照Bgra格式设定数据帧的描述信息(B:Blue,G:Green,R:Red,A:Alpha)
this.colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null); //根据数据帧的宽高创建colorBitmap的实例
this.kinect.Open(); //启动kinect摄像头
InitializeComponent();
}
在这段代码中,展示了Kinect摄像头启动的一般历程:
捕获摄像头,打开数据接口,监听接口过来的数据并交由响应函数处理,启动摄像头。
下面来写colorFrame_FrameArrived函数,处理摄像头送过来的帧数据:
void colorFrame_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
using(ColorFrame frame=e.FrameReference.AcquireFrame()) //建立一个ColorFrame的实例frame保存送过来的帧,通过using保证走完函数后及时释放相应资源
{
this.colorBitmap.Lock(); //锁定一下数据文件,准备进行填充
frame.CopyConvertedFrameDataToIntPtr(this.colorBitmap.BackBuffer, (uint)(this.colorFrameDescription.Width * this.colorFrameDescription.Height * 4), ColorImageFormat.Bgra);
//提供给函数一个空间接收帧数据,将数据储存进colorBitmap的后台缓存中
this.colorBitmap.AddDirtyRect(new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight));
//设定colorBitmap需要更改的位图区域,此处设定为整个图片
this.colorBitmap.Unlock(); //解锁位图资源
}
}
colorFrame_FrameArrived处理了前面建立的监听事件给出的触发信号,将获取到的摄像头帧信息传给了colorBitmap。
接下来将colorBitmap展示到窗口,窗口新建一个Image控件,绑定一个ColorSource对象:
ColorSource的代码很简单,只有一个get:
public ImageSource ColorSource
{
get
{
return this.colorBitmap;
}
}
代码结构就初步完成了,运行一下,可用!
光着膀子就不露脸了,看看哥们的掌纹是不是有点乱?一千多的摄像头清晰度绝对够,1080p啊!
但是在关闭测试程序的时候,程序会报错:
简单研究了下,是由于关闭程序的时候摄像头数据已中断,但又触发了之前建立的监听(this.colorFrame.FrameArrived),导致监听函数获取了一个空的帧数据,以致于报错,简单修改代码,在获取帧数据时增加一个判断frame!=null就可以了。
到这里,我们已经用Kinect摄像头获取到了最简单的彩色影像数据流,当然这只是最基本的,在实际应用中还要考虑摄像头突然掉线、上线以及内存占用等问题,在可靠性上再增加一些代码,尽量保证程序的可能性枚举与现实情况吻合,下一章就来讨论摄像头的工作状态变化获取及实际情况处理。
CS文件中的完整代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
namespace KinectColorStreamTest
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
private KinectSensor kinect = null; //用来标记kinect摄像头的实例
private ColorFrameReader colorFrame = null; //用来处理和保存摄像头传过来的彩色影像帧数据
private WriteableBitmap colorBitmap = null; //用来向Image控件中填充彩色影像数据
private FrameDescription colorFrameDescription = null; //用来描述彩色影响帧数据形态的参数
public MainWindow()
{
this.kinect = KinectSensor.GetDefault(); //获取第一个或默认的Kinect摄像头
this.colorFrame = kinect.ColorFrameSource.OpenReader(); //打开彩色影像数据的获取接口
this.colorFrame.FrameArrived += colorFrame_FrameArrived; //建立监听事件,当有彩色影像数据帧到达时触发
this.colorFrameDescription = this.kinect.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
//按照Bgra格式设定数据帧的描述信息(B:Blue,G:Green,R:Red,A:Alpha)
this.colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
//根据数据帧的宽高创建colorBitmap的实例
this.kinect.Open(); //启动kinect摄像头
this.DataContext = this;
InitializeComponent();
}
void colorFrame_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
using(ColorFrame frame=e.FrameReference.AcquireFrame()) //建立一个ColorFrame的实例frame保存送过来的帧,通过using保证走完函数后及时释放相应资源
{
if (frame != null)
{
this.colorBitmap.Lock(); //锁定一下数据文件,准备进行填充
frame.CopyConvertedFrameDataToIntPtr(this.colorBitmap.BackBuffer, (uint)(this.colorFrameDescription.Width * this.colorFrameDescription.Height * 4), ColorImageFormat.Bgra);
//提供给函数一个空间接收帧数据,将数据储存进colorBitmap的后台缓存中
this.colorBitmap.AddDirtyRect(new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight));
//设定colorBitmap需要更改的位图区域,此处设定为整个图片
this.colorBitmap.Unlock(); //解锁位图资源
}
}
}
public ImageSource ColorSource
{
get
{
return this.colorBitmap;
}
}
}
}