王明東
?
基于Kinect骨骼跟蹤功能實(shí)現(xiàn)PC的手勢(shì)控制
王明東1,2
(1.華僑大學(xué) 計(jì)算機(jī)學(xué)院,福建 廈門(mén) 361000;2.黎明職業(yè)大學(xué) 計(jì)算機(jī)與信息工程系,福建 泉州 362000)
主要介紹了基于Kinect骨骼跟蹤功能開(kāi)發(fā)一套手勢(shì)模擬鼠標(biāo)操作的設(shè)計(jì)思路與實(shí)現(xiàn)方法,以實(shí)現(xiàn)對(duì)計(jì)算機(jī)的遠(yuǎn)距離手勢(shì)遙控。
Kinect;骨骼跟蹤;手勢(shì)控制
微軟幾年前就預(yù)測(cè)計(jì)算領(lǐng)域的下一個(gè)重大變革是圖形用戶界面向自然用戶界面的轉(zhuǎn)移,Kinect便是自然用戶界面應(yīng)用的成功案例。Kinect是一種3D體感攝影機(jī)主要用來(lái)進(jìn)行體感游戲動(dòng)作捕捉。Kinect所有動(dòng)作捕捉和識(shí)別都是做在硬件設(shè)備里面,且微軟并沒(méi)有對(duì)Kinect的輸出做任何加密。于是,基于Kinect的各種應(yīng)用層出不窮,如:虛擬試衣間、體感購(gòu)物、Kinect Robot等。隨著2011年6月微軟推出Kinect for Windows SDK Beta,基于Kinect應(yīng)用開(kāi)發(fā)成為計(jì)算機(jī)應(yīng)用領(lǐng)域研究的一個(gè)熱點(diǎn)。
Kinect有三個(gè)Camera,其中中間的一個(gè)是RGB Camera,用來(lái)獲取640x480的彩色圖像,每秒鐘最多獲取30幀圖像;兩側(cè)是兩個(gè)景深(3D Depth)傳感器,使用紅外線檢測(cè)玩家的相對(duì)位置,原理和人眼立體成像是一樣的;Kinect兩側(cè)各有兩組麥克風(fēng)用來(lái)做3D語(yǔ)音識(shí)別,能夠把聲源附近之內(nèi)各種各樣信息捕捉到;下邊底座內(nèi)有一個(gè)馬達(dá)用來(lái)調(diào)整Kinect的仰角。【1】
2.2.1獲取原始傳感器流
從深度傳感器,彩色攝像頭傳感器,和四個(gè)麥克風(fēng)陣列,獲得原始數(shù)據(jù)流。使開(kāi)發(fā)人員能夠基于低級(jí)別的Kinect感應(yīng)器生成的數(shù)據(jù)流進(jìn)行開(kāi)發(fā)。
2.2.2骨骼跟蹤(Skeleton Tracking)
跟蹤Kinect的監(jiān)測(cè)領(lǐng)域內(nèi)的一個(gè)或兩個(gè)人的骨架圖像的能力,使創(chuàng)建手勢(shì)驅(qū)動(dòng)的應(yīng)用程序可以很容易。Kinect最多可以追蹤每個(gè)人的20個(gè)骨骼點(diǎn),目前只能追蹤人體[2]。是Kinect的核心技術(shù),正因?yàn)橛辛诉@項(xiàng)技術(shù),很多有趣的功能才得以實(shí)現(xiàn)。圖2介紹了Kinect骨骼點(diǎn)的分布情況。
2.2.3先進(jìn)的音頻能力
音頻處理能力包括先進(jìn)的噪音抑制和回聲消除,波束形成以確定當(dāng)前的聲源,并與Windows語(yǔ)音識(shí)別API集成。

圖1 Kinect整體結(jié)構(gòu)

圖2 Kinect骨骼點(diǎn)的分布情況

圖3 屏幕區(qū)域劃分
運(yùn)用Kinect的骨骼跟蹤(Skeleton Tracking)功能,捕獲操作者骨骼點(diǎn)的運(yùn)動(dòng),并將相關(guān)骨骼點(diǎn)的運(yùn)動(dòng)信息通過(guò)API函數(shù)SendInput映射成鼠標(biāo)的相關(guān)動(dòng)作,從而實(shí)現(xiàn)手勢(shì)操控。具體方法:
①將左手的移動(dòng)轉(zhuǎn)換成鼠標(biāo)的移動(dòng)。
②將右手在不同區(qū)域的上下?lián)]動(dòng)轉(zhuǎn)換成鼠標(biāo)的左右鍵單擊,首先將計(jì)算機(jī)的屏幕劃分為四個(gè)區(qū)域如圖3。當(dāng)右手在右鍵區(qū)域位置高于AB時(shí)表示為按下鼠標(biāo)右鍵,再回落到AB下面時(shí)表示放開(kāi)鼠標(biāo)右鍵;當(dāng)右手在左鍵區(qū)域位置高于AB時(shí)表示為按下鼠標(biāo)左鍵,再回落到AB下面時(shí)表示放開(kāi)鼠標(biāo)左鍵;如此一上一下表示一次單擊。
③以左右滕蓋的距離(大于一個(gè)閥值)表示啟用滾輪, 右手水平揮動(dòng)以CD為界一個(gè)來(lái)回表示一次后滾;右手上下?lián)]動(dòng)以AB為界一個(gè)來(lái)回表示一次前滾。

圖4SkeletonFrameReady參數(shù)對(duì)象結(jié)構(gòu)
當(dāng)Kinect正確識(shí)別操作者時(shí)SkeletonFrameReady事件被觸發(fā)來(lái)處理骨骼跟蹤,該事件的參數(shù)包含兩個(gè)重要的對(duì)象:SkeletonFrame和Skeletons(SkeletonData對(duì)象)(參見(jiàn)圖4[3])。在SkeletonData對(duì)象的Joints屬性集合中保存了所有骨骼點(diǎn)的信息。每個(gè)骨骼點(diǎn)的信息都是一個(gè)Joint對(duì)象,其中的Position的X、Y、Z表示了三維位置。其中X和Y的范圍都是-1到1,而Z是Kinect到識(shí)別對(duì)象的距離。
基于Kinect開(kāi)發(fā)一套手勢(shì)模擬鼠標(biāo)操作,要解決的關(guān)鍵問(wèn)題:將骨骼點(diǎn)的平面坐標(biāo)X和Y的取值[-1,1]轉(zhuǎn)換成在屏幕的位置值[4]。可以用下面的代碼,將Joint的位置縮放到合適的比例:
Joint scaledLeft = skeleton.Joints[JointID.HandLeft].ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
上面的語(yǔ)句相當(dāng)于將骨骼點(diǎn)的平面坐標(biāo),X:由-SkeletonMaxX到SkeletonMaxX的范圍擴(kuò)大為0到屏幕的寬度的范圍,Y:由-SkeletonMaxY到SkeletonMaxY的范圍擴(kuò)大為0到屏幕的高度的范圍。
下面是在VS2010環(huán)境下運(yùn)用WPF實(shí)現(xiàn)手勢(shì)模擬鼠標(biāo)移動(dòng)、左右鍵單擊的源代碼。
3.3.1鼠標(biāo)控制類(lèi)代碼:
//定義鼠標(biāo)數(shù)據(jù)結(jié)構(gòu)
internal struct MouseInput
{ public int X;
public int Y;
public uint MouseData;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
internal struct Input
{ public int Type;
public MouseInput MouseInput;
}
public static class MouseSetting
{ public const int InputMouse = 0;
public const int MouseEventMove = 0x01;
public const int MouseEventKeyDown = 0x02;
public const int MouseEventLeftUp = 0x04;
public const int MouseEventRightDown = 0x08;
public const int MouseEventRightUp = 0x10;
private static bool lastDown; //標(biāo)識(shí)鼠標(biāo)鍵的前一狀態(tài), true表示按下
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint numInputs, Input[] inputs, int size);
public static void SendMouseInput(int positionX, int positionY, int maxX, int maxY, bool MouseClick, int keyType)
// positionX, positionY:鼠標(biāo)位置;maxX, maxY:鼠標(biāo)移動(dòng)范圍;MouseClick:是否按下鍵; keyType:標(biāo)識(shí)左右鍵
{ Input[] i = new Input[2];
//移動(dòng)鼠標(biāo)
i[0] = new Input();
i[0].Type = InputMouse;
i[0].MouseInput.X = (positionX * 65535) / maxX;
i[0].MouseInput.Y = (positionY * 65535) / maxY;
i[0].MouseInput.Flags = MouseEventAbsolute | MouseEventMove;
//判斷要發(fā)送的鼠標(biāo)事件
if (keyType == 1)
{ if (!lastDown && MouseClick)
{ i[1] = new Input();
i[1].Type = InputMouse;
i[1].MouseInput.Flags = MouseEventKeyDown; }
else if (lastDown && ! MouseClick)
{ i[1] = new Input();
i[1].Type = InputMouse;
i[1].MouseInput.Flags = MouseEventLeftUp; }
lastDown = MouseClick; //記錄當(dāng)前鼠標(biāo)狀態(tài)
}
else
{ if (!lastDown && MouseClick)
{ i[1] = new Input();
i[1].Type = InputMouse;
i[1].MouseInput.Flags = MouseEventRightDown; }
else if (lastDown && ! MouseClick)
{ i[1] = new Input();
i[1].Type = InputMouse;
i[1].MouseInput.Flags = MouseEventRightUp; }
lastDown = MouseClick;
}
// 將鼠標(biāo)事件通知操作系統(tǒng)
uint result = SendInput(2, i, Marshal.SizeOf(i[0]));
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}}
3.3.2骨骼跟蹤代碼:
public partial class MainWindow : Window
{ private float MouseDownThreshold = 0.10f;//將屏幕分為按下與放開(kāi)區(qū)域(圖4 AB的位置)。
private float LeftRightThreshold = -0.12f;//將屏幕分為左右鍵區(qū)域(圖4 CD的位置)。
private const float SkeletonMaxX = 0.50f;//界定骨骼跟蹤的水平范圍
private const float SkeletonMaxY = 0.33f; //界定骨骼跟蹤的垂直范圍
private Runtime _runtime = new Runtime(); //聲明并實(shí)例化一個(gè)kinect運(yùn)行時(shí)對(duì)象
private int userid = -1;//用于記錄用戶的userindex
private void Window_Loaded(object sender, RoutedEventArgs e)
{ //指定用于骨骼跟蹤的用戶處理事件
_runtime.SkeletonFrameReady += _runtime_SkeletonFrameReady;
try { // 初始化Kinect對(duì)象,并告訴Kinect將用到景深與骨骼信息
_runtime.Initialize(RuntimeOptions.UseDepth|RuntimeOptions.UseSkeletalTracking);
} catch (Exception ex)
{ MessageBox.Show("Could not initialize Kinect device: " + ex.Message); }
}
void _runtime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{ SkeletonData sd = e.SkeletonFrame.Skeletons.First();
//將第一個(gè)被捕獲者固定為操控者
if (userid == -1) { userid = sd.UserIndex; }
foreach (SkeletonData sd1 in e.SkeletonFrame.Skeletons)
{ if (sd1.TrackingState == SkeletonTrackingState.Tracked)
{ if (userid == 0)
{ userid = sd1.UserIndex;
sd = sd1;
break; }
else
if (sd1.UserIndex == userid)
{ sd = sd1;
break; }
} }
//確保雙手被跟蹤
if (sd.Joints[JointID.HandLeft].TrackingState == JointTrackingState.Tracked &&
sd.Joints[JointID.HandRight].TrackingState == JointTrackingState.Tracked)
{ int cursorX, cursorY;
//取得左右手的骨骼點(diǎn)
Joint jointRight = sd.Joints[JointID.HandRight];
Joint jointLeft = sd.Joints[JointID.HandLeft];
//將左手的骨骼點(diǎn)的位置信息換算成對(duì)應(yīng)的主屏幕的寬度和高度
Joint scaledLeft = jointLeft.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
//根據(jù)左手的位置找出鼠標(biāo)光標(biāo)的位置
cursorX = (int)scaledLeft.Position.X;
cursorY = (int)scaledLeft.Position.Y;
bool MouseClick; //標(biāo)識(shí)是否按下鼠標(biāo)鍵
int keyType; //標(biāo)識(shí)鼠標(biāo)左右鍵
//根據(jù)右手的位置找出鼠標(biāo)左/右鍵是否按下
if (jointRight.Position.Y > MouseDownThreshold)
MouseClick = true;
else
MouseClick = false;
if (jointRight.Position.X < LeftRightThreshold)
keyType = 1; //左鍵
else
keyType = 2; //右鍵
SendMouseInput(cursorX, cursorY, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, MouseClick, keyType);
return;
} }
Kinect在精確定位上尚有不足;但基于Kinect骨骼跟蹤實(shí)現(xiàn)的手勢(shì)模擬鼠標(biāo)操作可以通過(guò)懸停選擇和手勢(shì)控制等簡(jiǎn)單且容易理解的控制方式方便的實(shí)現(xiàn)計(jì)算機(jī)的遙感控制,據(jù)此可以開(kāi)發(fā)出很多有趣的應(yīng)用。
[1] 馬寧博客:http://www.cnblogs.com/aawolf/archive/2011/06/17/2083249.html[EB/OL].
[2] Kinect SDK的開(kāi)發(fā)指南:http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/guides.aspx[EB/OL].
[3] Kinect SDK API Reference[EB/OL].
[4] Kinect SDK的官方論壇:http://social.msdn.microsoft.com/Forums/en-US/kinectsdk/threads[EB/OL].
Virtualizing gesture control of PC by Skeleton Tracking through Kinect
WANG Ming-dong1,2
(1.School of Computer Science,Huaqiao University,Xiamen 361000,China;2.Computer and Information Engineering department; Liming Vocational University; Quanzhou Fujian 362000)
The article explores the application of gesture-imitating mouse action by Skeleton Tracking through Kinect, to realize the remote gesture control of PC.
Kinect;Skeleton Tracking;Gesture control
(責(zé)任編輯:季平)
2012-03-10
王明東(1976—),男,福建泉州人,講師,在讀碩士,主要從事管理信息系統(tǒng)方面的研究。
TP312
A
1673-1417(2012)02-0011-06