由於項目緣由,須要使用人臉檢測(face detection)功能。身爲一名前JAVA業務程序員和現前端程序員,這樣的功能仍是陌生的領域。那能不能經過搜索和學習能力,加上已有的編程思想,快速實現功能呢?這就是這篇文章的重點,憑藉本身的技術與積累,走向本身不熟悉的領域。html
使用PC加攝像頭,經過人臉檢測,完成自動拍照功能。在PC的屏幕上,顯示攝像頭的實時畫面,要是畫面中檢測出人臉,則觸發拍照。前端
抽其關鍵點:攝像頭,實時畫面,人臉檢測,和拍照node
項目並無要求開發應用的類型,那麼我確定是先從自身擁有的技能出發,看是否能尋求解決方案。身爲前端,深知前端技術潛力無限,確定有本身還不知道的技術。果不其然,找到了Tracking.jsgit
Tracking.js是一個頗有意思的庫,體積小巧,在瀏覽器上,直接經過JS提供一些基本的Computer Vison相關的功能,如人臉檢測(face detection),顏色識別(color detection),特徵識別(feature detection)。關鍵是,出了對靜態圖片可以進行識別和處理以外,還可以直接對視頻(video)和攝像頭(webcam)視屏流進行處理,這就基本給出了人臉識別的方案。程序員
那如何拍照呢?我找到了WebcamJS。可以在瀏覽器上讀取攝像頭視頻流,調用函數截取某個時刻視頻流幀爲圖片,即視爲拍照。github
兩個庫一結合,就有了初步的解決方案,實現了功能,簡單快速。web
在Tracking.js的官網上能夠看到,demo的視頻尺寸都是很小的,320 * 240,纔能有30FPS的處理速度。尺寸若是大了,則識別速度慢,卡頓明顯。項目中視頻顯示大小基本爲1080P分辨率屏幕的三分之一,直接處理這個大小的視頻,速度確定不夠。就算我不直接對大尺寸視頻流進行處理,轉而對一個隱藏的小尺寸視頻流處理,將人臉位置映射到大視頻流中,速度上沒問題,可是可檢測的人臉大小就有限了,即人必須離攝像頭比較近才能被檢測到。編程
使用的是羅技的1080P的網絡攝像頭,可是在瀏覽器上可以看到的,好像並無以1080P的分辨率進行展現。嘗試了一些參數的修改,可是結果都不盡人意。瀏覽器
實時的視頻流人臉識別,是很耗CPU的,下圖中右邊那個藍色的陡坡就是在我關閉了Tracking.js的demo頁面後CPU降低的曲線。服務器
這種狀況下,想添加一些傳統的網頁動效,簡直卡出翔來。(關於這點,使用web worker進行人臉檢測的工做,應該能有所幫助,可是本身並無往這方面走)
爲了尋找上面的問題的解決辦法,我瞭解到了Tracking.js和WebcamJS的運行原理。好比在瀏覽器上獲取攝像頭視頻流,是經過getUserMedia,是基於WebRTC的支持。
WebcamJS就是經過getuserMedia()
方法,得到攝像頭的視頻流信息,做爲<video>
標籤的src
屬性,歷來可以在網頁上進行顯示實時畫面。經過Canvas
的drawImage()
方法,將video標籤傳入,便可繪製那個時刻視頻幀的圖像。(也是經過此次機會我才瞭解到drawImage()
原來還能夠接受HTMLVideoElement
做爲參數的)
以前就知道,通常作計算機視覺的,都會用opencv庫,這是個C++的庫。同時又查到了,有人在node上作了opencv的擴展,而且看到了這個Github項目。因而爲了檢測效果,本身作了嘗試。
經過上面的學習,我已經可以在瀏覽器段獲取攝像頭的幀圖像,而且知道opencv能作人臉檢測。那麼此次的方案思路就是:將視頻流的幀圖像,經過websocket發到後臺服務器上,在服務器裏使用opencv進行人臉分析,將人臉的座標發送到前端。
這裏後臺我並無使用node-opencv,而是使用QT直接作websocket服務器和調用opencv庫(仗着本身曾也學過C++,就大膽的直接奔着C++去了)。
可是結果也不理想,緣由以下。
將圖片發送給後臺,首先想到的是使用Canvas的toDataURL()
方法,將圖片轉成base64字符串,發給後臺。但實測該方法很慢!640 * 480大小的圖片,經過toDataURL()
,大體須要50ms時間。
而後考慮使用getImageData(0, 0, 640, 480)
方法,獲取圖片像素信息,而後轉成字符串發到後臺。經測,該方法比toDataURL()
確實快很多,大體在5ms左右。可是將它轉成JSON字符串,則很慢很慢。
最後查到,toDataURL('image/jpeg')
會加快速度,由於這裏不須要計算Alpha通道。實測,小於10ms。
以前有擔憂的網絡傳輸耗時問題,卻是獲得了證明,這個擔憂是沒有必要的。由於是本地傳輸,經過websocket傳輸一張圖片(小尺寸或者大尺寸)base64字符串大小的內容,耗時都很小,算下來FPS可以上50。
Approach | CPU % |
---|---|
QT Opencv Face Detection | 30% |
Tracking.js Face Detection | 50% |
Websocket + Opencv | 90% |
不肯定本身在實現上是否哪裏出了問題,致使這麼高的CPU使用率。但無論怎麼,仍是放棄了這個方案。
居然都使用上了QT,就大步向前走好了,畢竟這樣的圖像處理程序,仍是作桌面應用是作合適的。何況QT體系中的QML語言,可以使用JS,學起來有點像在學一個新的前端MVVM框架,好感度和信心瞬間提高很多。
使用QML作界面,使用Camera和VideoOutput組件進行攝像頭視頻的實時顯示,這裏能指定顯示分辨率和FPS,很方便;配合使用QVideoFilterRunnable和QAbstractVideoFilter類對幀進行處理,異步返回給主界面人臉檢測的結果;opencv和另一個能作人臉識別的C++庫Dlib結合使用,可以完成640 * 480尺寸的30FPS處理。
再優化!給每一幀圖片進行人臉識別,速度和識別能力均可以提升,就是經過Dlib中提供的Video Object Tracking來完成。一旦對某一幀可以檢測到人臉以後,對以後的幀執行該人臉區域圖像的tracking。這樣作的效果可以得到更高的FPS,同時tracking還能完成更遠距離臉部的捕獲。
到這裏,方案才以爲差很少了。
面對項目中本身的未知領域,若是不缺錢,那麼直接買商業解決方案。Visage Tech提供的HTML5的人臉識別解決方案(好像用了WebAssembly),簡直變態:快速!準確!穩定!核心科技就是和咱們這些小打小鬧的不同。
若是不購買商用解決方案,那麼應該儘可能找到可以幫助本身的朋友,指條正確的方向可以節省不少調查摸索的時間。好比,若是需求要求程序在拍照時還能控制外接的燈泡,完成閃光燈的效果。那麼如何使用軟件完成對外部硬件的控制呢?這樣的功能對於我這個非計算機專業的而言,真是蒙圈了。最後仍是經歷的大半天的摸索,才找到GPIO的解決辦法。
提升編程的素養,擴大本身的興趣面,熱愛技術,善於google,邏輯思路清晰,那麼在面對不熟悉的領域,新的技術,也可以找到解決方案。而且這個過程能讓本身得到很多知識,face detection, object tracking, tracking.js, webcamJS, getUserMedia(), toDataURL()的性能,opencv,dlib,QML,GPIO,樹莓派,我還差點去現學了Python。這些東西沒有必要都是深究,可是知道他們的存在,會給擴展本身的思路。