本文會使用到我開發的兩個開源模組:「python-module-yolo11」開箱即用的 YOLO11 Python 程式、「unity-module-yolo11 (MDF YOLO11)」則是配合第一個模組來用的套件。而因為 python-module-yolo11 是一支獨立的程式關係,讓這個遊戲專案只能用於展示科技,不適合打包成執行檔給玩家使用。
這兩個模組皆開源,任何人都能任意使用,如果能放個超連結到這篇文章的話我會很感謝你~
網路視訊鏡頭
我們的動作捕捉會用 YOLO11 來開發,因此無須購買 Kinect 之類的硬體,只要連接一個網路視訊鏡頭 (Webcam)。
取得 YOLO11 的 Python 模組
首先前往 python-module-yolo11 的 Releases 網頁,下載 1.0.0 版本的 Source Code。
下載後是一個壓縮檔,請將檔案解壓縮到一個空間充足的位置 (至少留個 3GB~,未來還有機會再增長)。
解壓縮後,雙點擊 install.bat 來啟動安裝程式。
安裝程式主要會設定好 Python 的可攜式執行環境,並下載安裝 YOLO 模型、OSC 套件等必要功能,需要穩定的網路來下載。
當畫面最後一直出現如下圖中的提示,代表 YOLO11 模組已安裝完成,而且可以順利執行!如果要關閉,請按下鍵盤 Ctrl + C 後再點擊 y 來關閉。
如果要再次啟動 YOLO11 模組,可以直接雙點擊 start.bat 來啟動,不需要再安裝一次。
取得 YOLO11 的 Unity 模組
接下來請建立一個 Unity 6 的新專案,如果專案已內建 URP,可先點擊 Remove Readme Assets 來移除無關內容。
選擇 Proceed 並等待系統執行完成。
接下來,請從頂部選單的 Window 開啟 Package Manager。
點開左上角的 + 號,選擇 Install package from git URL。
分兩次將以下兩個網址複製貼上並點擊 Install。
1https://github.com/keijiro/OscJack.git?path=Packages/jp.keijiro.osc-jack#2.0.0
1https://github.com/tedliou/unity-module-yolo11.git#1.0.0
最後 Package Manager 將會安裝好 OSC Jack 與 MDF YOLO11。OSC Jack 是一個網路傳輸的功能,MDF YOLO11 會用它來和 python-module-yolo11 模組溝通。
建立示範場景
開啟預設的 Sample Scene,建立一個空物件 GameObject 和方塊 (Cube)、圓球 (Sphere)、圓柱體 (Cylinder) 各一個,並且在 GameObject 上掛上 Body Tracker 腳本 (MDF YOLO11 模組提供的功能)。
Body Tracker 有提供動作捕捉要追蹤的關節設定 (Tracking Joints),預設為追蹤鼻子和左右手腕。
接下來我們要來撰寫程式碼,讓剛才建立的方塊、圓球和圓柱體的座標能同步到鼻子、左手腕、右手腕的關節位置。自行建立一個 CustomManager.cs 腳本。
CustomManager.cs 建立好後,將內容直接替換成以下程式碼,程式碼的說明已使用註解寫在程式碼內,如有問題可以在留言區或到 GitHub 發 Issue/PR。
1using MDF.YOLO11;
2using UnityEngine;
3
4// 將方塊 (Cube)、圓球 (Sphere)、圓柱體 (Cylinder) 分別移動到
5// YOLO 偵測到的第一個人的鼻子、左手腕、右手腕的關節位置
6public class CustomManager : MonoBehaviour
7{
8 // 公開變數
9 // 鼻子 (Cube)、左手腕 (Sphere)、右手腕 (Cylinder)
10 public GameObject nose, leftWrist, rightWrist;
11
12 // 遊戲開始時監聽 BodyTracker 的更新事件
13 // UpdateCubes 被呼叫時代表 YOLO 有順利追蹤到肢體
14 private void Start()
15 {
16 GetComponent<BodyTracker>().ValueChanged += UpdateCubes;
17 }
18
19 // YOLO 追蹤到肢體時會一直呼叫這個
20 // 分別從肢體追蹤的結果中取出座標,並移動物件到指定座標 (關節的座標)
21 // COCOKeypoint.XXXX 是關節的名稱
22 private void UpdateCubes(BodyKeypoint keypoints)
23 {
24 UpdateJointObject(keypoints, COCOKeypoint.Nose, nose);
25 UpdateJointObject(keypoints, COCOKeypoint.LeftWrist, leftWrist);
26 UpdateJointObject(keypoints, COCOKeypoint.RightWrist, rightWrist);
27 }
28
29 // 取出第一個人的指定關節座標,並轉換成世界座標
30 // 讓物件在遊戲畫面上的位置等同於 YOLO 看到的位置
31 private void UpdateJointObject(BodyKeypoint keypoints, COCOKeypoint joint, GameObject targetObj)
32 {
33 var point = keypoints[0][joint];
34
35 // 如果有勾選 Body Tracker 的 Invert X 或 Invert Y
36 // 沒偵測到的關節有可能會是 0 或 1 的初始值
37 // 當座標為初始值時要當作無效座標,將物件隱藏
38 if (IsInvisiable(point))
39 {
40 targetObj.SetActive(false);
41 return;
42 }
43
44 var screenPos = new Vector3(Screen.width * point.x, Screen.height * point.y, Mathf.Abs(Camera.main.transform.position.z));
45 var worldPos = Camera.main.ScreenToWorldPoint(screenPos);
46 targetObj.transform.position = worldPos;
47 targetObj.SetActive(true);
48 }
49
50 // 最好要用 Mathf.Approximately 來比對浮點數的座標
51 // 因浮點數偶爾會有誤差,用 == 可能會出 Bug
52 private bool IsInvisiable(Vector2 point)
53 {
54 return
55 (Mathf.Approximately(point.x, 1) || Mathf.Approximately(point.x, 0)) &&
56 (Mathf.Approximately(point.y, 1) || Mathf.Approximately(point.y, 0));
57 }
58}
最後回到 Unity,將剛才建立的方塊、圓球和圓柱體分別拖曳到 Nose、Left Wrist 與 Right Wrist 欄位,一套簡單的系統即開發完成。
效果預覽
啟動 python-module-yolo11 與執行 Unity 專案,現在遊戲應該已能捕捉到你的動作,並且將三個物件的位置同步到你的鼻子與左右手腕中。
示範專案
本文所使用的 Unity 專案也已上傳至 GitHub,歡迎多加利用:tedliou/unity-tutorial-yolo11