深度学习及AR在移动端打车场景下的应用
本文內容根據作者在美團Hackathon 4.0中自研的項目實踐總結而成。作為美團技術團隊的傳統節目,每年兩次的Hackathon已經舉辦多年,產出很多富于創意的產品和專利,成為工程師文化的重要組成部分。本文就是2017年冬季Hackathon 4.0一個獲獎項目的實踐總結。
前言
2017年在移動端直接應用AI算法成為一種主流方向。Apple也在WWDC 2017上重磅推出Core ML框架。準備Hackathon的過程中,我們就想能否基于Core ML的深度學習能力,結合AR,做酷一點的產品。我們觀察到在晚上下班時間,是公司的打車高峰時段,這時候經常會有一堆車在黑暗中打著雙閃,你很難通過辨認車牌去找到你叫的專車,所以我們把產品定向為一個打車時幫助用戶找到車的App。
很快我們就把上面的想法落地實現了,開發了一個叫做WhereAreYou的簡單App應用,相當于AR版本的微信共享位置,只要打開攝像頭就可以看到小伙伴們的方位和遠近。當然了,應用于打車場景下,就是讓用戶知道目標車輛從何駛來、距離多遠。程序大概結構如圖1所示:
遠距離下使用AR幫助用戶找到目標方位
我們用Node.js寫了一個簡單的服務,用戶可以創建一個共享位置的group,其他用戶拿到groupID后可以加入這個組,接著程序會通過服務來共享他們各自的GPS信息,同一個group內的成員可以在地圖上看到其他成員的位置。值得一提的是,我們添加了一個AR模式,成員點擊AR按鈕后可以進入,此時攝像頭會被打開,如果同一個組的其他小伙伴方位距離此用戶很近,屏幕上就會出現一個3D模型,告訴用戶附近有某某小伙伴,距離此地的遠近等信息。主要過程和效果如圖2所示:
項目做到這里都很順利,接下來就遇到了一些難點,主要是利用ARKit渲染模型的部分。其中有一個問題是如何把兩個GPS空間上的方位反映到用戶屏幕上,經過一些努力,我們終于攻克這個難關,這里可以分享一點干貨:
那么問題來了,如何將一個3D模型顯示在屏幕正中央 \(\gamma\) 處呢?這里就用到了ARKit的ARSCNView中的模型渲染API,跟OpenGL類似,ARSCNView從創建之初會設置一個3D世界原點并啟動攝像頭,隨著手機的移動,攝像頭相當于3D世界中的一個眼睛,可以用一個觀察矩陣[camera]表示。這樣在屏幕正中央俯視偏角 \(\gamma\) 處渲染一個3D節點的問題,其實就是如何才能把觀測坐標轉換為世界坐標的問題。我們首先將物體放在手機前3米處,然后直接根據下圖所示公式就可求得最終坐標:
下面是在ARSCNView每次重新渲染回調中設置模型位置的邏輯:
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {guard let renderLocations = self.netGroupInfo?.locations?.filter({ (userLocation) -> Bool inreturn userLocation.userId != GroupMenberManager.sharedInstance.getCurrentUserID()}) else {return}DispatchQueue.main.async {guard let camera = self.sceneView.pointOfView else { return }//當前用戶定位let currentLocation = UserLocation() currentLocation.latitude = GroupMenberManager.sharedInstance.userLatitudecurrentLocation.longitude = GroupMenberManager.sharedInstance.userLongitute// 循環處理當前組內其他成員for renderLocation in renderLocations {// 兩點間距離公式求得距離用來控制3D模型字體大小,直觀的反應距離的遠近let distance = currentLocation.distanceFrom(renderLocation)// 求得兩個用戶間的坐標關系let angle = currentLocation.angleFrom(renderLocation)// 根據上述公式求得3D模型要渲染的最終位置 compassAngle為實時獲取的陀螺儀指南針方向var position = SCNVector3(x: 0, y: 0, z: -3).roateInHorizontalPlaneBy(angle: self.compassAngle - angle)position = camera.convertPosition(position, to: nil)//穩定在水平上position.y = 0;//更新位置self.virtualObjectManager.findVirtualObject(renderLocation.userId ?? "")?.scnNode.position = position//根據距離更新模型文字和大小self.virtualObjectManager.findVirtualObject(renderLocation.userId ?? "")?.changeNodeTextAnSize(text: renderLocation.userTitle, distance: distance)}}}寫了一個周末差不多把上面功能完成,這個時候對于參賽獲獎是沒有任何底氣的。因為其實這個點子并不十分新穎,技術難點也不夠。最主要的痛點是,我們真機聯調測試的時候發現,在10m范圍內GPS定位的精度完全不可靠,屏幕中渲染的點位置經常錯亂。我們之前知道近距離GPS定位會不準,卻沒想到3D模型在屏幕上對誤差的反應這么敏感,這樣的話比賽時現場演示是絕對不行的。
既然GPS近距離定位不準無法解決,我們決定在近距離時放棄GPS用另一種方式提醒用戶目標在哪里。
近距離下使用AI算法找到目標
我們做了一個設想,就是讓程序在10米范圍能夠智能地去主動尋找到目標,然后在手機屏幕上標注出來。
之后我們對視覺算法在移動端實現的現狀進行調研,發現隨著近幾年計算機視覺飛躍式發展,網上各種開源圖片分類識別算法有很多,加上2017 年年初Apple推出了非常靠譜的Core ML,所以在短時間內實現一個移動端的“目標發現”算法是可行的。
在確定WhereAreYou需要添加的功能后,我們立足于打車找車這個問題進行調研開發,最后終于實現了一個穩定、高效、實時的基于多種CNN模型混合的車輛發現跟蹤算法,下面GIF可以看到效果。
在使用完Core ML之后,真心覺得它確實如Apple在WWDC 2017上所言,性能十分優越。由此可以預見之后幾年,在移動端直接應用AI算法的優秀App會層出不窮。
扯遠了,上點干貨吧!
在說我們的《基于多種CNN模型混合的車輛發現跟蹤算法及其移動端實現》之前,先說一下Apple的Core ML能幫我們做到哪一步。
Core ML 是一個可以讓開發者很容易就能在應用中集成機器學習模型(Machine Learning Models)的應用框架,在 iOS、watchOS、macOS和tvOS上都可以使用它。Core ML使用一種新的文件格式(.mlmodel),可以支持多種類型的機器學習模型數據,比如一些深度神經網絡算法(CNN、RNN),決策樹算法(boosted trees、random forest、decision trees),還有一些廣義的線性模型(SVM、Kmeans)。Core ML models以.mlmodel文件的形式直接集成到開發應用中,文件導入后自動生成對應的工具類可直接用于分類識別等AI功能。
我們知道通過Keras、Caffe、libsvm 等開源學習框架可以生成相應的模型文件,但這些模型文件的格式并不是.mlmodel。Core ML Tools可以對這些文件進行轉換,生成.mlmodel文件,將目前比較流行的開源學習框架訓練出的模型直接應用在Core ML上,如圖8所示:
coremltools本身是一個Python工具包,它可以幫我們完成下面幾件事情:
- 第一點就是剛剛提到的將一些比較出名的開源機器學習工具(如Keras、Caffe、scikit-learn、libsvm、XGBoost)訓練出來的模型文件轉換為.mlmodel。
- 第二點是提供可以自定義轉換的API。打個比方,假設Caffe更新到了Caffe 3.0,本身模型的文件格式變了,但coremltools還沒來及更新,這時就可以利用這些API自己寫一個轉換器。
- coremltools工具本身可以使用上述所說的各種開源機器學習工具訓練好的模型進行決策。
看到這里是不是內心很澎湃?是的,有了這個工具我們可以很方便地把訓練好的模型應用到Apple設備上,所以趕緊安裝吧!步驟很簡單,機器上有Python(必須是Python 2.X)環境后執行pip install -U coremltools就好了。
那如何進行轉換呢?舉一個例子:
我們可以到Caffe Model Zoo上下載一個公開的訓練模型。比如我們下載web_car,這個模型可以用于車型識別,能夠區分奔馳、寶馬等諸多品牌的各系車型約400余種。下載好web_car.caffemodel、deploy.prototxt、class_labels.txt這三個文件,寫一個簡單的Python腳本就可以進行轉換了。
import coremltools# 調用caffe轉換器的convert方法執行轉換 coreml_model = coremltools.converters.caffe.convert(('web_car.caffemodel', 'deploy.prototxt'), image_input_names = 'data', class_labels = 'class_labels.txt')# 保存轉換生成的分類器模型文件 coreml_model.save('CarRecognition.mlmodel')coremltools同時還提供了設置元數據描述的方法,比如設置作者信息、模型輸入數據格式描述、預測輸出張量描述,較為完整的轉換腳本如下:
import coremltools# 調用caffe轉換器的convert方法執行轉換 coreml_model = coremltools.converters.caffe.convert(('googlenet_finetune_web_car.caffemodel', 'deploy.prototxt'), image_input_names = 'data', class_labels = 'cars.txt')# 設置元數據 coreml_model.author = 'Audebert, Nicolas and Le Saux, Bertrand and Lefevre Sebastien' coreml_model.license = 'MIT' coreml_model.short_description = 'Predict the brand & model of a car.' coreml_model.input_description['data'] = 'An image of a car.' coreml_model.output_description['prob'] = 'The probabilities that the input image is a car.' coreml_model.output_description['classLabel'] = 'The most likely type of car, for the given input.'# 保存轉換生成的分類器模型文件 coreml_model.save('CarRecognition.mlmodel')上面所說的“可以讓開發者很容易地在應用中集成機器學習模型”是什么意思呢?是指如果你有一個CarRecognition.mlmodel 文件,你可以把它拖入到Xcode中:
Xcode會自動生成一個叫做CarRecognition的類,直接使用其預測方法就好了。比如對一個汽車圖片做識別,像這樣:
let carModel = CarRecognition() let output = try carModel.prediction(image: ref)基于上述Core ML提供的功能結合一些開源模型算法我們完成了《基于多種CNN模型混合的車輛發現跟蹤算法及其移動端實現》。
首先說一下大概的算法流程,還記得本文一開始在圖1中提到的WhereAreYou程序結構圖嗎?現在我們在AR模塊中添加主動尋找目標的功能。當目標GPS距離小于50米時,算法被開啟。整個識別算法分為目標檢測、目標識別以及目標追蹤。當攝像頭獲取一幀圖片后會首先送入目標檢測模塊,這個模塊使用一個CNN模型進行類似SSD算法的操作,對輸入圖片進行物體檢測,可以區分出場景中的行人、車輛、輪船、狗等物體并輸出各個檢測物體在圖片中的區域信息。
我們篩選所有汽車目標,將對應物體的圖片截取后送入目標識別模塊,對車型進行識別。之后拿到識別出的車型跟車主上傳的車型進行對比,如果車主的車型跟識別出的結果一致,就將當前幀和目標區域送入目標跟蹤模塊,并對當前車輛進行持續跟蹤。當然如果跟蹤失敗就從頭進行整個過程。具體如圖10所示:
下面說一下為什么要結合這三種算法進行“尋找車主汽車”這個任務:
大家應該還記得剛剛介紹coremltools的時候舉的一個例子,在例子中我們在Caffe Model Zoo下載了一個車型識別的算法模型。沒錯,我們這個結合算法其目標識別模塊中用的車型識別正是這個模型。最初調研時,在caffe上找到這個開源模型很開心,覺得把這個模型下載好后轉換一下應用到工程中就完事了。結果發現,實際上將拍攝到的整幅圖片送入這個模型得到的識別正確率幾乎為零。分析原因是因為這個模型的訓練數據是汽車的完整輪廓,而且訓練圖片并無其它多余背景部分。而現實中用戶不可能只拍汽車,場景中汽車只是很小的一個區域,大部分還是天空、馬路、綠化帶等部分,整幅圖片不做截取直接進行處理識別率當然不行。所以只有先找到場景中的車在哪,然后再識別這個是什么車。
在一副圖片中標定場景中出現的所有車輛的位置,其實就是SSD問題(Single Shot MultiBox Detector),進一步調研可以了解到近幾年基于CNN的SSD算法層出不窮,各種論文資料也很多。其中要數康奈爾大學的YOLO算法尤為出名。更重要的是原作者提供了一個他訓練好的模型,這個模型在GitHub上就可以下載,沒錯我們結合算法其目標檢測中的模型算法就是使用的這個→_→ 。
YOLO算法的一個特性就是其檢測識別速度十分快,這是由其網絡結構和輸入結構決定的。YOLO模型輸出張量結構決定了在屏幕上如何截取對應圖片區域,這里簡單介紹一下,概念不嚴謹之處還請各位不吝賜教。如圖11所示,YOLO算法將輸入圖片分為13 × 13個小塊,每張圖片的各個小塊對應到其所屬物體的名稱和這個物體的范圍。打個比方圖11中狗尾巴處的一個小塊對應的是狗和這個狗在圖片中的位置(dog、x、y、width、height),算法支持20種物體的區分。通過網絡預測得到的張量為13 × 13 × 125。
其具體意義是一張圖片中所有小塊(共13 × 13個)每次預測得到5組結果,每組結果對應一個矩形區域信息(x、y、width、height)代表本小塊所屬的目標區域,同時給出這個區域確信是一個目標的概率(confidence,這里的“確信是一個目標”是指20種物體任意一個即可),還有 20種物體各自的確信概率。即125 = 5 × 25(x、y、width、height、confidence、Class1Confidence、Class2Cconfidence……)。了解這點后我們就不難截取最終識別結果所對應的圖片區域了(當然只選取置信率比較高的前幾個)。
圖12展示了YOLO高效地執行結果,圖13展示了YOLO目標檢測與車輛識別結合后的執行效果。
算法到此時可以算是差不多了,但從圖13中還是可以看到一些問題:
識別的結果并不是每幀圖片都是對的,而且也并不是每幀圖片都能檢測出場景中的每一個車輛。這樣就會導致在屏幕上標注車輛位置提示用戶時會出現斷斷續續。經過調研后我們又加入了目標跟蹤的模塊。目標跟蹤的任務比較好理解,輸入一幀圖片和這張圖片中的一個區域信息,要求得出下一幀中這個區域對應圖像所在位置,然后迭代此過程。目標跟蹤算法在深度學習火起來之前就比較成熟了,文獻和開源實現都比較多,我們選用 CoreML官方提供的跟蹤模塊進行處理,實驗效果發現還不錯,最終結果如上(圖7)所示。
各個模塊執行時間統計如下:
總結
《基于多種CNN模型混合的車輛發現跟蹤算法及其移動端實現》這個項目由于時間原因還有很多缺陷,誠如當時評委意見所說的那樣“核心算法都是使用網上現有模型,沒有自己進行訓練”,此算法可以提高優化的地方有很多。比如添加車輛顏色、車牌等檢測提高確認精度,優化算法在夜間、雨天等噪聲環境下的表現等。
最后,通過這個項目的開發實現讓我們知道在移動端應用CNN這樣的學習算法已經十分方便,如圖15這樣構建的移動端AI程序的執行速度和效果都很不錯。希望我們的WhereAreYou項目就像能夠幫助用戶更快找到車一樣,給前端工程師提供多一些靈感。相信未來前端工程師能做的可以做的需求會越來越有趣!
參考文獻
- [1] Yang L, Luo P, Change Loy C, et al. A large-scale car dataset for fine-grained categorization and verification[C]//Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015: 3973-3981.
- [2] Redmon J, Farhadi A. YOLO9000: better, faster, stronger[J]. arXiv preprint arXiv:1612.08242, 2016.
- [3] https://developer.apple.com/machine-learning/ .
- [4] https://pypi.python.org/pypi/coremltools .
- [5] https://github.com/caffe2/caffe2/wiki/Model-Zoo .
作者簡介
- 大衛,美團前端iOS開發工程師,2016年畢業于安徽大學,同年加入美團到店餐飲事業群,從事商家移動端應用開發工作。
總結
以上是生活随笔為你收集整理的深度学习及AR在移动端打车场景下的应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最新阿里内推高级Java面试题
- 下一篇: Spring Boot中使用MyBati