人像美妝 OpenGL 實現(xiàn),真沒那么難
一、貼紙美妝
人像美妝效果的實現(xiàn)方式有很多種,其中貼紙美妝是最常見也是應(yīng)用最廣泛的一種實現(xiàn)方式。
二、貼紙美妝的OpenGL實現(xiàn)
1.劃分人臉網(wǎng)格
一般來說,在進(jìn)行美妝效果之前,都需要進(jìn)行人臉檢測,得到人臉部位的若干人臉點。(這一步一般在渲染之前就已經(jīng)完成,由人臉SDK完成)。
目前主流人臉檢測都是基于深度學(xué)習(xí)算法,各大廠自研或使用第三方算法,如商湯、曠視等。
人臉檢測點位例子:

2.劃分人臉網(wǎng)格
OpenGL是基于三角形進(jìn)行繪制圖像的,在繪制貼紙的時候,可以將人臉的區(qū)域劃分成若干個三角形,然后將貼紙繪制在這些三角形當(dāng)中。
將這些離散的零散的點位,按照一定規(guī)則劃分成不重疊的三角形,這叫“三角剖分算法”。三角剖分算法有很多。可以參考:三角剖分算法。
三角剖分后的人臉三角形:
3.定義標(biāo)準(zhǔn)人臉網(wǎng)格,使用人臉網(wǎng)格進(jìn)行貼紙繪制
使用貼紙美妝時,需要先定義一個標(biāo)準(zhǔn)模特的人臉網(wǎng)格(一般使用標(biāo)準(zhǔn)模特圖進(jìn)行人臉檢測即可)。
設(shè)計師在Photoshop或其他工具制作貼紙時,需要在標(biāo)準(zhǔn)人臉網(wǎng)格下進(jìn)行設(shè)計。在實際繪制時,將實際人臉點與標(biāo)準(zhǔn)人臉點一一匹配對應(yīng)進(jìn)行繪制,就能將貼紙按照網(wǎng)格繪制到人臉上。
在繪制的時候,可以選擇不同的疊加方式進(jìn)行繪制。
三、繪制方案優(yōu)化
3.1 方案一:美妝貼紙裁剪
上述方案的性能弊端
經(jīng)過上述方案,已經(jīng)可以實現(xiàn)基礎(chǔ)貼紙美妝效果。
但是這種方案只能一次性輸出全臉的妝容貼紙,當(dāng)有不同部位的妝容需要分別應(yīng)用時,每個妝容部位都需要一個完整的大妝容貼紙(例如需要分別應(yīng)用口紅、腮紅、眼瞳、眼影4種效果,就需要4個全臉貼紙),這將造成極大的內(nèi)存消耗和性能浪費。
因為一張貼紙圖片,可能90%以上是無效的部分:

裁剪優(yōu)化
按照上圖的有效部分和無效部分,如果可以只裁剪出來紅框的有效部分,那么有以下幾個優(yōu)點:
1.貼紙素材包大小可以大大降低。1000×1000的圖片大小為4Mb,100×100的圖片大小僅為40kb
2.程序運行時,內(nèi)存占用降低
3.渲染繪制速度變快,不需要再每一幀繪制大圖
裁剪優(yōu)化需要在標(biāo)準(zhǔn)人臉點位中,也對照裁剪出各個部位的三角網(wǎng)格,每個部位都用小網(wǎng)格進(jìn)行繪制:



這里需要注意的關(guān)鍵點,需要把裁剪后的貼圖坐標(biāo),和之前標(biāo)準(zhǔn)人臉圖的坐標(biāo)對應(yīng)上。這里需要做一層裁剪的坐標(biāo)運算。

3.2 方案二:合并繪制優(yōu)化
在4.1優(yōu)化后的基礎(chǔ)上,可以再進(jìn)行更進(jìn)一步的優(yōu)化。
4.1方案優(yōu)化后,如果有N個部位的貼圖,那么就需要進(jìn)行N次繪制。事實上這N次繪制可以合并成一次繪制,大大節(jié)省性能浪費,可以提升渲染速度和實時渲染的幀率。
繪制網(wǎng)格合并
可以將不同部位的網(wǎng)格拼接起來,在單次渲染中按照順序依次繪制。
四、貼紙美妝中需要注意的一些坑
1.貼紙順序問題
在有多個美妝效果的情況下,可能出現(xiàn)美妝貼紙部位會重疊的情況。例如:眼影和眼線,很多時候會同時出現(xiàn)。先繪制的效果會被后面繪制的效果覆蓋。
此時需要與設(shè)計師溝通,在PS里預(yù)先演算重疊的效果,通過透明度調(diào)整、疊加方式的調(diào)整、圖層順序的調(diào)整,選擇最符合預(yù)期的重疊方案實現(xiàn)
2.貼紙在不同光照環(huán)境下可能出現(xiàn)漂浮的問題
實際場景是暗光或者逆光的環(huán)境下,貼紙可能出現(xiàn)漂浮等不佳的效果。原因是貼紙無法動態(tài)改變其明亮度、對比度、飽和度等,使得上面的參數(shù)與人臉照片的這些參數(shù)相匹配,無法做到所有光照環(huán)境100%契合
解決思路
通過算法檢測當(dāng)前幀人臉區(qū)域的明亮、對比、飽和等信息,對貼紙也做對應(yīng)的調(diào)色處理(這種方案成本比較大)
也可以簡單計算當(dāng)前幀的亮度信息,過大或過暗時降低貼紙透明度(簡單的處理方式)
3.兩個人臉緊貼時,貼紙可能會覆蓋另一個人的人臉
解決思路
進(jìn)行遮擋識別,屏蔽遮擋部分(如果把手蓋在臉上,遮擋掉臉部的妝容也是同理)
用人臉mask進(jìn)行過濾,在人臉范圍內(nèi)才顯示貼紙
識別當(dāng)前人臉的方向,可以計算模擬假3D貼紙,貼紙僅會出現(xiàn)在人臉內(nèi)部區(qū)域
最終效果圖:
Demo代碼工程:https://github.com/sysu-huangwei/Makeup
-- END --
進(jìn)技術(shù)交流群,掃碼添加我的微信:Byte-Flow
獲取相關(guān)資料和源碼
推薦:
全網(wǎng)最全的 Android 音視頻和 OpenGL ES 干貨,都在這了
