ARKit-平面檢測(cè)與可視化

翻譯自:https://blog.markdaws.net

相關(guān)工程地址:https://github.com/markdaws/arkit-by-example

在我們的第一個(gè)hello world ARKit應(yīng)用中我們?cè)O(shè)置了我們的工程并在真實(shí)的世界中渲染了一個(gè)虛擬的3D立方體宗苍,并且會(huì)在你四周移動(dòng)的時(shí)候持續(xù)追蹤

在這篇文章中熔任,我們會(huì)著眼于在真實(shí)場(chǎng)景中提取3D幾何體的信息并且將它進(jìn)行可視化。檢測(cè)幾何體對(duì)于增強(qiáng)現(xiàn)實(shí)的應(yīng)用是非常重要的拭抬,因?yàn)槿绻阆胱龅胶驮谡鎸?shí)世界一樣的交互你需要知道用戶(hù)點(diǎn)擊了桌子上梧税、正在看地板或者其他和平常生活類(lèi)似的3D交互

ARKit可以檢測(cè)平面沦疾。一旦我們檢測(cè)到了一個(gè)平面称近,我們可以把他進(jìn)行可視化,然后把這個(gè)平面的規(guī)格和角度展現(xiàn)出來(lái)

計(jì)算機(jī)視覺(jué)

在我們深入代碼之前哮塞,理解清楚在ARKit下面發(fā)生了什么是非常有用的刨秆,因?yàn)檫@個(gè)技術(shù)還不完美,有很多情況會(huì)降低或者影響到你的應(yīng)用的表現(xiàn)

AR的目的就是可以在真實(shí)世界的特別的點(diǎn)上插入虛擬的內(nèi)容忆畅,并且當(dāng)你在真實(shí)的世界移動(dòng)的時(shí)候可以持續(xù)的追蹤衡未。ARKit的基本處理流程會(huì)把iOS的攝像頭采集到的視頻流的每一幀進(jìn)行處理然后把特征點(diǎn)提取出來(lái)。特征點(diǎn)可以是很多東西家凯,但是你如果想去在圖片中檢測(cè)出有趣的特征點(diǎn)你可以在多個(gè)幀中進(jìn)行追蹤缓醋。一個(gè)特征點(diǎn)可能是一個(gè)物體的一個(gè)角或者一個(gè)布的紋理的一個(gè)邊等等。有很多方法去生成這些特征點(diǎn)绊诲,你可以在網(wǎng)上讀到更多的信息送粱,但對(duì)于我們的目標(biāo)指導(dǎo)我們可以從一個(gè)圖像中提取到很多獨(dú)特的進(jìn)行認(rèn)證的特征點(diǎn)就夠了

一旦你有了這些特征點(diǎn),你就可以在多幀之間追蹤這些特征點(diǎn)不論你走到哪里掂之,你可以獲取這些相關(guān)點(diǎn)然后估計(jì)3D姿態(tài)信息抗俄,比如說(shuō)當(dāng)前的攝像頭位置以及這些特征點(diǎn)的位置。當(dāng)用戶(hù)移動(dòng)的越多世舰,我們就會(huì)獲得更多的特征點(diǎn)动雹,這些3D姿態(tài)估計(jì)也會(huì)得到改善

在平面檢測(cè)中,一旦你有了一定數(shù)量的特征點(diǎn)冯乘,你就可以嘗試把平面對(duì)著那些點(diǎn)放到合適的位置洽胶,然后在尺寸晒夹、角度和位置上找到最佳的匹配裆馒。ARKit在持續(xù)分析這些特征點(diǎn)然后在代碼中向我們報(bào)告所有他找到的平面

下面是我手機(jī)在檢測(cè)我的沙發(fā)扶手的一個(gè)截屏,你可以看到這個(gè)布有很好的紋理丐怯,大量的獨(dú)特又有趣的特征點(diǎn)可以被追蹤到喷好,每一個(gè)十字星就是一個(gè)ARKit找到的獨(dú)特的特征點(diǎn)

sofafeatures
sofafeatures

下一張圖片是我照我的冰箱門(mén)的,你可以注意到這并沒(méi)有幾個(gè)特征點(diǎn)

doorfeatures
doorfeatures

這是非常重要的读跷,因?yàn)闉榱俗孉RKit檢測(cè)到特征點(diǎn)你必須摘到有足夠多的特征點(diǎn)的東西去檢測(cè)梗搅。那些會(huì)造成糟糕的特征點(diǎn)提取的情況有:

  1. 糟糕的光線(xiàn)--弱光或者帶有高光反射的強(qiáng)光。杜絕有糟糕光線(xiàn)的環(huán)境
  2. 缺少紋理--如果你把相機(jī)對(duì)準(zhǔn)一個(gè)白墻效览,這里真的沒(méi)有什么特別的東西用來(lái)提取无切,ARKit就不能找到并且追蹤你。杜絕對(duì)準(zhǔn)一些純色或者發(fā)光的區(qū)域
  3. 快速移動(dòng)--這對(duì)于ARKit是情況各異的丐枉,通常如果你只是用圖片去檢測(cè)和估計(jì)3D姿態(tài)哆键,如果你移動(dòng)攝像頭太快你就會(huì)得到一些糟糕的圖片這會(huì)造成追蹤的失敗。不過(guò)ARKit用了叫做VIO的算法瘦锹,所以ARKit除了用圖像信息以外還用到了設(shè)備運(yùn)動(dòng)傳感器的信息去估計(jì)用戶(hù)的姿態(tài)籍嘹。這讓ARKit在追蹤上面很健壯

添加可視化的調(diào)試信息

在我們開(kāi)始之前闪盔,給應(yīng)用添加一些調(diào)試信息是非常有用的,也就是渲染原始的世界的同時(shí)也把ARKit檢測(cè)到的特征點(diǎn)信息渲染出來(lái),這是很有用的可以讓你知道你是不是在一個(gè)可以追蹤的很好的地方辱士。要做到這個(gè)你可以在我們的ARSCNView實(shí)例中打開(kāi)調(diào)試選項(xiàng):

self.sceneView.debugOptions = ARSCNDebugOptionShowWorldOrigin | ARSCNDebugOptionShowFeaturePoints;

檢測(cè)平面幾何體

在ARKit中你可以通過(guò)在你的會(huì)話(huà)配置中設(shè)置planeDetection屬性指定你想要檢測(cè)水平面泪掀。這個(gè)值可以被設(shè)置為ARPlaneDetectionHorizontal或者ARPlaneDetectionNone

一旦你設(shè)置了這個(gè)屬性,你就開(kāi)始得到ARSCNViewDelegate的回調(diào)信息颂碘。這里有很多的方法异赫,我們要用到的第一個(gè)是

/**
Called when a new node has been mapped to the given anchor.
@param renderer The renderer that will render the scene.
@param node The node that maps to the anchor.
@param anchor The added anchor.
*/
- (void)renderer:(id <SCNSceneRenderer>)renderer
    didAddNode:(SCNNode *)node
    forAnchor:(ARAnchor *)anchor {
}

這個(gè)方法在ARKit每次認(rèn)為他檢測(cè)到了一個(gè)新的平面時(shí)進(jìn)行回調(diào)。我們會(huì)得到兩個(gè)信息头岔,node和anchor祝辣。這個(gè)SCNNode實(shí)例是一個(gè)ARKit創(chuàng)建的SceneKit node,他有一些屬性可以設(shè)置比如位置和角度切油,然后我們還得到了anchor的實(shí)例蝙斜,這個(gè)告訴我們這個(gè)被找到的anchor更多的信息,比如說(shuō)尺寸以及這個(gè)平面的中心

這個(gè)anchor是ARPlaneAnchorl類(lèi)型的澎胡,從這里我們可以得到這個(gè)平面的擴(kuò)展和中心信息

渲染平面

有了上面的信息孕荠,我們現(xiàn)在可以在虛擬的世界里畫(huà)一個(gè)SceneKit 3D平面。我們創(chuàng)建了一個(gè)Plane類(lèi)繼承自SCNNode去做這件事情攻谁。在構(gòu)建方法里面我們創(chuàng)建了這個(gè)平面以及設(shè)置他的尺寸:

// Create the 3D plane geometry with the dimensions reported
// by ARKit in the ARPlaneAnchor instance
self.planeGeometry = [SCNPlane planeWithWidth:anchor.extent.x height:anchor.extent.z];
SCNNode *planeNode = [SCNNode nodeWithGeometry:self.planeGeometry];
// Move the plane to the position reported by ARKit
planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
// Planes in SceneKit are vertical by default so we need to rotate
// 90 degrees to match planes in ARKit
planeNode.transform = SCNMatrix4MakeRotation(-M_PI / 2.0, 1.0, 0.0, 0.0);
// We add the new node to ourself since we inherited from SCNNode
[self addChildNode:planeNode];

既然我們有了自己的Plane類(lèi)稚伍,回到ARSCNViewDelegate的回調(diào)方法,我們可以在ARKit報(bào)告了新的Anchor時(shí)創(chuàng)建我們的Plane:

- (void)renderer:(id <SCNSceneRenderer>)renderer 
    didAddNode:(SCNNode *)node 
    forAnchor:(ARAnchor *)anchor {
if (![anchor isKindOfClass:[ARPlaneAnchor class]]) {
    return;
}
Plane *plane = [[Plane alloc] initWithAnchor: (ARPlaneAnchor *)anchor];
[node addChildNode:plane];
}

更新平面

如果你運(yùn)行了上面的程序戚宦,當(dāng)你向四周走動(dòng)時(shí)你可以看到新的平面在虛擬世界中渲染出來(lái)个曙,盡管這些平面不是在你走動(dòng)的時(shí)候合適的增長(zhǎng)的。ARKit在持續(xù)的分析這個(gè)場(chǎng)景受楼,當(dāng)它發(fā)現(xiàn)一個(gè)平面比他之前預(yù)計(jì)的大了或者笑了的時(shí)候垦搬,他會(huì)更新這個(gè)平面的擴(kuò)展值。所以我們需更新已經(jīng)渲染了的Plane

我們可以通過(guò)ARSCNViewDelegate中的一個(gè)方法得到這些更新的信息:

- (void)renderer:(id <SCNSceneRenderer>)renderer 
didUpdateNode:(SCNNode *)node 
    forAnchor:(ARAnchor *)anchor {
// See if this is a plane we are currently rendering
Plane *plane = [self.planes objectForKey:anchor.identifier];
if (plane == nil) {
    return;
}
[plane update:(ARPlaneAnchor *)anchor];
}

在我們的Plane類(lèi)的update方法中我們可以更新平面的寬度和高度:

- (void)update:(ARPlaneAnchor *)anchor {
self.planeGeometry.width = anchor.extent.x;
self.planeGeometry.height = anchor.extent.z;
// When the plane is first created it's center is 0,0,0 and 
// the nodes transform contains the translation parameters. 
// As the plane is updated the planes translation remains the 
// same but it's center is updated so we need to update the 3D
// geometry position
self.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
}

現(xiàn)在我們已經(jīng)讓平面渲染和更新了艳汽,我們可以進(jìn)到應(yīng)用里面看看了

提取信息的結(jié)果

下面是我檢測(cè)的視頻的一些截圖

這是廚房的猴贰,ARKit做得很好,準(zhǔn)確的找到了平面的擴(kuò)展信息和角度信息河狐,正好貼合這個(gè)平面

kitchenplane
kitchenplane

這是地板的米绕,你可以看到當(dāng)你在四周走動(dòng)的時(shí)候,ARKit在持續(xù)的鋪滿(mǎn)新屏幕馋艺,這在你開(kāi)發(fā)應(yīng)用的時(shí)候是一個(gè)要注意的點(diǎn)栅干,用戶(hù)必須一上來(lái)就在四周走動(dòng)一圈然后再放置東西,所以在幾何體還不是足夠好到能用的時(shí)候給用戶(hù)好的視覺(jué)上的提示是一個(gè)很重要的部分

floorplane
floorplane

下面是和上面同一場(chǎng)景幾秒鐘之后的效果捐祠,ARKit已經(jīng)把所有的平面整合成了一個(gè)平面碱鳞。提示,在ARSCNViewDelegate中你需要處理這樣的情況當(dāng)ARKit合并幾個(gè)平面時(shí)會(huì)刪除一些ARPlaneAnchor的實(shí)例

floorplane2
floorplane2

這是一個(gè)很有趣的場(chǎng)景雏赦,我在樓上距離地面大概有12到15英尺劫笙,在糟糕的光線(xiàn)條件下芙扎,ARKit依然可以提取出一個(gè)平面,難以置信填大!

aboveplane
aboveplane

這是一個(gè)梯子旁邊的比較窄的墻戒洼,注意平面在實(shí)際的表面邊緣超出部分是怎么延伸的

smallplane
smallplane

重要的結(jié)論

  1. 不要期望于一個(gè)平面可以完美的對(duì)齊表面,你可以從視頻里面看出來(lái)允华,平面被檢測(cè)出來(lái)圈浇,但是角度可能會(huì)不準(zhǔn)確,所以你如果開(kāi)發(fā)一個(gè)應(yīng)用想要得到一個(gè)特別準(zhǔn)確的幾何體你可能會(huì)失望

  2. 邊緣不是特別好靴寂,平面經(jīng)常會(huì)大一點(diǎn)或者小一點(diǎn)磷蜀,不要試著做一個(gè)需要完美的對(duì)齊的應(yīng)用

  3. 追蹤很健壯并且很快百炬,你可以看到我移動(dòng)的很快但是追蹤的依然很棒

  4. 特征點(diǎn)檢測(cè)的效果很好褐隆,在糟糕的光線(xiàn)和較遠(yuǎn)的距離下依然檢測(cè)到了一些平面

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末剖踊,一起剝皮案震驚了整個(gè)濱河市庶弃,隨后出現(xiàn)的幾起案子德澈,更是在濱河造成了極大的恐慌,老刑警劉巖梆造,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缴守,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镇辉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)摊聋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鸡捐,“玉大人栈暇,你說(shuō)我怎么就攤上這事≡雌恚” “怎么了煎源?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵香缺,是天一觀(guān)的道長(zhǎng)手销。 經(jīng)常有香客問(wèn)我,道長(zhǎng)图张,這世上最難降的妖魔是什么锋拖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任诈悍,我火速辦了婚禮,結(jié)果婚禮上兽埃,老公的妹妹穿的比我還像新娘侥钳。我一直安慰自己,他們只是感情好柄错,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布舷夺。 她就那樣靜靜地躺著,像睡著了一般售貌。 火紅的嫁衣襯著肌膚如雪给猾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天颂跨,我揣著相機(jī)與錄音敢伸,去河邊找鬼。 笑死恒削,一個(gè)胖子當(dāng)著我的面吹牛详拙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔓同,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼饶辙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了斑粱?” 一聲冷哼從身側(cè)響起讯壶,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碍侦,沒(méi)想到半個(gè)月后呐能,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尚揣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年涌矢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片快骗。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娜庇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出方篮,到底是詐尸還是另有隱情名秀,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布藕溅,位于F島的核電站匕得,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏巾表。R本人自食惡果不足惜汁掠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望考阱。 院中可真熱鬧晋南,春花似錦、人聲如沸负间。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)政溃。三九已至态秧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間申鱼,已是汗流浹背愤诱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淫半,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓匣砖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親猴鲫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子对人,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 在第一個(gè) hello world ARKit app 里我們給項(xiàng)目做了初始設(shè)置拂共,并在真實(shí)世界里渲染了一個(gè) 3D 立...
    張嘉夫閱讀 13,787評(píng)論 15 49
  • ARKit ARKit框架通過(guò)集成iOS設(shè)備攝像頭和運(yùn)動(dòng)功能,在您的應(yīng)用程序或游戲中產(chǎn)生增強(qiáng)現(xiàn)實(shí)體驗(yàn)宜狐。 概述 增強(qiáng)...
    暗夜夜夜行路閱讀 5,786評(píng)論 0 17
  • 村上說(shuō)肉體才是我們的神殿势告,好好供奉她,才是實(shí)現(xiàn)我們美好生活的根本培慌。當(dāng)身體疲憊不堪時(shí)候真的什么都不想做不想動(dòng)想都覺(jué)得...
    肉月閱讀 273評(píng)論 0 0
  • 我建立了一個(gè)關(guān)于各個(gè)行業(yè)的銷(xiāo)售交流群,大一起討論銷(xiāo)售經(jīng)驗(yàn)柑爸,你要有興趣參加嗎盒音?群里有很多銷(xiāo)售資料都是討論留下馅而,很不錯(cuò)...
    25579笨小孩閱讀 2,204評(píng)論 0 1
  • 但他并不看好火爆全國(guó)的P2P互聯(lián)網(wǎng)金融,曾多次公開(kāi)批評(píng)譬圣,而且早于2014年就暫停了P2P網(wǎng)貸公司的審批。 ” 在黃...
    泡個(gè)小菜閱讀 765評(píng)論 1 0