您當(dāng)前的位置是:  首頁 > 新聞 > 文章精選 >
 首頁 > 新聞 > 文章精選 >

教你如何結(jié)合WebRTC與TensorFlow實現(xiàn)圖像檢測(下篇)

2018-01-10 10:49:31   作者:Chad Hart   來源:聲網(wǎng)Agora   評論:0  點擊:


  第3部分——瀏覽器端
  開始之前,請先在項目的根目錄位置創(chuàng)建一個static目錄。我們將從這里提供HTML和JavaScript。
  現(xiàn)在,我們首先使用WebRTC的getUserMedia抓取一個本地攝像頭Feed。從這里,我們需要將該Feed的快照發(fā)送到剛剛創(chuàng)建的對象檢測Web API,獲取結(jié)果,然后使用canvas實時地在視頻上顯示這些結(jié)果。
  HTML
  我們先創(chuàng)建local.html文件:
  此網(wǎng)頁的作用如下:
  • 使用WebRTC adapter.js代碼填充(polyfill)
  • 設(shè)置一些樣式,以便
  • 將各個元素一個個疊加起來
  • 將視頻放在底部,這樣我們就能使用canvas在它上面繪圖
  • 為我們的getUserMedia流創(chuàng)建一個視頻元素
  • 鏈接到一個調(diào)用getUserMedia的JavaScript文件
  • 鏈接到一個將與我們的對象檢測API交互并在我們的視頻上繪制方框的JavaScript文件
  獲取攝像頭流
  現(xiàn)在,在靜態(tài)目錄中創(chuàng)建一個local.js文件,并將下面的代碼添加到該文件中:
  在這里你會看到我們首先設(shè)置了一些約束條件。對于我自己的情況,我需要一段1280×720視頻,但要求范圍在640×480與1920×1080之間。然后,我們使用這些約束條件執(zhí)行g(shù)etUserMedia,并將所生成的流分配給我們在HTML中創(chuàng)建的視頻對象。
  對象檢測API的客戶端版本
  TensorFlow對象檢測API教程包含了可執(zhí)行以下操作的代碼:獲取現(xiàn)有圖像,將其發(fā)送給實際API進(jìn)行“推斷”(對象檢測),然后為它所看到的對象顯示方框和類名。要想在瀏覽器中模擬這一功能,我們需要:
  • 抓取圖像——我們會創(chuàng)建一個canvas來完成這一步
  • 將這些圖像發(fā)送給API——為此,我們會將文件作為XMLHttpRequest中form-body的一部分進(jìn)行傳遞
  • 再使用一個canvas將結(jié)果繪制在我們的實時流上
  • 要完成所有這些步驟,需要在靜態(tài)文件夾中創(chuàng)建一個objDetect.js文件。
  初始化和設(shè)置
  我們需要先定義一些參數(shù):
  你會注意到,我將其中一些參數(shù)作為data-元素添加到了自己的HTML代碼中。我最終是要在多個不同的項目中使用這段代碼,并且希望重用相同的代碼庫,而如此添加參數(shù)就可以輕松做到這一點。待具體使用這些參數(shù)時,我會一一解釋。
  設(shè)置視頻和canvas元素
  我們需要一個變量來表示我們的視頻元素,需要一些起始事件,還需要創(chuàng)建上面提到的2個canvas。
  drawCanvas用于顯示我們的方框和標(biāo)簽。imageCanvas用于向我們的對象檢測API上傳數(shù)據(jù)。我們需要向可見HTML添加drawCanvas,這樣我們就能在繪制對象框時看到它。接下來,需要跳轉(zhuǎn)到ObjDetect.js底部,逐函數(shù)向上編寫。
  啟動該程序
  1.觸發(fā)視頻事件
  我們來啟動該程序。首先要觸發(fā)一些視頻事件:
  先查找視頻的onplay事件和loadedmetadata事件——如果沒有視頻,圖像處理也就無從談起。我們需要用到元數(shù)據(jù)來設(shè)置我們的繪圖canvas尺寸,使其與下一部分中的視頻尺寸相符。
  2.啟動主對象檢測子例程
  雖然drawCanvas必須與視頻元素大小相同,但imageCanvas絕不會顯示出來,只會發(fā)送到我們的API?梢允褂梦募_頭的uploadWidth參數(shù)減小此大小,以幫助降低所需的帶寬量和服務(wù)器上的處理需求。需要注意的是,減小圖片可能會影響識別準(zhǔn)確度,特別是圖片縮減得過小的時候。
  至此我們還需要為drawCanvas設(shè)置一些樣式。我選擇的是cyan,但你可以任選顏色。只是要確保所選的顏色與視頻Feed對比明顯,從而提供很好的可見度。
  3.toBlob conversion
  設(shè)置好canvas大小后,我們需要確定如何發(fā)送圖像。一開始我采取的是較為復(fù)雜的方法,結(jié)果看到Fippo的grab()函數(shù)在最后一個KrankyGeek WebRTC事件處,所以我又改用了簡單的toBlob方法。待圖片轉(zhuǎn)換為blob(二進(jìn)制大對象)后,我們就會將它發(fā)送到我們要創(chuàng)建的下一個函數(shù),即postFile。
  有一點需要注意——Edge似乎不支持HTMLCanvasElement.toBlob方法。好像可以改用此處推薦的polyfill或改用msToBlob,但這兩個我都還沒有機(jī)會試過。
  將圖像發(fā)送至對象檢測API
  我們的postFile接受圖像blob作為實參。要發(fā)送此數(shù)據(jù),我們需要使用XHR將其作為表單數(shù)據(jù)通過POST方法發(fā)布。不要忘了,我們的對象檢測API還接受一個可選的閾值,所以在這里我們也可以加入此閾值。為便于調(diào)整,同時避免操作此庫,你可以在我們在開頭設(shè)置的data-標(biāo)記中加入此參數(shù)及其他一些參數(shù)。
  我們設(shè)置好表單后,需要使用XHR來發(fā)送它并等待響應(yīng)。獲取到返回的對象后,我們就可以繪制它們(見下一個函數(shù))。這樣就大功告成了。由于我們想要持續(xù)不斷地執(zhí)行上述操作,因此我們需要在獲取到上一API調(diào)用返回的響應(yīng)后,立即繼續(xù)抓取新圖像并再次發(fā)送。
  繪制方框和類標(biāo)簽
  接下來我們需要使用一個函數(shù)來繪制對象API輸出,以便我們可以實際查看一下檢測到的是什么:
  由于我們希望每次都使用一個干凈的繪圖板來繪制矩形,我們首先要使用clearRect來清空canvas。然后,直接使用class_name對項目進(jìn)行過濾,然后對剩余的每個項目執(zhí)行繪圖操作。
  在objects對象中傳遞的坐標(biāo)是以百分比為單位表示的圖像大小。要在canvas上使用它們,我們需要將它們轉(zhuǎn)換成以像素數(shù)表示的尺寸。我們還要檢查是否啟用了鏡像參數(shù)。如果已啟用,我們需要翻轉(zhuǎn)x軸,以便與視頻流翻轉(zhuǎn)后的鏡像視圖相匹配。最后,我們需要編寫對象class_name并繪制矩形。
  讓我們試一下吧!
  現(xiàn)在,打開你最喜歡的WebRTC瀏覽器,在地址欄中輸入網(wǎng)址。如果你是在同一臺計算機(jī)上運行,網(wǎng)址將為http://localhost:5000/local(如果設(shè)置了證書,則為https://localhost:5000/local)。
  關(guān)于優(yōu)化
  上述設(shè)置將通過服務(wù)器運行盡可能多的幀。除非為Tensorflow設(shè)置了GPU優(yōu)化,否則這會消耗大量的CPU資源(例如,我自己的情況是消耗了一整個核心),即便不作任何改動也是如此。更高效的做法是,限制調(diào)用該API的頻率,僅在視頻流中有新活動時才調(diào)用該API。為此,我在一個新的objDetectOnMotion.js文件中對objDetect.js做了一些修改。
  修改前后內(nèi)容大致相同,我只不過添加了2個新函數(shù)。首先,不再是每次都抓取圖像,而是使用一個新函數(shù)sendImageFromCanvas(),僅當(dāng)圖片在指定的幀率內(nèi)發(fā)生了變化時,該函數(shù)才發(fā)送圖片。幀率用一個新的updateInterval參數(shù)表示,限定了可以調(diào)用該API的最大間隔。為此,我們需要使用新的canvas和內(nèi)容。
  這段代碼很簡單:
  imageChangeThreshold是一個百分比,表示有改動的像素所占的百分比。我們獲得此百分比后將其傳遞給imageChange函數(shù),此函數(shù)返回True或False,表示是否超出了閾值。下面顯示的就是這個函數(shù):
  上面的這個函數(shù)其實是經(jīng)過大幅改進(jìn)后的版本,之前的版本是我很久以前編寫的,用于在動作檢測嬰兒監(jiān)視器程序中檢測嬰兒動作。它首先測量每個像素的RGB顏色值。如果這些值與該像素的總體顏色值相比絕對差值超過10,則將該像素視為已改動。10只是隨意定的一個值,但在我的測試中似乎是很合適的值。如果有改動的像素數(shù)超出threshold,該函數(shù)就會返回True。
  對此稍微深入研究后,我發(fā)現(xiàn)其他一些算法通常轉(zhuǎn)換成灰度值,因為顏色并不能很好地反映動作。應(yīng)用高斯模糊也可以消除編碼差異。Fippo提出了一個很好的建議,即借鑒test.webrtc.org在檢測視頻活動時使用的結(jié)構(gòu)相似性算法(見此處此處)。后續(xù)還會分享更多技巧。
  適合任何視頻元素
  這段代碼實際上對任何
  不妨使用你自己的視頻試一下。只是提醒一下,如果你使用的是托管在另一臺服務(wù)器上的視頻,要注意CORS問題。
  一不小心寫成了長篇
  完成上面這一切耗費了很多時間,不過現(xiàn)在我希望開始著手有趣的部分了:嘗試不同的型號和訓(xùn)練我自己的分類器。已發(fā)布的對象檢測API是針對靜態(tài)圖像設(shè)計的。那么針對視頻和對象跟蹤進(jìn)行了調(diào)整的模型又是什么樣的呢?很值得一試。
  此外,這里還有太多的優(yōu)化工作需要做。我在運行此服務(wù)時并沒有配備GPU,如果配備的話,性能會大為不同。如果幀的數(shù)量不多,支持1個客戶端需要大約1個核心,而我使用的是最快但準(zhǔn)確性最低的模型。在這方面有很大的性能提升空間。如果觀察此服務(wù)在GPU云端網(wǎng)絡(luò)中性能如何,想必也很有趣。
【免責(zé)聲明】本文僅代表作者本人觀點,與CTI論壇無關(guān)。CTI論壇對文中陳述、觀點判斷保持中立,不對所包含內(nèi)容的準(zhǔn)確性、可靠性或完整性提供任何明示或暗示的保證。請讀者僅作參考,并請自行承擔(dān)全部責(zé)任。

專題