好像很多人需要這個,但是網上為數不多的代碼都是Kinect V1的,所以放出我的代碼來供大家討論。
源碼
https://github.com/Beginner258/Kinect_Cursor_Control
運行環境
- Kinect for Windows V2
- Kinect SDK 2.0
- OpenCV 3.0
使用方法
首先需要讓Kinect識別出你,建議距離0.5m以上4m以內並且正對攝像頭,如果位置合適的話瞬間就能識別出,如果幾秒鍾都沒有識別出來就請調節位置。然后將手放入操作窗口就可以控制鼠標了,綠色的點代表指尖。
效果
原理介紹
指尖識別基礎
程序的核心在於指尖識別,我發現網上關於指尖識別的資料不多,所以自己想了個很簡單的辦法,不過效果還不錯。首先應該知道三點:
1. Kinect可以分辨出畫面中哪一部分是人體
2. Kinect帶有深度攝像頭,可以獲取物體到攝像頭的距離
3. Kinect可以獲取到人體的最多25個關節點的位置
減小搜索空間
為了尋找指尖,沒有必要在整副畫面中去搜索,那樣會導致效率非常低。指尖肯定是在手部關節點(Hand
)附近的,因此只需要獲取到手部關節點的位置然后再拓展出一片區域,在這片區域里進行搜索就行了。之所以取Hand
而不是取HandTip
,是因為后者的穩定性非常差,即使在一個合適的距離正對Kinect也不一定能識別出來。
指尖識別
這時候就可以根據指尖的特征來進行指尖識別了。不過實際上我識別出的不是指尖,而是指尖上方的一點。此點的特征如下:
- 不屬於人體
- 或者屬於人體,但是和手部關節點不在同一個平面上(允許有誤差)
- 到手部關節點的位置在某個合適的范圍內
- 下面連續N(這里我取N為5)個像素都屬於人體
首先,對於第一點很好理解,因為上面說了識別的不是指尖,而是指尖上方的一點。
第二點是用來處理手移動到身邊正前方的時候的情況,比如手在胸前,這時候指尖上方的點都是屬於人體的,不滿足第一點。這里的誤差指的是手和小臂成90度時的深度差,一般15cm左右。
第三點是為了消除兩根手指根部之間的那個位置形成的誤判,同時也進一步減小了搜索空間,正常情況下手指到手腕的距離都在10~25cm范圍內,這里把拇指篩掉了,一般也不會用拇指去操作。如果要恢復拇指的話調整下參數就可以。
第四個條件篩選出了離手指尖最近的那個點。
確定操作窗口
為了便於操作和觀察,我設置了一個操作窗口,位於肩部的左上方和右上方,根據操作手的左右而調整。這個窗口就代表着電腦的屏幕,手指在窗口里的位置就是鼠標在電腦屏幕上的位置。這里窗口的大小是根據關節點Head
到Neck
的距離作為單位長度算出來的,也就是說能根據人體到Kinect的距離來調整操作窗口的大小。同時這個窗口是實時更新的,會根據人體的位置而進行調整。
這里要說一下,如果操作的位置相對固定,那么建議識別出窗口后就不要再更新,將操作窗口固定,因為這樣能夠大幅度提高鼠標的穩定性,同時上傳了一份以這種方式來做的代碼,不過這份代碼只實現了單手控制。
抖動消除
這是個不太好處理的問題,因為容易影響到正常操作。這里我設置了一個移動的閾值,如果和上一個位置相比,鼠標的位置改變很微小,那么就保持上次的位置不變。還可以再加入一個判斷位置突變的閾值,如果當前位置和上一次位置相距太遠,就可以判斷為非法而篩去。
指尖位置與鼠標位置的轉換
黑色框為程序里確定的操作窗口,大寫的X和Y代表的是屏幕的寬和高,紅色框為電腦屏幕,假設人的手指在的位置,如果想將鼠標也映射到同樣的位置,那么就有
的等比關系成立。電腦屏幕的寬和高,實際上是不需要考慮分辨率的,因為在鼠標的坐標系下,電腦的寬和高都被分成了65535個單位,所以寬和高可以視為65535。根據這些,就可以算出
的值來。