純前端做到人臉識別-提取-合成

尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️

加入LINE好友

近火爆朋友圈的軍裝照H5大家一定還記憶猶新,其原理是先提取出照片中的臉部,然後與模板進行合成,官方的合成處理據說由天天P圖提供技術支持,後端合成後返回給前端展示,形式很新穎效果也非常好,整個流程涉及的人臉識別和圖像合成兩項核心技術在前端都有對應的解決方案,因此理論上前端也可以完成人臉識別-提取-合成整個流程,做到純前端的軍裝照H5效果。

前端人臉識別

首先需要的是人臉識別,這個一聽就覺得高大上的東西原理並不深奧,無非是用人的臉部特徵規則對圖像進行匹配和識別,這項工作前端雖然可以做到,但前端做到基本就只能依據內置規則庫進行匹配,這個庫的質量就決定了識別質量,而通常更成熟的方案是引入機器學習,讓程序不斷自我修正和提高,進一步提高識別率,機器學習的前端庫倒是也有,但把這兩者結合起來的還沒發現,因此對前端人臉識別的準確率不要報太高期望。

現有的前端人臉識別庫不算多,這里我們選擇的是效果相對好點的trackingjs,這個類庫功能非常強大,庫如其名,它可以完成各種追蹤類的圖像處理任務,人臉識別只是其眾多功能之一,而且通過選配插件,還可以精確識別眼睛、鼻子等五官的位置,好像稍微折騰一下也可以做到美圖秀秀的效果。

這里我們只用trackingjs做到臉部識別,初始化一個臉部識別任務的代碼如下:

//實例化

vartracker= newtracking.ObjectTracker([‘face’]);

//識別回調

tracker.on(‘track’,function(event){

if(!event.data.length){

returnconsole.log(‘畫面中沒有人臉’);

}

event.data.forEach(function(rect,i){

console.log(rect);//單個臉部數據

})

})

//配置參數

這樣一個臉部識別任務就初始化完成了,調用方式如下:

tracking.track(‘#img’,tracker);

//其中’#img’參數是目標圖像的選擇器

在識別回調中event.data就是數組格式的臉部數據,如果長度為0則表示圖像中沒有人臉或者識別失敗,如果識別成功,單個臉部數據的格式如下:

{

x: number,//臉部位於原圖x軸方向位置

y: nuber,//臉部位於原圖y軸方向位置

width:number,//臉部區域寬度

height:nubmer//臉部區域高度

}

有了這個臉部數據就可以很容易的將該區域從原圖中提取出來,前端當然就用canvas啦,示例如下:

varimg= document.getElementById(“img”);

varfaceCtx= document.getElementById(“mycanvas”).getContext(‘2d’);

vartheFace= …;//假設我們識別到了theFace

//使用drawImage()方法將臉部繪制出來

faceCtx.drawImage(img,theFace.x,theFace.y,theFace.width,theFace.height,0,0,theFace.width,theFace.height);

到這里我們已經做到了臉部識別 + 提取,而且代碼量也沒多少,其實這里面有個小坑要在實踐中才會發現,那就是trackingjs的配置,文檔中能找到4個跟識別有關的配置,分別是:

setClassifiers(classifiers)

setEdgesDensity(edgesDensity)

setScaleFactor(scaleFactor)

setStepSize(stepSize)

看不懂吧,我也看不懂,而且文檔中對他們沒有任何有用的說明,在測試中我只使用了後兩個配置,翻譯過來分別是」比例因子」和」步長」,經過枯燥的人肉測試發現,這兩個參數的有效取值範圍分別在1 – 2和1.1 – 2,其中setStepSize不能為1,否則會瀏覽器會卡死,所以從1.1開始取值,取值超過2也可以,但識別成功的概率就很低了。通過調整這兩個參數絕大多數圖像都可以成功識別,唯獨對臉部大特寫很難識別,這可能需要配合另外兩個參數吧,我實在沒耐心繼續人肉測試下去了,感興趣的自己回去玩吧。

前端圖像處理

經過上一步的識別+提取我們已經得到了臉部圖像,要做到合成軍裝照效果我們還需要對臉部圖像進行處理,使色調與模板一致,將來才能毫無違和感的融合在一起,具體到軍裝照這個例子我們需要將臉部重新著色,並達到」做舊」的老照片效果,如果用PS想必大家都會,但在前端怎麼做到呢?

這里我們需要借助騰訊前端團隊出品的AlloyImage,這是一個堪稱前端PS的前端圖像處理類庫,比如要做到上述效果,我們只需要這樣:

varfaceImg= document.getElementById(“theFace”);

faceImg.loadOnce(function(){

AlloyImage(this).act(“灰度處理”).add(

AlloyImage(this.width,this.height,“#808080”)

.act(“高斯模糊”,4)

.act(“色相/飽和度調節”,22,45,0,true),

“疊加”

).replace(this);

}

然後你就得到了一個做舊的人臉,還是非常簡單的,AlloyImage的使用基本可以說是傻瓜化,感興趣的就自己花個五分鐘去看下官方文檔吧,這里不再贅述。

然後就要說一下我們這個圖像處理和人家天天P圖的差距了,雖然我們得到了理想的色調,但要想把隨便一張人臉與特定模板做合成,有兩件事必不可少。首先是臉部角度矯正,如果模板是正的而你的照片是歪的,直接暴力拼接肯定很違和,所以需要先識別出臉部角度,並糾正到指定角度;然後是臉部中心定位,因為人臉識別的結果提取出來後不一定是以臉部中心為中心的,所以在合成之前要識別出臉部中心線,並以此為依據與模板進行定位。然而這些我們都沒有,所以我們只能對輸入的圖像的要求更高,如果輸入了嘴歪眼斜的圖片,結果就只能尷尬了。

最後的圖片合成部分就更簡陋了,先將處理好的臉部畫到畫布指定位置,然後將摳好圖的臉部透明png模板鋪在上面,完成。實際過程中需要處理一些小問題,比如要根據模板的臉部尺寸將臉部圖像縮放到合適的尺寸;摳模板時要將邊緣模糊處理,而且盡量保留模板本來的臉部輪廓,只將五官摳掉。即便這樣,合成結果還是很容易穿幫,不過純前端處理也沒有更好的辦法了。

效果展示

好了,說的再多不如看個例子,示例提供三種圖片輸入源,分別是本地圖片、遠程圖片、內置示例。其中內置的圖片大部分是提前在PS中糾正過角度的,而且內置圖片會自動匹配到我事先調校好的參數,不出意外可以直接識別出人臉;如果選擇本地圖片作為圖片源,最好選擇頭部姿態垂直的正面照,同時參考內置圖片的 參數設置調節參數,一次識別不成功很正常,需要多調幾次;也可以使用遠程圖片識別,但因為canvas受到跨域策略影響,遠程圖片只能識別不能提取和合成。

示例:純前端軍裝照合成(http://refined-x.com/projects/codes/tracking.html)

後記

最初是抱著好奇的心態開始搗鼓這個項目的,雖然最終的合成效果遠遠達不到生產要求,但整個示例擼下來後對人臉識別和圖片處理技術都有了基本的認識,對canvas操作中一些細節問題的解決也略微補足了一下這方面的知識空白,算略有收獲吧。

源自:http://refined-x.com/2017/09/06/純前端做到人臉識別-提取-合成/

聲明:文章著作權歸作者所有,如有侵權,請聯繫小編刪除。

About 尋夢園
尋夢園是台灣最大的聊天室及交友社群網站。 致力於發展能夠讓會員們彼此互動、盡情分享自我的平台。 擁有數百間不同的聊天室 ,讓您隨時隨地都能找到志同道合的好友!