Unity Kinect创建自定义手势

一 Kinect Studio 收集视频样本
首先,打开Kinect Studio,先点击File进入设置界面,这里我们可以设置我们的视频片段存储位置。 
录制视频样本,先转到Record界面,连接Kinect 
成功之后,我们的Kinect的三个红外灯应该是亮了,然后点击那个红色的icon开始录制视频。 
我们这里以挥手这个动作来作为例子,我们站在一个合适的位置,做挥手的动作,一开始慢慢的,多做几组),然后录制完毕,点击停止录制。 
这时候,Kinect Studio 的界面会自动跳转到Play的界面。我们先Disconnect Kinect之后,可以点击play的icon来查看这个视频例子,注意,我用红色方框框起来的部分,这个就是保存的文件名,注意,只要我们点击了录制,Kinect Studio都会给我们自动保存的。保存的位置就是我们刚才设置的文件夹,如果,你没有设置的话,可以去File 的Setting里面看看它的默认文件夹的位置。 
同样的操作,我们在做几遍,当然你的视频样本越多,我们生成的分类器就更准确啊。
二 Visual Gesture Builder制作正负样本
打开软件,File -> New Solution, 自己随便命个名,我这里叫做DemoWave。
现在的面板李应该出现了你刚才project,右键这个工程,选择Create New Project With Wizard。 
出现VGB Gesture Wizard 的界面,点击 Next 
给我们的姿势命个名,我这里叫做demowave。 
这里是判断我们的姿势是否包含下半身的骨骼,因为我们只是挥手,腿部做什么动作都可以,所以,选择不包含。 
这里是判断我们的姿势是否需要判断特定的手势。因为我们挥手主要是看胳膊的动作,所以,不关心手部的动作,这里也选择不包含。 
这里是让我们来选择需要判断的骨骼的部分,每个图旁边都有一定的注解说它忽略了什么,我这里就不一一翻译了,因为我们判断的是挥手,所以,左右手都是需要判断的,但是不需要判断下半身的状态,所以,我们选择第一个joint mask就好。 
这里是问我们的动作判断是否是区分左右的?那我们的挥手动作为例,如果我们选择NO,那么Kinect判断挥手的时候,就不区分是左胳膊懂还是右胳膊动;如果我们选择YES的话,那么Visual Gesture Builder就会给我们建立两个Project一个叫做demowave_Right,另外一个叫做demowave_Left,就相当于建立两个分类标准,用于区分左右手。 
这个界面主要是来判断我们的动作是否是连续性的还是离散的。所谓离散性质,就是判断这个我们动作“发生了“还是“没有发生“,就是一个1还是0的判断,如果连续性质的话呢,就是判断Kinect检测到的姿势和我们分类器的姿势的吻合度有多少,它不是一个是否的判断而是一系列的数字来表示当前的姿势和分类器姿势的重合度,而且,这个数字越高,表示当前检测的动作和分类器的标志动作越像。而我们这里指向判断用户是否挥动了左手还是右手,是一个是否的判断,所以我们这里选择NO。 
这里就是说,下面会有这两个gesture会被创建。因为我们在之前选择了左右的判断,所以这里会出现两个getures如果刚才我们没有选择左右的判断,那么这里只会出现一个gesture。 
点击confirm,就会生成对应的工程,现在我们的工程如下图所示。 
这里简单的说一下,一共是两个工程有四个文件生成,所以呢,就是每个gesture右两个文件,这两个文件名字都是一样的,只不过一个是.a结尾的,一个不是,那么.a结尾的文件呢,其实是测试gesture的一个文件,而那个不带.a的才是我们拿来训练的样本。基本上呢,我们是那样本数目的2/3用来训练样本,1/3就是放在那个.a 文件下,用来测试分类器的。
好的,下面,我们来利用刚才收集到的视频片段来创建正负样本。右键,demowave_Left,选择Add Chip,把我们刚才录的视频片段加入进去。(建议大家录完视频片段之后给它们改个名字,这样便于管理,当然,我说是视频片段,这里的视频片段其实是包含了Kinect的骨骼等数据的) 
我们把视频片段(也就是Chips)加入进去之后,然后告诉训练器哪些帧时正样本,哪些帧时负样本。其中正样本被蓝色的线标志出来了,这里需要手动判别正负样本,当然,对一段视频操作当然是少不了快捷键啊。尴尬的是,默认打开的窗口(也就是你们现在展示的窗口)是看不到快捷键提示的。那么我们只要把下面的Gesture Tags的区域拉大一点,是不是看见下面的快捷键提示啦?(为了避免出现误判的情况,除了收集足够多的正样本之外,我们还需要各种各样的负样本,如图,我们在做一个挥手的样本收集,我在录制视频的时候还跳动几下,用作负样本) 
然后,我们依次把每个Chips的政府样本都设置好之后。我们可以选择总的工程文件,右键Build,当然,你已经迫不及待的想看看当前姿势的训练情况,你也可以选择某一个Gesture文件右键Build。然后就是等待的过程,这个时间取决于样本的多少,因为我这里只有6个视频片段,所以训练时间很短。
当你发现下面的Output栏中出现build完成的提示,并且没有错误的话,那么恭喜你,你自定义姿势的分类器已经训练完成了。
还记得那个.a文件嘛?如果你还有没有训练的视频片段的话,可以把那个视频片段加入你的.a文件下,来测试分类器。当然,你也可以右键工程选择Live Preview,这样的话,Visual Gesture Builder就会打开Kinect,就会捕捉你的动作,实时的判断当前的动作是否符合条件。旁边的那个方框里面的数值(类似直方图)越高,说明你的动作越符合分类器。 
训练完成之后,我们会得到一个.gba的文件,这个就是我们训练出来的分类器!
三 Unity5 中调用分类器
首先创建一个Unity的工程,导入Kinect Unity的开发包。 
什么?不知道怎么使用Unity5 +Kinect v2,好吧,这又一个step by step的教程 
在我们的工程文件(Assets)下面创建一个文件夹叫做StreamingAssets,然后把我们刚才生成的分类器文件(.gba文件/.gbd文件)放进去。
创建一个脚本GestureSourceManger.cs里面的代码如下:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Windows.Kinect;
using Microsoft.Kinect.VisualGestureBuilder;
public class GestureSourceManager : MonoBehaviour {
public BodySourceManager _BodySource;
public string databasePath;
private KinectSensor _Sensor;
private VisualGestureBuilderFrameSource _Source;
private VisualGestureBuilderFrameReader _Reader;
private VisualGestureBuilderDatabase _Database;
// Gesture Detection Events public event GestureEvent OnGesture;
private static GestureSourceManager instance = null ;


public static GestureSourceManager Instance{
get {
return instance;
}
}
// Use this for initialization void Start() {
_Sensor = KinectSensor.GetDefault();
if (_Sensor != null ) {
if (!_Sensor.IsOpen) {
_Sensor.Open();
}
// Set up Gesture Source
_Source = VisualGestureBuilderFrameSource.Create(_Sensor, 0 );
// open the reader for the vgb frames
_Reader = _Source.OpenReader();
if (_Reader != null ) {
_Reader.IsPaused = true ;
_Reader.FrameArrived += GestureFrameArrived;
}
// load the 'Seated' gesture from the gesture database
string path = System.IO.Path.Combine(Application.streamingAssetsPath, databasePath);
Debug.Log ( "database path is " +path);
_Database = VisualGestureBuilderDatabase.Create(path);
// Load all gestures
IList<Gesture> gesturesList = _Database.AvailableGestures;
for ( int g = 0 ; g < gesturesList.Count; g++) {
Gesture gesture = gesturesList[g];
Debug.Log ( "database name is " + gesture.Name);
_Source.AddGesture(gesture);
}
}
instance = this ;
}
// Public setter for Body ID to track public void SetBody ( ulong id) {
if (id > 0 ) {
_Source.TrackingId = id;
_Reader.IsPaused = false ;
Debug.Log ( "id is " +id);
} else {
_Source.TrackingId = 0 ;
_Reader.IsPaused = true ;
}
gameObject.GetComponent<GestureController> ().AddGesture ();
}
// Update Loop, set body if we need one void Update() {
if (!_Source.IsTrackingIdValid) {
FindValidBody();
}
}
// Check Body Manager, grab first valid body void FindValidBody() {
if (_BodySource != null ) {
Body[] bodies = _BodySource.GetData();
if (bodies != null ) {
foreach (Body body in bodies) {
if (body.IsTracked) {
SetBody(body.TrackingId);
break ;
}
}
}
}
}
/// Handles gesture detection results arriving from the sensor for the associated body tracking Id private void GestureFrameArrived ( object sender, VisualGestureBuilderFrameArrivedEventArgs e) {
VisualGestureBuilderFrameReference frameReference = e.FrameReference;
using (VisualGestureBuilderFrame frame = frameReference.AcquireFrame()) {
if (frame != null ) {
// get the discrete gesture results which arrived with the latest frame
IDictionary<Gesture, DiscreteGestureResult> discreteResults = frame.DiscreteGestureResults;
if (discreteResults != null ) {
foreach (Gesture gesture in _Source.Gestures) {
if (gesture.GestureType == GestureType.Discrete) {
DiscreteGestureResult result = null ;
discreteResults.TryGetValue(gesture, out result);

if (result.Confidence > 0.05 ) {
// Fire Event
if (OnGesture!= null ){
Debug.Log( "Detected Gesture " + gesture.Name + " with Confidence " + result.Confidence);
OnGesture( this , new KinectGestureEvent(gesture.Name, result.Confidence));
}
}
}
}
}
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
然后在外部调用这个代码,注意:这个脚本是必须传入一个BodyManager对象的,还要写一下我们的分类器的名称(当然,这个你在脚本里面hardcode也可以)。 
现在,点击运行,挥一下手,你就会发现,控制栏有输出啦!
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值