Kinect传感器是一款由微软开发的深度感应摄像头,它能够捕捉用户的体感动作,广泛应用于游戏、教育、医疗等领域。本文将介绍如何使用Kinect传感器进行编程,包括初始化、数据获取、录制与回放等功能的实现。
在本文中,假设读者已经具备了使用Kinect传感器和Kinect SDK(非OpenNI版本)的基础知识,并且熟悉C#编程语言。本文的应用程序是基于Kinect Beta 2 SDK开发的。如果对Kinect传感器不太熟悉,可以查看一系列优秀的教程。
在开始编程之前,需要准备以下工具和资源:
KinectRecorderInterface类的使用非常简单。首先,来看一下这个类的公共成员、方法和事件。
声明并创建这个类的实例,就像大多数类的声明一样。
KinectRecorderInterface recorder = new KinectRecorderInterface();
初始化时,通过recorder打开Kinect传感器,并选择适当的图像分辨率(深度图像可以高达640x480)。
注意:一次只能有一个应用程序使用Kinect!
使用以下代码仅打开深度流:
recorder.InitializeSensor(ImageResolution.Resolution320x240);
使用以下代码同时打开深度流和视频流:
recorder.InitializeSensor(ImageResolution.Resolution320x240, ImageResolution.Resolution640x480);
完整的初始化代码如下:
private KinectRecorderInterface recorder;
public void InitializeKinectRecorder() {
recorder = new KinectRecorderInterface();
recorder.InitializeSensor(ImageResolution.Resolution640x480, ImageResolution.Resolution640x480);
recorder.PlaybackSkeletonDataReady += new KinectRecorderInterface.PlaybackFrameHandler(recorder_PlaybackSkeletonDataReady);
recorder.SkeletonFrameReady += new KinectRecorderInterface.SkeletonFrameHandler(recorder_SkeletonFrameReady);
recorder.ImageFrameReady += new KinectRecorderInterface.ImageFrameHandler(recorder_ImageFrameReady);
recorder.DepthFrameReady += new KinectRecorderInterface.DepthFrameHandler(recorder_DepthFrameReady);
}
现在,可以创建适当的事件处理程序来从Kinect获取数据。
注意:事件处理程序和EventArgs与使用Kinect SDK时相同,除了回放!
recorder.SkeletonFrameReady += new KinectRecorderInterface.SkeletonFrameHandler(recorder_SkeletonFrameReady);
recorder.ImageFrameReady += new KinectRecorderInterface.ImageFrameHandler(recorder_ImageFrameReady);
recorder.DepthFrameReady += new KinectRecorderInterface.DepthFrameHandler(recorder_DepthFrameReady);
回放事件处理程序与实时数据获取非常相似,但它区分其EventArgs(稍后会详细介绍)。
recorder.PlaybackSkeletonDataReady += new KinectRecorderInterface.PlaybackFrameHandler(recorder_PlaybackSkeletonDataReady);
现在,可以像通常一样从SkeletonTracking、DepthStream和VideoStream获取Kinect的数据,但目前还没有录制或回放。
可以随时使用StartRecording()方法开始捕获可用的(Tracked)SkeletonData。
使用StopRecording()方法停止捕获并保存任何存储的SkeletonData。默认情况下,数据存储在"Recordings"文件夹中,除非从RecordDirectory更改它。
注意:如果没有SkeletonData,保存将被中止。
recorder.RecordDirectory = "./StoreData";
recorder.StartRecording();
// 等待想要的时间
recorder.StopRecording();
现在,默认情况下,已经创建了一个新的"Recordings"文件夹,以及一个名为"recording_00x.dat"的文件。
录制了一些动作后,可以随时回放它们。使用StartPlayback()开始回放最后一个可用的录制。
另外,可以使用StartPlayback(recording_xxx.dat)来回放选择的录制。
注意:每次应用程序开始/录制/保存时,都会更新一个录音目录(List
// 播放最后一个可用的录音
recorder.StartPlayback();
// 播放选择的录音
List records = recorder.ExistingRecords;
recorder.StartPlayback(records[0]);
当到达需要存储数据的阶段时,意识到不能序列化SkeletonData,因为它没有标记为Serializable。因此,实现了Json.Net,效果非常好!但是,不幸的是,当尝试反序列化并转换(见下文)存储的数据时,它又失败了,因为SkeletonData没有任何public构造函数(它的构造函数设置为internal)!欢迎提供更好的解决方案!
// 这段代码因为SkeletonData没有public构造函数而出错
var json = System.IO.File.ReadAllText(filepath);
var skeletonData = Newtonsoft.Json.JsonConvert.DeserializeObject>(json);
最后,没有想出任何其他解决方案,只能创建一个与SkeletonData几乎相同的新类,如下所示:
将在获取SkeletonDataArgs时获取SerializableSkeletonData。SkeletonDataArgs包含SerializableSkeletonData。
使用SerializableSkeletonData:它几乎与使用SkeletonData的过程相同!
例如,假设有以下代码用于SkeletonData:
private void recorder_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs skeletonFrameArgs) {
SkeletonData skeleton = skeletonFrameArgs.SkeletonFrame.Skeletons[0];
if (skeleton != null) {
// 用数据做一些事情
setEclipsePos(HeadEclipse, skeleton.Joints[JointID.Head]);
setEclipsePos(LeftHandEclipse, skeleton.Joints[JointID.HandLeft]);
setEclipsePos(RightHandEclipse, skeleton.Joints[JointID.HandRight]);
}
}
使用回放的SerializableSkeletonData的相同功能:
private void recorder_PlaybackSkeletonDataReady(object sender, SkeletonDataArgs skeletonDataArgs) {
SerializableSkeletonData skeleton = skeletonDataArgs.serializableSkeletonData;
if (skeleton != null) {
// 用数据做一些事情
setEclipsePos(HeadEclipse, skeleton.Joints[(int)JointID.Head]);
setEclipsePos(LeftHandEclipse, skeleton.Joints[(int)JointID.HandLeft]);
setEclipsePos(RightHandEclipse, skeleton.Joints[(int)JointID.HandRight]);
}
}
KinectRecorderInterface有一个PlayPause方法,当在录制或回放模式时可以使用。
使用PlayPauseRecording()或PlayPausePlayback(),每次想要暂停录制或回放时。再次使用相同的方法继续。
// 暂停或恢复录制
recorder.PlayPauseRecording();
// 暂停或恢复回放
recorder.PlayPausePlayback();
使用Status来检查或查看录制接口的当前状态!
public enum KinectRecorderStatus {
Idle = 0,
Initializing = 1,
Recording = 2,
Playing = 3,
Saving = 4,
Loading = 5,
NotConnected = 6,
PlayingPaused = 7,
RecordingPaused = 8
}
// 打印当前状态
statusLabel.Text = recorder.Status.ToString();
// 检查'Status'
if (recorder.Status == KinectRecorderStatus.Playing) {
// 做一些事情
}
应用程序已经在后台运行了HotKey识别!可以设置多达4个HotKeys来处理:
// 将'F9'设置为录制的HotKey
recorder.RecordHotKey = System.Windows.Forms.Keys.F9;