Android OpenGLES 實(shí)時(shí)美顏(磨皮)的優(yōu)化(二)

在前一篇文章Android OpenGLES 實(shí)時(shí)美顏(磨皮)的優(yōu)化,我們已經(jīng)介紹了關(guān)于實(shí)時(shí)美顏(磨皮)的一些優(yōu)化點(diǎn)。但在實(shí)際的優(yōu)化測試中發(fā)現(xiàn),當(dāng)處理器發(fā)熱之后,就無法保證預(yù)覽幀率了拌滋,主要還是高斯模糊處理的數(shù)據(jù)量比較大導(dǎo)致。因此猜谚,我們需要尋找新的磨皮方法败砂。
目前市面上關(guān)于磨皮方法有好多種赌渣,使用PS磨皮經(jīng)常用到的方法包括高反差保留、高低頻昌犹、中性灰以及雙線性等坚芜。其中中性灰和雙線性的效率一般,因此斜姥,我們從高反差保留鸿竖、高低頻這兩種方法中選擇。這里選擇使用高反差保留法做磨皮處理铸敏,PS中的高反差保留法進(jìn)行磨皮缚忧,隨手一搜便能找到很多文章,比如:
https://jingyan.baidu.com/article/455a99504d568fa1662778d6.html

接下來杈笔,我們嘗試著實(shí)現(xiàn)文章中講到的過程闪水。

第一步,對圖像做高斯模糊處理

關(guān)于高斯模糊的優(yōu)化蒙具,可以參考本人的文章:
OpenGLES濾鏡開發(fā)匯總 —— 高斯模糊實(shí)現(xiàn)以及優(yōu)化

對于人像進(jìn)行高斯模糊球榆,我們設(shè)計(jì)一個(gè)11x11的高斯算子對圖像進(jìn)行高斯模糊,shader如下:
vertex shader :

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;

// 高斯算子左右偏移值禁筏,當(dāng)偏移值為5時(shí)持钉,高斯算子為 11 x 11
const int SHIFT_SIZE = 5;

uniform highp float texelWidthOffset;
uniform highp float texelHeightOffset;

varying vec2 textureCoordinate;
varying vec4 blurShiftCoordinates[SHIFT_SIZE];

void main() {
    gl_Position = uMVPMatrix * aPosition;
    textureCoordinate = aTextureCoord.xy;
    // 偏移步距
    vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
    // 記錄偏移坐標(biāo)
    for (int i = 0; i < SHIFT_SIZE; i++) {
        blurShiftCoordinates[i] = vec4(textureCoordinate.xy - float(i + 1) * singleStepOffset,
                                       textureCoordinate.xy + float(i + 1) * singleStepOffset);
    }
}

fragment shader:

precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D inputTexture;
const int SHIFT_SIZE = 5; // 高斯算子左右偏移值
varying vec4 blurShiftCoordinates[SHIFT_SIZE];
void main() {
    // 計(jì)算當(dāng)前坐標(biāo)的顏色值
    vec4 currentColor = texture2D(inputTexture, textureCoordinate);
    mediump vec3 sum = currentColor.rgb;
    // 計(jì)算偏移坐標(biāo)的顏色值總和
    for (int i = 0; i < SHIFT_SIZE; i++) {
        sum += texture2D(inputTexture, blurShiftCoordinates[i].xy).rgb;
        sum += texture2D(inputTexture, blurShiftCoordinates[i].zw).rgb;
    }
    // 求出平均值
    gl_FragColor = vec4(sum * 1.0 / float(2 * SHIFT_SIZE + 1), currentColor.a);
}

經(jīng)過以上的shader進(jìn)行高斯模糊處理之后,我們得到這樣一張高斯模糊圖像:


高斯模糊處理

第二步篱昔,利用高通濾波器做高反差保留

在PS的高反差保留磨皮方法中每强,高反差保留磨皮混合采用的是強(qiáng)光模式,計(jì)算公式為:color = 2 * color1 * color2旱爆。因此舀射,我們設(shè)計(jì)出這樣一個(gè)高通濾波器窘茁,其shader如下:
fragment shader:

precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D inputTexture; // 輸入原圖
uniform sampler2D blurTexture;  // 高斯模糊圖片
const float intensity = 24.0;   // 強(qiáng)光程度
void main() {
    lowp vec4 sourceColor = texture2D(inputTexture, textureCoordinate);
    lowp vec4 blurColor = texture2D(blurTexture, textureCoordinate);
    // 高通濾波之后的顏色值
    highp vec4 highPassColor = sourceColor - blurColor;
    // 對應(yīng)混合模式中的強(qiáng)光模式(color = 2.0 * color1 * color2)怀伦,對于高反差的顏色來說,color1 和color2 是同一個(gè)
    highPassColor.r = clamp(2.0 * highPassColor.r * highPassColor.r * intensity, 0.0, 1.0);
    highPassColor.g = clamp(2.0 * highPassColor.g * highPassColor.g * intensity, 0.0, 1.0);
    highPassColor.b = clamp(2.0 * highPassColor.b * highPassColor.b * intensity, 0.0, 1.0);
    // 輸出的是把痘印等過濾掉
    gl_FragColor = vec4(highPassColor.rgb, 1.0);
}

經(jīng)過高通濾波器之后山林,我們得到這樣一個(gè)紋理圖像:


高通濾波器得到的紋理

可以看到房待,經(jīng)過三通道強(qiáng)光混合處理后,痘印驼抹、邊沿等地方都清晰起來了桑孩。強(qiáng)光的程度,一般是3的倍數(shù)框冀,這里取24倍流椒。

第三步,保邊預(yù)處理

到這一步明也,其實(shí)我們已經(jīng)得到了需要過濾顏色值宣虾,但在這一張圖中惯裕,也把邊沿的顏色差值包含進(jìn)來了。我們接下來需要過濾掉邊沿的顏色差值绣硝。這樣在后續(xù)的處理中蜻势,我們可以保留邊沿的細(xì)節(jié)不被模糊掉。因此接下來鹉胖,我們需要將經(jīng)過高通濾波得到的紋理握玛,再做一次高斯模糊。不過這一次不能11 x11 這么大的高斯算子甫菠,我們選擇一個(gè) 5 x 5 大小的高斯算子挠铲。高斯模糊的shader 如下:
vertex shader:

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec4 aTextureCoord;

// 高斯算子左右偏移值,當(dāng)偏移值為2時(shí)淑蔚,高斯算子為5 x 5
const int SHIFT_SIZE = 2;

uniform highp float texelWidthOffset;
uniform highp float texelHeightOffset;

varying vec2 textureCoordinate;
varying vec4 blurShiftCoordinates[SHIFT_SIZE];

void main() {
    gl_Position = uMVPMatrix * aPosition;
    textureCoordinate = aTextureCoord.xy;
    // 偏移步距
    vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
    // 記錄偏移坐標(biāo)
    for (int i = 0; i < SHIFT_SIZE; i++) {
        blurShiftCoordinates[i] = vec4(textureCoordinate.xy - float(i + 1) * singleStepOffset,
                                       textureCoordinate.xy + float(i + 1) * singleStepOffset);
    }
}

fragment shader:

precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D inputTexture;
// 高斯算子左右偏移值市殷,當(dāng)偏移值為2時(shí),高斯算子為5 x 5
const int SHIFT_SIZE = 2;
varying vec4 blurShiftCoordinates[SHIFT_SIZE];
void main() {
    // 計(jì)算當(dāng)前坐標(biāo)的顏色值
    vec4 currentColor = texture2D(inputTexture, textureCoordinate);
    mediump vec3 sum = currentColor.rgb;
    // 計(jì)算偏移坐標(biāo)的顏色值總和
    for (int i = 0; i < SHIFT_SIZE; i++) {
        sum += texture2D(inputTexture, blurShiftCoordinates[i].xy).rgb;
        sum += texture2D(inputTexture, blurShiftCoordinates[i].zw).rgb;
    }
    // 求出平均值
    gl_FragColor = vec4(sum * 1.0 / float(2 * SHIFT_SIZE + 1), currentColor.a);
}

將高通濾波器得到的紋理刹衫,經(jīng)過高斯模糊處理后醋寝,得到這樣一張紋理:


高斯模糊處理的紋理

對比高通濾波器處理后的紋理,邊沿細(xì)節(jié)變得模糊了带迟,而且音羞,需要過濾的顏色差值仍舊保留著。到這一步仓犬,我們就得到了做磨皮處理的前置紋理嗅绰。接下來就是高反差保留磨皮的最后也是最重要的一步。

第四步搀继,磨皮調(diào)節(jié)

經(jīng)過前面的處理窘面,我們得到一張輸入圖片的高斯模糊紋理,以及一張高反差保留的高斯模糊紋理叽躯。我們使用這兩張紋理财边,通過比較藍(lán)色通道,計(jì)算出需要磨皮的實(shí)際強(qiáng)度值点骑,與原圖進(jìn)行混合處理酣难,然后輸出最終的紋理。shader如下所示:

precision mediump float;
varying vec2 textureCoordinate;
uniform sampler2D inputTexture;         // 輸入原圖
uniform sampler2D blurTexture;          // 原圖的高斯模糊紋理
uniform sampler2D highPassBlurTexture;  // 高反差保留的高斯模糊紋理
uniform lowp float intensity;           // 磨皮程度
void main() {
    lowp vec4 sourceColor = texture2D(inputTexture, textureCoordinate);
    lowp vec4 blurColor = texture2D(blurTexture, textureCoordinate);
    lowp vec4 highPassBlurColor = texture2D(highPassBlurTexture, textureCoordinate);
    // 調(diào)節(jié)藍(lán)色通道值
    mediump float value = clamp((min(sourceColor.b, blurColor.b) - 0.2) * 5.0, 0.0, 1.0);
    // 找到模糊之后RGB通道的最大值
    mediump float maxChannelColor = max(max(highPassBlurColor.r, highPassBlurColor.g), highPassBlurColor.b);
    // 計(jì)算當(dāng)前的強(qiáng)度
    mediump float currentIntensity = (1.0 - maxChannelColor / (maxChannelColor + 0.2)) * value * intensity;
    // 混合輸出結(jié)果
    lowp vec3 resultColor = mix(sourceColor.rgb, blurColor.rgb, currentIntensity);
    // 輸出顏色
    gl_FragColor = vec4(resultColor, 1.0);
}

經(jīng)過上面的處理之后黑滴,我們就得到磨皮處理的結(jié)果如下:


磨皮處理效果

可以看到憨募,經(jīng)過高反差保留磨皮后的結(jié)果,磨皮效果還不錯(cuò)袁辈,而且720P磨皮處理時(shí)菜谣,在高通驍龍625處理器上,經(jīng)過高反差保留磨皮之后,預(yù)覽幀率能夠保持在30FPS左右尾膊。我們可以看到甘磨,邊沿細(xì)節(jié)還是不夠明顯,所以眯停,我們可以使用USM銳化增強(qiáng)邊沿細(xì)節(jié)部分济舆。這篇文章就不講解USM銳化的實(shí)現(xiàn)了。

詳細(xì)實(shí)現(xiàn)過程莺债,可以參考本人的開源相機(jī)項(xiàng)目:
CainCamera
CainCamera的FilterLibrary中有經(jīng)過優(yōu)化后的實(shí)時(shí)美顏(磨皮)實(shí)現(xiàn)滋觉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市齐邦,隨后出現(xiàn)的幾起案子椎侠,更是在濱河造成了極大的恐慌,老刑警劉巖措拇,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件我纪,死亡現(xiàn)場離奇詭異,居然都是意外死亡丐吓,警方通過查閱死者的電腦和手機(jī)浅悉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券犁,“玉大人术健,你說我怎么就攤上這事≌吵模” “怎么了荞估?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稚新。 經(jīng)常有香客問我勘伺,道長,這世上最難降的妖魔是什么褂删? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任飞醉,我火速辦了婚禮,結(jié)果婚禮上笤妙,老公的妹妹穿的比我還像新娘冒掌。我一直安慰自己噪裕,他們只是感情好蹲盘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膳音,像睡著了一般召衔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祭陷,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天苍凛,我揣著相機(jī)與錄音趣席,去河邊找鬼。 笑死醇蝴,一個(gè)胖子當(dāng)著我的面吹牛宣肚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悠栓,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼霉涨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惭适?” 一聲冷哼從身側(cè)響起笙瑟,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎癞志,沒想到半個(gè)月后往枷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凄杯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年错洁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戒突。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡墓臭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妖谴,到底是詐尸還是另有隱情窿锉,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布膝舅,位于F島的核電站嗡载,受9級特大地震影響仍稀,放射性物質(zhì)發(fā)生泄漏洼滚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一技潘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧享幽,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸯隅。三九已至滋迈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間户誓,已是汗流浹背饼灿。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帝美,地道東北人碍彭。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像悼潭,于是被迫代替她去往敵國和親庇忌。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.背景 前段時(shí)間由于項(xiàng)目需求舰褪,做了一個(gè)基于GPUImage的實(shí)時(shí)美顏濾鏡〗哉睿現(xiàn)在各種各樣的直播、視頻App層出不窮...
    一個(gè)橘子而已閱讀 1,551評論 1 7
  • 轉(zhuǎn)載自:實(shí)戰(zhàn)分享:實(shí)時(shí)美顏濾鏡是怎樣煉成的 1.背景 前段時(shí)間由于項(xiàng)目需求占拍,做了一個(gè)基于GPUImage的實(shí)時(shí)美顏...
    路漫漫其修遠(yuǎn)兮Wzt閱讀 12,289評論 3 58
  • 轉(zhuǎn)載自VR設(shè)計(jì)云課堂[http://www.reibang.com/u/c7ffdc4b379e]Unity S...
    水月凡閱讀 1,009評論 0 0
  • 1.背景 前段時(shí)間由于項(xiàng)目需求略就,做了一個(gè)基于GPUImage的實(shí)時(shí)美顏濾鏡。現(xiàn)在各種各樣的直播晃酒、視頻App層出不...
    琨君閱讀 61,550評論 67 357
  • 用兩張圖告訴你表牢,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,699評論 2 59