利用Kinect将投影变得可直接用手操控
Finally
總算是到了這一天了!假期里算法想不出來(lái),或者被BUG折磨得死去活來(lái)的時(shí)候,總是YY著什么時(shí)候能心情愉快地坐在電腦前寫(xiě)一篇項(xiàng)目總結(jié),今天總算是抽出時(shí)間來(lái)總結(jié)一下這神奇的幾個(gè)月。
現(xiàn)在回過(guò)頭來(lái)看,上學(xué)期退出ACM集訓(xùn)隊(duì)果然是對(duì)的,這次開(kāi)發(fā)學(xué)到的東西太多太多,以前在ACM的時(shí)候,感覺(jué)不會(huì)的東西好多啊,真正來(lái)自己試著開(kāi)發(fā)個(gè)東西,發(fā)現(xiàn)不會(huì)的東西果然好多。不過(guò)要是幾個(gè)老師知道我上午給新生做完ACM宣講報(bào)告下午就跟教練說(shuō)退出,他們會(huì)是什么心情啊哈哈。
這些是第一次嘗試開(kāi)發(fā),如果ACM是練內(nèi)功的話,那么練了三年也總該讓我拿出來(lái)用用了,不然學(xué)了三年還是只在個(gè)控制臺(tái)里玩甚是寂寞,自己親手從無(wú)到有創(chuàng)造出一個(gè)東西來(lái)的感覺(jué), 實(shí)在太爽了!
先說(shuō)一下這次項(xiàng)目印象最深的幾個(gè)教訓(xùn):
- 流程圖也好,大體思路圖也行,甚至隨手演算的過(guò)程都可以,總之一定要把思路理清楚了,思路不清的后果就是代碼越寫(xiě)越亂,最后只能全部推倒重來(lái),事先不畫(huà)圖省下的時(shí)間遠(yuǎn)遠(yuǎn)比不上最后重寫(xiě)所浪費(fèi)的時(shí)間。
- 以前刷題的時(shí)候,也知道命名規(guī)范的重要性,只是沒(méi)想到會(huì)如此重要。之前我的代碼風(fēng)格還算不錯(cuò),不過(guò)一開(kāi)始寫(xiě)的時(shí)候還偷下懶,省掉一兩個(gè)單詞之類(lèi),有時(shí)心急了還直接用原來(lái)的命名方法,用下劃線分割單詞(Kinect的API里都是用大小寫(xiě)分割單詞的),這樣寫(xiě)的弊端就是代碼也是越來(lái)越亂,而且一旦有事中斷了幾天,回來(lái)再看代碼就發(fā)現(xiàn)看不懂了,于是又簡(jiǎn)單粗暴推倒重來(lái)。所以一定要有一套自己的命名風(fēng)格,而且不要為了省事少些那一兩個(gè)單詞,敲個(gè)長(zhǎng)變量名所帶來(lái)的是代碼的高可讀性,多耗費(fèi)的時(shí)間遠(yuǎn)遠(yuǎn)小于以后推倒重來(lái)所浪費(fèi)的時(shí)間!
- 到處都是注釋,反而大大降低了可讀性,一眼看去全是綠的,頭都暈了,開(kāi)發(fā)中期我就被自己那么多的注釋弄得看見(jiàn)綠代碼就想吐,后期只注釋主要功能,提高抽象程度,代碼反而變得清晰有邏輯。所以那種基本每行都有注釋的風(fēng)格,我并不認(rèn)同,當(dāng)然,我說(shuō)的是代碼基本僅供自己一個(gè)人看的情況。
- 有一次就是,我做了個(gè)比較微小的改動(dòng),結(jié)果怎么調(diào)都不對(duì),也已經(jīng)忘了改動(dòng)之前是什么狀態(tài),簡(jiǎn)直是有種欲哭無(wú)淚的感覺(jué)。還有就是進(jìn)行一個(gè)大的改動(dòng)之后,突然發(fā)現(xiàn)之前的那個(gè)版本才是對(duì)的(哭)。有個(gè)版本控制機(jī)制的話,這種情況應(yīng)該能避免很多。
- 之前在知乎上看到一個(gè)貼,講的是新手應(yīng)該怎樣進(jìn)行開(kāi)發(fā),提到的一種思路就是進(jìn)行迭代開(kāi)發(fā)。一開(kāi)始可能什么都不懂,然后著手做了一部分之后,就對(duì)項(xiàng)目有了個(gè)大概的輪廓,然后推翻進(jìn)行新的一輪開(kāi)發(fā),這時(shí)又對(duì)未來(lái)該怎么做有更清晰的了解,這樣不斷迭代把項(xiàng)目逐步推向成熟。我是迭代了4次之后出了目前這個(gè)基本完成的版本,不過(guò)在寫(xiě)的時(shí)候沒(méi)刻意考慮過(guò)用這種方法,之所以迭代了4次是因?yàn)樯厦嫣岬降姆N種原因?qū)е峦品貋?lái)(捂臉),不過(guò)現(xiàn)在看來(lái)這種方法好像真的很合理。
項(xiàng)目介紹
好了,現(xiàn)在正式開(kāi)始介紹一下項(xiàng)目本身。
背景
這個(gè)項(xiàng)目原本是用來(lái)參加2016年的微軟創(chuàng)新杯,但是在上一周,也就是3月20號(hào)的四川省區(qū)域賽中未獲獎(jiǎng),只能直接參戰(zhàn)中國(guó)區(qū)半決賽。這次區(qū)域賽失敗的原因有很多,雖然作品已經(jīng)完成得差不多了,但是沒(méi)能優(yōu)秀地將其展示出來(lái),在現(xiàn)成演示的時(shí)候還遇到了一個(gè)巨大失誤,中途才發(fā)現(xiàn),所以沒(méi)等通知結(jié)果就知道多半是悲劇了。第一次參加這類(lèi)開(kāi)發(fā)類(lèi)的比賽,就當(dāng)交學(xué)費(fèi)好了,不過(guò)這次區(qū)域賽給我的感覺(jué)是,微軟還是想找?guī)讉€(gè)最有商業(yè)前途的作品,這個(gè)項(xiàng)目炫是很炫酷,但是實(shí)際意義不大的樣子,所以感覺(jué)中國(guó)區(qū)半決賽希望也不大。不過(guò)無(wú)所謂啦,我自己玩得嗨就行了,微軟欣不欣賞那是另外一回事,說(shuō)不定哪天我就搭建出個(gè)鋼鐵俠那樣的實(shí)驗(yàn)室不是?啊哈哈,最近也順便把這個(gè)項(xiàng)目報(bào)成了大學(xué)生創(chuàng)新創(chuàng)業(yè)訓(xùn)練計(jì)劃,成功申請(qǐng)到國(guó)家級(jí),算是可以安慰一下。
目標(biāo)
簡(jiǎn)單來(lái)說(shuō),此項(xiàng)目就是要把投影儀投出的投影變得可以直接用裸手操控,就好像投影變成了一塊大型的平板電腦,投影可以是在投影幕上、墻上甚至桌子上,任何光滑且不是反射材質(zhì)的平面都行,至于為什么不能是反射材質(zhì),等下會(huì)有介紹。剛開(kāi)始是計(jì)劃達(dá)到能用手指直接在投影上寫(xiě)字的精度,后來(lái)發(fā)現(xiàn)很難做到,瓶頸在于指尖的識(shí)別算法不夠精確,這是我自己構(gòu)思的一個(gè)簡(jiǎn)單算法,未來(lái)應(yīng)該會(huì)用更高級(jí)更精確的算法來(lái)替代。
開(kāi)發(fā)環(huán)境
Kinect for Windows V2?+?Kinect SDK 2.0?+?OpenCV 3.0?+?Visual Studio Community 2015
Kinect
項(xiàng)目里利用到的一個(gè)非常重要的東西就是Kinect for Windows V2,一款微軟的動(dòng)作感應(yīng)器,可以算成是一類(lèi)現(xiàn)實(shí)增強(qiáng)設(shè)備,發(fā)布時(shí)主要是搭配XBox來(lái)玩體感游戲,但是這么厲害的一個(gè)東西只能用來(lái)玩游戲?qū)嵲谔上?#xff0c;所以微軟在前幾天發(fā)布了它的Windows版本,讓它能夠在PC上進(jìn)行開(kāi)發(fā)。就是下面這么個(gè)東西:
原理
原理其實(shí)并不算難,主要可以參考下面這張圖。
- 因?yàn)椴僮饕谕队吧线M(jìn)行,所以需要先識(shí)別出投影是畫(huà)面中的哪一塊,這里用的算法比較簡(jiǎn)單,先投一副純色圖像出來(lái),然后利用投影區(qū)RGB值近似的原理,找出投影的左下角和右上角之后就確定了投影的區(qū)域,這樣做的缺點(diǎn)是投影區(qū)只能是矩形而且不能太歪。其實(shí)有時(shí)間的話,可以試一下利用9*9的矩陣來(lái)找出所有屬于邊緣的點(diǎn),然后渲染所有邊緣點(diǎn),也就找出了整個(gè)邊緣,這樣可以適應(yīng)任意形狀。
- 因?yàn)橛檬种竵?lái)調(diào)用鼠標(biāo)進(jìn)行操作,而接觸屏幕的地方又是手指的指尖,所以需要識(shí)別出指尖。
一開(kāi)始我是基于Kinect中BodyIndex這個(gè)數(shù)據(jù)源來(lái)尋找指尖,首先定位出腕關(guān)節(jié)在哪,然后根據(jù)腕關(guān)節(jié)的位置向上尋找復(fù)合指尖特征的點(diǎn),可以說(shuō)效果很好,識(shí)別非常精確和穩(wěn)定,而且能同時(shí)識(shí)別出5個(gè)指尖,這部分是我在假期里完成的,本來(lái)以為來(lái)到學(xué)校后將程序根據(jù)投影儀調(diào)整下就差不多可以用了,然而到校測(cè)試后才發(fā)現(xiàn)一個(gè)致命的問(wèn)題,就是當(dāng)手臂貼近墻壁時(shí),整個(gè)手臂的BodyIndex數(shù)據(jù)都丟失了。因?yàn)槲④浰坪跽J(rèn)為,如果某個(gè)點(diǎn)要是屬于人體的話,那么它和背景的深度差至少要有二三十厘米左右(正好是人體的厚度)。這個(gè)問(wèn)題讓我失眠了幾晚上...不過(guò)也是在失眠的時(shí)候想出了現(xiàn)在用的解決方法。ds
現(xiàn)在用的方法是基于`Depth`數(shù)據(jù)來(lái)找指尖的,簡(jiǎn)單來(lái)說(shuō)就是根據(jù)指尖的特點(diǎn)找出所有吻合的點(diǎn),然后取 位置最高的那個(gè)(因?yàn)椴僮鞯臅r(shí)候用的基本都是一根手指),這樣做可以減少很多工作量,因?yàn)楹芏喾欠c(diǎn)都直接被略去了。-
因?yàn)橄脒_(dá)到手指指哪,鼠標(biāo)就點(diǎn)擊哪的效果,所以必須把手指在投影上的位置,映射成鼠標(biāo)在電腦里相應(yīng)的位置,這個(gè)其實(shí)簡(jiǎn)單推導(dǎo)一下就可以得出。
黑色框?yàn)橥队捌聊?#xff0c;大寫(xiě)的X和Y代表的是屏幕的寬和高,紅色框?yàn)殡娔X屏幕,假設(shè)人的手指在的位置,如果想將鼠標(biāo)也映射到同樣的位置,那么就有??的等比關(guān)系成立。這里投影屏幕的寬和高在上面第一步中獲取,而電腦屏幕的寬和高,實(shí)際上是不需要考慮分辨率的,因?yàn)樵谑髽?biāo)的坐標(biāo)系下,電腦的寬和高都被分成了65535個(gè)單位,所以寬和高可以視為65535。根據(jù)這些,就可以算出的值來(lái)。
- Kinect是帶有深度攝像頭的,也就是說(shuō)它能夠知道畫(huà)面中的每一點(diǎn)到它的距離。似乎是利用三組紅外發(fā)射器來(lái)實(shí)現(xiàn),所以也就要求物體不能是反射材質(zhì),不然會(huì)獲取不到距離。因?yàn)槟軌蛑榔聊坏木嚯x,也能知道手指的距離,所以如果手指距離屏幕足夠近,那么就可以判斷為點(diǎn)擊。但是,屏幕有可能不是絕對(duì)垂直的,Kinect也有擺歪的可能性,同時(shí)深度數(shù)據(jù)也不是100%精確,所以在計(jì)算屏幕距離時(shí),需要考慮一個(gè)容錯(cuò)值,在這個(gè)范圍內(nèi)都被視為屏幕,在這里我設(shè)置的值是10cm,雖然看上去很多,但是實(shí)際效果還不錯(cuò)。但是,這也帶來(lái)一個(gè)很?chē)?yán)重的問(wèn)題,就是手指在離屏幕的位置小于10cm的時(shí)候,也被視為了屏幕,這時(shí)候指尖就丟失了,手指變成了手指中部(因?yàn)槭种覆皇峭耆叫杏趬γ娴?#xff0c;而是有一定角度,所以指根的地方距離屏幕更遠(yuǎn)),這就會(huì)產(chǎn)生很不穩(wěn)定的現(xiàn)象,至今沒(méi)有解決。
上面就是核心的功能,除此之外,還要加入一些鼠標(biāo)的抖動(dòng)消除、誤差消除的處理,同時(shí)我還調(diào)用了Kinect的手勢(shì)識(shí)別功能,直接用手勢(shì)來(lái)完成撤銷(xiāo)的操作。這段時(shí)間忙著找實(shí)習(xí),以后有時(shí)間的話,應(yīng)該會(huì)優(yōu)化指尖識(shí)別的算法,同時(shí)加入更多的手勢(shì)來(lái)調(diào)用操作。
效果展示
(博客園的MarkDown居然不可以插視頻,差評(píng))
演示視頻在這里
直接在墻上玩割繩子:
用手在墻上書(shū)寫(xiě)(外加用手勢(shì)來(lái)調(diào)用撤銷(xiāo)):
直接裸手操控PPT:
END
這個(gè)項(xiàng)目差不多就這么多啦,剩下的只是優(yōu)化下各個(gè)功能,或者加點(diǎn)新東西進(jìn)去。從假期里就構(gòu)思了一個(gè)比較有意思的小程序,等這段時(shí)間忙結(jié)束,應(yīng)該就會(huì)把它敲出來(lái)。真是越來(lái)越好玩了!
轉(zhuǎn)載于:https://www.cnblogs.com/czaoth/p/6027449.html
總結(jié)
以上是生活随笔為你收集整理的利用Kinect将投影变得可直接用手操控的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 软考考前冲刺第十三章UML建模
- 下一篇: wget命令下载文件