2011 年 6 月所提供下載的 SDK 為 Beta 版,目前提供用於 non-commercial (非商業用途),例如:研究、展示、開發測試、教學用途;也可以此 SDK 進行教學、以 blog 等型式進行分享或透過為人寫 AP 收費,亦可先行以此 SDK 開發未來作為商業使用的應用程式。詳細條款說明,請參考 SDK 下載網站及 EULA 說明。
1. Kinect SDK 介紹與開發環境安裝 3. Kinect 深度影像擷取與深度計算 5. 玩家任意背景替換應用 7. 繪製人體骨架與多人骨架追蹤 9. Kinect 聲音錄製 | 2. Kinect 初始化與彩色影像擷取 4. 透過深度資料辨認玩家位置 6. 骨架追蹤與螢幕座標轉換 8. 骨架追蹤範例 - 操控光劍與地球 |
Kinect 體感遊戲在Xbox 360 上獲得極高的好評,但是對於 Windows 平台上的開發卻一直只能使用非官方的解決方案,例如 NKinect (http://nkinect.codeplex.com) 配合CL NUI SDK (http://codelaboratories.com/nui);但是微軟終於在 2011 年 6 月推出了 Kinect for Windows SDK Beta,特別是可以使用 C# 與.NET Framework 4.0 來進行開發,這對 .NET 開發人員來說無疑是 2011 年最好的消息了。
Kinect for Windows SDK : http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk
本篇文章將詳細的介紹在 Windows 7 上開發 Kinect 應用程式所需要的一切知識,包含硬體原理、開發環境安裝、SDK 的使用與 API 呼叫方式,相信可以協助你一步一步的進入 Kinect 神奇的開發領域。
.jpg)
Kinect 感應器可以取得以下三種資訊:
Kinect 也支援追焦功能,底座馬達會隨著焦點人物而轉動 Kinect 方向 (左右各 28 度),下表是 Kinect 的詳細規格:
| 感應項目 | 有效範圍 |
|---|---|
| 顏色與深度 | 1.2 ~ 3.6 公尺 |
| 骨架追蹤 | 1.2 ~ 3.6 公尺 |
| 視野角度 | 水平 57 度、垂直 43 度 |
| 底座馬達旋轉 | 左右各 28 度 |
| 每秒畫格 | 30 FPS |
| 深度解析度 | QVGA (320 x 240) |
| 顏色解析度 | VGA (640 x 480) |
| 聲音格式 | 16KHz, 16 位元 mono pulse code modulation (PCM) |
| 聲音輸入 | 四麥克風陣列、24 位元類比數位轉換 (ADC)、雜音消除 |
在進行 Kinect 應用程式開發之前,你需要準備好相關的軟硬體,需求如下:
.jpg)
MSRKINECTSDK=C:\Program Files (x86)\Microsoft Research KinectSDK\
.jpg)
.jpg)
這個工具包主要是將一些在開發 Kinect 應用程式時會使用到的程式碼整理成擴充方法,讓你在開發 Kinect 應用程式時可以簡化程式碼的撰寫。
.jpg)
Kinect 的 NUI 程式庫提供應用程式取得 Kinect 感應器傳送至主機的三種資訊串流 (必須在初始化 API 時指定要接收那幾種串流):
下圖就是完整的 Kinect for Windows SDK 架構圖:
.jpg)
要使用 Kinect API 接收感應器的資訊,是透過 Runtime 物件,因此 Kinect 應用程式的第一步就是建立一個 Runtime 物件來準備接收感應器的資料,然後呼叫 Initialize 方法進行初始化 (指定要接收那類型的資料),在應用程式結束時要呼叫 Uninitialize 方法,關閉 Kinect 設備。
// 建立一個 Runtime 物件,代表 Kinect 設備
Runtime nui = new Runtime();
// 初始化設備
nui.Initialize();
// 開始使用 Runtime 物件的方法、事件,
// 取得影像、骨架資料、控制攝影機
// 關閉設備
nui.Uninitialize();其中你可以透過 Device 物件的 Count 屬性來取得目前主機上總共連接了幾台 Kinect 設備,在建立 Runtime 物件時,可以在建構式參數中加上所要連接的 Kinect 設備編號
Device d = new Device();
if (d.Count > 0)
{
int index = 0;
// 建立一個 Runtime 物件,index 代表 Kinect 設備的編號
Runtime nui = new Runtime(index);
}NUI API 初始化選項:
例如:
// 要取得彩色影像串流、深度與玩家編號的影像串流、追蹤骨架資訊
nui.Initialize(
RuntimeOptions.UseColor |
RuntimeOptions.UseDepthAndPlayerIndex |
RuntimeOptions.UseSkeletalTracking
);彩色影像就是 RGB 攝影機所拍到的動態影像畫面 (如下圖左邊的影像):
.jpg)
nui.VideoStream.Open(ImageStreamType.Video, 2,ImageResolution.Resolution640x480, ImageType.Color);那麼該如何擷取彩色影像呢? 在使用了RuntimeOptions.UseColor 初始化 Runtime 物件後,就可以開始在 Runtime 物件的 VideoFrameReady 事件中接收彩色影像:
nui.Initialize(RuntimeOptions.UseColor);
nui.VideoFrameReady += new
EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);
nui.VideoStream.Open(ImageStreamType.Video, 2,
ImageResolution.Resolution640x480, ImageType.Color);void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
{
PlanarImage data = e.ImageFrame.Image;
image1.Source = BitmapSource.Create(data.Width, data.Height, 96, 96,
PixelFormats.Bgr32, null, data.Bits, data.Width * data.BytesPerPixel);
}如果覺得呼叫 BitmapSource.Create 方法太麻煩,可以使用 Coding4Fun 函式庫中的 ToBitmapSource 擴充方法
void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
{
// 使用 Coding4Fun 函式庫,image1 是 WPF 的 Image 控制項
image1.Source = e.ImageFrame.ToBitmapSource();
}深度影像就是由紅外線發射器和紅外線 CMOS 攝影機共同取得的動態影像畫面 (如下圖右邊的影像):
.jpg)
.jpg)
那麼該如何擷取深度影像呢? 在使用了 RuntimeOptions. UseDepth 初始化 Runtime 物件後,就可以開始在 Runtime 物件的 DepthFrameReady 事件中接收深度影像:
nui.Initialize(RuntimeOptions.UseDepth);
nui.DepthFrameReady += new
EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrameReady);
nui.DepthStream.Open(ImageStreamType.Depth, 2,
ImageResolution.Resolution640x480, ImageType.Depth);void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)
{
// 使用 Coding4Fun 函式庫,image2 是 WPF 的 Image 控制項
image2.Source = e.ImageFrame.ToBitmapSource();
}Kinect 的骨架追蹤系統可以在感應器可視範圍內主動追蹤最多兩位玩家的骨架,骨架追蹤系統可以在感應器可視範圍內主動追蹤最多兩位玩家的骨架,如果某一個玩家被主動追蹤,那麼在呼叫 SkeletonEngine.GetNextFrame 時會取得該玩家完整的骨架資訊,預設只有前兩個玩家是主動被追蹤的。背動骨架追蹤預設是啓動的,可以額外追蹤 4 個玩家,但是由於處理速度的因素,背動追蹤下的骨架資訊有限。
.jpg)
.jpg)
NUI 骨架API 提供最多兩個玩家的骨架位置與方向的資訊,應用程式取得的是一堆座標的集合,稱為骨架關節位置 (skeleton joint positions),因此在初始化 NUI 時一定要指定要使用骨架資料,並且啓動骨架追蹤。
NUI API 初始化骨架追蹤的方式:
Runtime nui = new Runtime();
nui.Initialize(RuntimeOptions.UseSkeletalTracking);
nui.SkeletonFrameReady +=
new EventHandler<SkeletonFrameReadyEventArgs>(
nui_SkeletonFrameReady);骨架資訊取得方式和取得彩色影像資訊類似,可以使用輪詢模型 (呼叫 SkeletonEngine.GetNextFrame 方法) 或事件模型 (在 SkeletonFrameReady 事件中讀取 e.SkeletonFrame.Skeletons 屬性)。
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
// 迴圈有可能跑多次 (多個玩家被追蹤)
foreach(SkeletonData data in e.SkeletonFrame.Skeletons)
{
// 只要處理正在被追蹤的玩家
if (data.TrackingState == SkeletonTrackingState.Tracked)
{
JointCollection jc = data.Joints;
Vector v = jc[JointID.Head].Position;
// 處理關節座標 v
}
}
}其中你可以透過 SkeletonData 的Joints 集合來取得某一個玩家的所有關節的 3D 座標,你可以使用 JointID 這個列舉來指定要取得那一個關節的座標,例如 SkeletonData.Joints[JointID.Head].Position 可以取得玩家頭部的 3D 座標(Vector 型別),所有的關節位置與名稱如下圖:
.jpg)
關節資料說明:
如果你要將關節 3D 座標轉換成螢幕上的 2D 座標時,例如要在畫面上繪製人體骨架位置,可以使用以下這個函式:
Point GetDisplayPosition(Joint joint)
{
float depthX, depthY;
nui.SkeletonEngine.SkeletonToDepthImage(
joint.Position, out depthX, out depthY);
// 轉換到 320 x 240 空間系統
depthX = Math.Max(0, Math.Min(depthX * 320, 320));
depthY = Math.Max(0, Math.Min(depthY * 240, 240));
int colorX, colorY;
nui.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(
ImageResolution.Resolution640x480, new ImageViewArea(),
(int)depthX, (int)depthY, (short)0, out colorX, out colorY);
return new Point(colorX * picColorVideo.Width / 640,
colorY * picColorVideo.Height / 480);
}另外,由於有時候因為人體的快速動作,例如微小但是高頻率發生的抖動、或者突然的大跳動,都會造成關節的雜訊,因此可以啓動關節平順化的處理功能:
.jpg)
Kinect for Windows SDK 的出現為個人電腦平台帶來了全新的應用程式操作方式,操作電腦不再侷限於鍵盤和滑鼠,透過 Kinect,不只是遊戲,只要你有創意,就可以在 Windows 7 平台上開發出有趣又有商機的 Kinect 應用。