利用Kinect將投影變得可直接用手操控

Finally

總算是到了這一天了!假期裏算法想不出來,或者被BUG折磨得死去活來的時候,老是YY着何時能心情愉快地坐在電腦前寫一篇項目總結,今天總算是抽出時間來總結一下這神奇的幾個月。javascript

如今回過頭來看,上學期退出ACM集訓隊果真是對的,此次開發學到的東西太多太多,之前在ACM的時候,感受不會的東西好多啊,真正來本身試着開發個東西,發現不會的東西果真好多。不過要是幾個老師知道我上午給新生作完ACM宣講報告下午就跟教練說退出,他們會是什麼心情啊哈哈。html

這些是第一次嘗試開發,若是ACM是練內功的話,那麼練了三年也總該讓我拿出來用用了,否則學了三年仍是隻在個控制檯裏玩甚是寂寞,本身親手從無到有創造出一個東西來的感受, 實在太爽了!java

先說一下此次項目印象最深的幾個教訓:算法

  1. 功能一旦變得複雜,就必定要在紙上先畫一畫!
    • 流程圖也好,大致思路圖也行,甚至隨手演算的過程均可以,總之必定要把思路理清楚了,思路不清的後果就是代碼越寫越亂,最後只能所有推倒重來,事先不畫圖省下的時間遠遠比不上最後重寫所浪費的時間。
  2. 命名必定要規範
    • 之前刷題的時候,也知道命名規範的重要性,只是沒想到會如此重要。以前個人代碼風格還算不錯,不過一開始寫的時候還偷下懶,省掉一兩個單詞之類,有時心急了還直接用原來的命名方法,用下劃線分割單詞(Kinect的API裏都是用大小寫分割單詞的),這樣寫的弊端就是代碼也是愈來愈亂,並且一旦有事中斷了幾天,回來再看代碼就發現看不懂了,因而又簡單粗暴推倒重來。因此必定要有一套本身的命名風格,並且不要爲了省事少些那一兩個單詞,敲個長變量名所帶來的是代碼的高可讀性,多耗費的時間遠遠小於之後推倒重來所浪費的時間!
  3. 不寫沒必要要的註釋
    • 處處都是註釋,反而大大下降了可讀性,一眼看去全是綠的,頭都暈了,開發中期我就被本身那麼多的註釋弄得看見綠代碼就想吐,後期只註釋主要功能,提升抽象程度,代碼反而變得清晰有邏輯。因此那種基本每行都有註釋的風格,我並不認同,固然,我說的是代碼基本僅供本身一我的看的狀況。
  4. 最好進行版本控制
    • 有一次就是,我作了個比較微小的改動,結果怎麼調都不對,也已經忘了改動以前是什麼狀態,簡直是有種欲哭無淚的感受。還有就是進行一個大的改動以後,忽然發現以前的那個版本纔是對的(哭)。有個版本控制機制的話,這種狀況應該能避免不少。
  5. 迭代開發彷佛是個不錯的辦法
    • 以前在知乎上看到一個貼,講的是新手應該怎樣進行開發,提到的一種思路就是進行迭代開發。一開始可能什麼都不懂,而後着手作了一部分以後,就對項目有了個大概的輪廓,而後推翻進行新的一輪開發,這時又對將來該怎麼作有更清晰的瞭解,這樣不斷迭代把項目逐步推向成熟。我是迭代了4次以後出了目前這個基本完成的版本,不過在寫的時候沒刻意考慮過用這種方法,之因此迭代了4次是由於上面提到的種種緣由致使推翻重來(捂臉),不過如今看來這種方法好像真的很合理。

項目介紹

好了,如今正式開始介紹一下項目自己。小程序

背景

這個項目本來是用來參加2016年的微軟創新杯,可是在上一週,也就是3月20號的四川省區域賽中未獲獎,只能直接參戰中國區半決賽。此次區域賽失敗的緣由有不少,雖然做品已經完成得差很少了,可是沒能優秀地將其展現出來,在現成演示的時候還遇到了一個巨大失誤,中途才發現,因此沒等通知結果就知道多半是悲劇了。第一次參加這類開發類的比賽,就當交學費好了,不過此次區域賽給個人感受是,微軟仍是想找幾個最有商業前途的做品,這個項目炫是很炫酷,可是實際意義不大的樣子,因此感受中國區半決賽但願也不大。不過無所謂啦,我本身玩得嗨就好了,微軟欣不欣賞那是另一回事,說不定哪天我就搭建出個鋼鐵俠那樣的實驗室不是?啊哈哈,最近也順便把這個項目報成了大學生創新創業訓練計劃,成功申請到國家級,算是能夠安慰一下。測試

目標

簡單來講,此項目就是要把投影儀投出的投影變得能夠直接用裸手操控,就好像投影變成了一塊大型的平板電腦,投影能夠是在投影幕上、牆上甚至桌子上,任何光滑且不是反射材質的平面都行,至於爲何不能是反射材質,等下會有介紹。剛開始是計劃達到能用手指直接在投影上寫字的精度,後來發現很難作到,瓶頸在於指尖的識別算法不夠精確,這是我本身構思的一個簡單算法,將來應該會用更高級更精確的算法來替代。優化

開發環境

Kinect for Windows V2 + Kinect SDK 2.0 + OpenCV 3.0 + Visual Studio Community 2015spa

Kinect

項目裏利用到的一個很是重要的東西就是Kinect for Windows V2,一款微軟的動做感應器,能夠算成是一類現實加強設備,發佈時主要是搭配XBox來玩體感遊戲,可是這麼厲害的一個東西只能用來玩遊戲實在太惋惜,因此微軟在前幾天發佈了它的Windows版本,讓它可以在PC上進行開發。就是下面這麼個東西:
版本控制

原理

原理其實並不算難,主要能夠參考下面這張圖。
code

  1. 從Kinect獲取的整個畫面中識別出投影
    • 由於操做要在投影上進行,因此須要先識別出投影是畫面中的哪一塊,這裏用的算法比較簡單,先投一副純色圖像出來,而後利用投影區RGB值近似的原理,找出投影的左下角和右上角以後就肯定了投影的區域,這樣作的缺點是投影區只能是矩形並且不能太歪。其實有時間的話,能夠試一下利用9*9的矩陣來找出全部屬於邊緣的點,而後渲染全部邊緣點,也就找出了整個邊緣,這樣能夠適應任意形狀。
  2. 從Kinect獲取的整個畫面中識別出指尖
    • 由於用手指來調用鼠標進行操做,而接觸屏幕的地方又是手指的指尖,因此須要識別出指尖。

    一開始我是基於KinectBodyIndex這個數據源來尋找指尖,首先定位出腕關節在哪,而後根據腕關節的位置向上尋找複合指尖特徵的點,能夠說效果很好,識別很是精確和穩定,並且能同時識別出5個指尖,這部分是我在假期裏完成的,原本覺得來到學校後將程序根據投影儀調整下就差很少能夠用了,然而到校測試後才發現一個致命的問題,就是當手臂貼近牆壁時,整個手臂的BodyIndex數據都丟失了。由於微軟彷佛認爲,若是某個點要是屬於人體的話,那麼它和背景的深度差至少要有二三十釐米左右(正好是人體的厚度)。這個問題讓我失眠了幾晚上...不過也是在失眠的時候想出瞭如今用的解決方法。ds

    如今用的方法是基於`Depth`數據來找指尖的,簡單來講就是根據指尖的特色找出全部吻合的點,而後取 位置最高的那個(由於操做的時候用的基本都是一根手指),這樣作能夠減小不少工做量,由於不少非法點都直接被略去了。
  3. 將手指的位置映射成鼠標的位置
    • 由於想達到手指指哪,鼠標就點擊哪的效果,因此必須把手指在投影上的位置,映射成鼠標在電腦裏相應的位置,這個其實簡單推導一下就能夠得出。

      黑色框爲投影屏幕,大寫的X和Y表明的是屏幕的寬和高,紅色框爲電腦屏幕,假設人的手指在的位置,若是想將鼠標也映射到一樣的位置,那麼就有  的等比關係成立。這裏投影屏幕的寬和高在上面第一步中獲取,而電腦屏幕的寬和高,其實是不須要考慮分辨率的,由於在鼠標的座標系下,電腦的寬和高都被分紅了65535個單位,因此寬和高能夠視爲65535。根據這些,就能夠算出的值來。

  4. 根據手指到屏幕的距離,判斷點擊和非點擊兩種狀態
    • Kinect是帶有深度攝像頭的,也就是說它可以知道畫面中的每一點到它的距離。彷佛是利用三組紅外發射器來實現,因此也就要求物體不能是反射材質,否則會獲取不到距離。由於可以知道屏幕的距離,也能知道手指的距離,因此若是手指距離屏幕足夠近,那麼就能夠判斷爲點擊。可是,屏幕有可能不是絕對垂直的,Kinect也有擺歪的可能性,同時深度數據也不是100%精確,因此在計算屏幕距離時,須要考慮一個容錯值,在這個範圍內都被視爲屏幕,在這裏我設置的值是10cm,雖然看上去不少,可是實際效果還不錯。可是,這也帶來一個很嚴重的問題,就是手指在離屏幕的位置小於10cm的時候,也被視爲了屏幕,這時候指尖就丟失了,手指變成了手指中部(由於手指不是徹底平行於牆面的,而是有必定角度,因此指根的地方距離屏幕更遠),這就會產生很不穩定的現象,至今沒有解決。

上面就是核心的功能,除此以外,還要加入一些鼠標的抖動消除、偏差消除的處理,同時我還調用了Kinect的手勢識別功能,直接用手勢來完成撤銷的操做。這段時間忙着找實習,之後有時間的話,應該會優化指尖識別的算法,同時加入更多的手勢來調用操做。

效果展現

(博客園的MarkDown竟然不能夠插視頻,差評)

演示視頻在這裏

直接在牆上玩割繩子:

用手在牆上書寫(外加用手勢來調用撤銷):

直接裸手操控PPT:

END

這個項目差很少就這麼多啦,剩下的只是優化下各個功能,或者加點新東西進去。從假期裏就構思了一個比較有意思的小程序,等這段時間忙結束,應該就會把它敲出來。真是愈來愈好玩了!

相關文章
相關標籤/搜索