Kinect in Unity手勢識別的學習總結

Kinect學習

標籤:Kinect Windows

買了Kinect之後學習了好久,姑且做個階段性的總結吧。之後的實踐部分單獨再出一篇文章。

參考資料:

遇到的問題:

一、Kinect2.0概述以及Kinect數據源預覽

基本介紹了Kinect2.0的大概內容,以及開發好的Kinect SDK for windows,以及將來要和Unity團隊共同開發的插件。

Kinect擁有包括深度信息、紅外信息在內的一系列信息,其中深度信息非常的精確。

kinect Unity plugin

參考資料

Kinect Manager

Kinect手勢識別實踐

視頻課程筆記

微軟:快速入門Kinect for windows v2開發

6.1 介紹Kinect Studio

Kinect Studio教學

操作,在Kinect Studio中錄製動作

6.2 手勢識別

打開了C#的Body Basic的代碼,進行了修改實例。還不錯,但是Unity中用到的組件和這裏的似乎不太一樣。

Visual Gesture Builder的培訓步驟:通過Kinect Studio記錄手勢,使用Gesture Builder打標記,使用GestureBuilder去構建和分析手勢,在Gesture Builder中預覽手勢。最終,將自定義的手勢所存儲的數據庫整合到程序之中。

8.1 自定義手勢,錄製與回放

Visual Gesture Builder,使用Machine learning製作自定義動作

8.2 使用Kinect Gesture Builder

8.3 將創建的動作植入程序

9.1 瞭解離散手勢和連貫手勢

9.2 創建連貫手勢

9.3 使用Visual Gesture Builder創建自動標記片段

官方文檔學習

QA位置

如何處理離散的手勢,像是揮手和舉手

  1. 在腳本的UserDetected()函數中添加下列語句manager.DetectGesture(userId, KinectGestures.Gestures.xxxxx);
  2. GestureCompleted()函數中提那家如何處理離散手勢,比如
if(gesture == KinectGestures.Gestures.xxxxx)
{
    // gesture is detected - process it (for instance, set a flag or execute an action)
}
  1. GestureCancelled()函數中,處理如果連續手勢被取消了該怎麼做
if(gesture == KinectGestures.Gestures.xxxxx)
{
    // gesture is cancelled - process it (for instance, clear the flag)
}
  1. 對於需要檢測新的手勢或動作的實例,需要將它作爲KinectController的組件。

如何處理連續的手勢,像是放大、縮小和轉方向盤

連續手勢並不會返回一個完全完成的布爾值,而是一個百分比,如果大於50%則報告。

  1. UserDetected()函數中,添加下面的內容manager.DetectGesture(userId, KinectGestures.Gestures.xxxxx);
  2. GestureInProgress()函數中,添加下面的內容
if(gesture == KinectGestures.Gestures.xxxxx)
{
    if(progress > 0.5f)
    {
        // gesture is detected - process it (for instance, set a flag, get zoom factor or angle)
    }
    else
    {
        // gesture is no more detected - process it (for instance, clear the flag)
    }
}
  1. GestureCancelled()函數中,添加下面的內容
if(gesture == KinectGestures.Gestures.xxxxx)
{
    // gesture is cancelled - process it (for instance, clear the flag)
}
  1. 將其作爲KinectController的組件

如何在K2-assert中使用VGB手勢

Visual Gesture Builder創建額VGB對象也可以被用在K2-assert中。遵循下面的步驟:

  1. 將手勢數據庫(xxx.gbd)拷貝到Resources-folder並重命名它爲xxx.gbd.bytes
  2. 將VisualGestureManager-script作爲場景中一個gameobject的組件
  3. 設置VisualGestureManager-component中Gesture Database的值設爲第一步中的xxx.gbd
  4. 創建一個visual-gesture-listener來處理手勢,並將它作爲場景中Gameobject的一個組件(參考SimpleVisualGestureListener-script)
  5. GestureInProgress()函數中添加手勢監聽器的代碼來檢測連續手勢,並在GestureCompleted()函數中加入代碼來檢測離散手勢

如何創建屬於你的手勢

對於手勢識別而言,有兩種選擇:Visual gesture(用Visual Gesture Builder創建),或是預編程的手勢(被包括在KinectGestures.cs中)。對於自己的預編程手勢的創建可以參考這裏

用來證明編程性手勢的檢測的demo放在KinectDemos/GesturesDemo-folder中。第一個KinectGesturesDemo1-scene展示瞭如何使用離散手勢,第二個KinectGesturesDemo2-scene展示瞭如何使用連續手勢

這裏有一個創建和檢查visual gesture的視頻,也可以查看KinectDemos/GestureDemo/VisualGesturesDemo-scene來學習如何在Unity中使用Visual Gestrues。不過visual gesture只在32-bit下順利工作。

如何創建自己的程序性手勢

如上文所說,程序性手勢一般被定義在KinectScripts/KinectGestures.cs中或是其他的擴展這個文件的類中。手勢的檢測包括了對不同手勢狀態下手勢動作的檢查。

  1. 打開KinectScripts/KinectGestures.cs,將你的手勢名稱添加到Gestures-enum中。你需要知道,C#中enum對象時不能夠被繼承的,因此你只能夠在這裏進行修改。當然,如果你不想修改這個文件的話,可以爲你的手勢使用predefined UserGestureX-names
  2. 在打開的文件中找到CheckForGesture()方法,添加新手勢的例子,在內部switch代碼的結尾。這裏會包含着檢測手勢的代碼。
  3. gesture-case中,提那家內部的switch代碼來檢測用戶在不同階段下的手勢。如果你需要例子的話,可以查看其他的簡單手勢,比如舉左手、舉右手等。

CheckForGestures()方法中,你會訪問到jointsPos-array,這裏包含了所有的關節位置。以及jointsTracked-array,包含了關節是否被檢測到。關節位置使用的是以米爲單位的世界座標。

手勢識別代碼通常包括了對用戶在當前手勢狀態下姿態的檢測。手勢檢測總是從初始狀態0開始,你可以用初始狀態檢測手勢是否開始。比如,如果被檢測到的關節(手、腳踝等)與其他關節足夠的靠近,這意味着手勢已經開始。第暗涌SetGestureJoint()方法,保存下被檢測關節與狀態1在位置和時間上的增量。

這樣,在狀態1,你應該可以成功的檢測到手勢是否成功。比如,如果被檢測的關節移動到與其他關節的期望位置,且在預期的時間範圍之內,則成功檢測。不然的話,取消所有的手勢檢測並回到狀態0。取消可以通過調用SetGestureCancelled()方法來實現。

如果這是最後的期望狀態,那麼手勢就會結束,調用CheckPoseComplete()方法,其中最後一個參數爲0(不等待)來標記這個手勢爲完成。這樣子手勢監聽器會收到提示信息。

如果手勢已經成功了很久,但是還沒有完成,重新調用SetGestureJoint()來保存當前關節的位置和時間戳,開始再次進行手勢的增量計算。這樣就和繼續下一個手勢狀態過程,直到手勢完成。當手勢由多於兩個狀態組成時,也可以設置gestureData-structure中的progress屬性。

demo中與編程性手勢相關的場景在KinectDemos/GestureDemo-folder中。第一個時冠以如何使用離散型手勢的,第二個是關於連續性手勢的使用。

demo的學習

KinectGestureDemo1

SimpleVisualGestureListener.cs

位置爲KinectScripts-Sampels,被KinectDemos-GesturesDemo下第一個場景使用,作爲監聽器,一同使用的還有VisualGestureManager.cs

using UnityEngine;
using System.Collections;

//實現上需要繼承VisualGestureListenerInterface接口,並且實現GestureInProgress,GestureCompleted等函數(可選的樣子)
//這個文件從效果上是實現了demo裏的GUI部分,具體還需要拿到設備之後再做實驗
public class SimpleVisualGestureListener : MonoBehaviour, VisualGestureListenerInterface
{
	[Tooltip("GUI-Text to display the discrete gesture information.")]
	public GUIText discreteInfo;

	[Tooltip("GUI-Text to display the continuous gesture information.")]
	public GUIText continuousInfo;


	private bool discreteGestureDisplayed;
	private bool continuousGestureDisplayed;

	private float discreteGestureTime;
	private float continuousGestureTime;


	public void GestureInProgress(long userId, int userIndex, string gesture, float progress)
	{
		if(continuousInfo != null)
		{
			string sGestureText = string.Format ("{0} {1:F0}%", gesture, progress * 100f);
			continuousInfo.GetComponent<GUIText>().text = sGestureText;

			continuousGestureDisplayed = true;
			continuousGestureTime = Time.realtimeSinceStartup;
		}
	}

	public bool GestureCompleted(long userId, int userIndex, string gesture, float confidence)
	{
		if(discreteInfo != null)
		{
			string sGestureText = string.Format ("{0}-gesture detected, confidence: {1:F0}%", gesture, confidence * 100f);
			discreteInfo.GetComponent<GUIText>().text = sGestureText;

			discreteGestureDisplayed = true;
			discreteGestureTime = Time.realtimeSinceStartup;
		}

		// reset the gesture
		return true;
	}
	
	public void Update()
	{
		// clear gesture infos after a while
		if(continuousGestureDisplayed && ((Time.realtimeSinceStartup - continuousGestureTime) > 1f))
		{
			continuousGestureDisplayed = false;

			if(continuousInfo != null)
			{
				continuousInfo.GetComponent<GUIText>().text = string.Empty;
			}
		}

		if(discreteGestureDisplayed && ((Time.realtimeSinceStartup - discreteGestureTime) > 1f))
		{
			discreteGestureDisplayed = false;
			
			if(discreteInfo != null)
			{
				discreteInfo.GetComponent<GUIText>().text = string.Empty;
			}
		}
	}

}

VisualGestureManager.cs

這個是與上面那個一起在同一個demo裏面出現的,但看了好幾遍我都沒有明白這個VS的Manager是用來幹什麼的。

CubeGestureListener.cs

這個是掛載在方塊KinectController上的,與KinectManager腳本掛在同一個對象上。

這裏面的CubeGestureListener實現了KinectGestures.GestureListenerInterface,如果想要學習動作監聽器實現的話還是要看這代碼

核心部分就是三個布爾值swipeLeft/Right/Up,表示是否發生了這三個動作,其他的代碼都是爲更新這三個值並根據這三個值的變化進行動作。

可以看到,程序具體實現了GestureInProgressGestureCompleted等函數,這些函數在KinectGestures.cs中被定義,且在KinectManager.cs中作爲監聽器的方法被調用。

KinectManager.cs的實現方法:

  • 所有實現了GestureListenerInterface的MonoBehaviour對象全部被自動加入到gestureListeners列表之中。
  • 在Update函數中,週期性的檢查拿到的gestureData,如果gestureData.complete,則調用監聽器的GestureCompleted方法。其他如此類推。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章