<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android OpenGL 實現(xiàn)“人像背景虛化”效果

          共 5651字,需瀏覽 12分鐘

           ·

          2024-04-12 01:34


          手機上的人像模式,也被人們稱作“背景虛化”或 ”雙攝虛化“ 模式,也稱為 Bokeh 模式,能夠在保持畫面中指定的人或物體清晰的同時,將其他的背景模糊掉。突出畫面的主體部分,主觀上美感更強烈。


          VIVO 手機人像模式效果


          人像模式的一般實現(xiàn)原理是,利用雙攝系統(tǒng)獲取景深信息,并通過深度傳感器和圖像分割技術(shù)準確分離主題與背景,隨后應用人像增強處理和背景虛化算法,例如美顏、膚色優(yōu)化以及基于深度信息的虛化等,最終提供清晰突出的人像照片。


          所以,人像模式的實現(xiàn)對于軟件層面來說,關(guān)鍵還是有能精確輸出帶有深度(景深)信息的圖像分割算法。


          隨著深度學習的發(fā)展,現(xiàn)在已經(jīng)可以做到通過單個攝像頭,推測場景的深度圖,推薦一個 Deep-Image-Matting 開源模型:
          https://github.com/foamliu/Deep-Image-Matting


          如果只是簡單的實現(xiàn)人像 Matting , 可以參考飛鴿傳書的開源項目 ncnn_Android_RobustVideoMatting ,它使用的是騰訊的 ncnn 神經(jīng)網(wǎng)絡計算框架,ncnn 是一個為手機端極致優(yōu)化的高性能神經(jīng)網(wǎng)絡前向計算框架。


          VideoMatting Demohttps://github.com/githubhaohao/AndroidVideoMatting


          接下來,本文將教您如何利用人像分割和 OpenGL 的濾鏡來實現(xiàn)人像背景虛化效果。


          照例先上效果圖,OpenGL 實現(xiàn)的“人像背景虛化”效果





          實現(xiàn)原理


          “人像背景虛化”效果實現(xiàn),首先獲取到人像的 mask 圖,然后基于這個 mask 圖對人像進行保護,對背景做一些模糊(虛化)和一些高光的“光斑”效果,因為真實的光學系統(tǒng)在大光圈成像時,會在某些高光像素處形成特別質(zhì)感的光斑。


          景深信息

          如果我們拿到的 mask 圖包含了景深信息的話,我們還可以進行更加細致的處理,比如光斑的近大遠小,虛化效果的層次感,會更加接近手機人像模式成片的效果。


          “光斑”效果的實現(xiàn)參考我之前的文章:抖音、視頻號流行的 Bokeh 效果是怎么實現(xiàn)的?https://mp.weixin.qq.com/s/O4DFpruMdQecJBPga6Q5zA ,我們從里面選一個圓形的光斑。


          實現(xiàn)圓形光斑的 shader :


          #version 300 es
          precision highp float;
          in vec2 v_texCoord;
          uniform sampler2D sTexture;
          uniform sampler2D sPortraitTexture;
          uniform highp vec2 inputSize;
          layout(location = 0) out vec4 outColor;

          float sdCircle(in vec2 p, in float r) {
              return length(p)-r;
          }

          void main() {
              float effectValue = 0.4;
              vec2 uv = v_texCoord;
              vec2 d = 1.0 / inputSize;
              float scale = (inputSize.x + inputSize.y)/1080.0;
              float kernel = floor(20.0 * scale * effectValue);
              vec4 maxCol = vec4(0.0);
              vec4 mask = texture(sPortraitTexture, uv);
              for(float x = -kernel;x<kernel;x++) {
                  for(float y = -kernel;y<kernel;y++) {
                      vec2 xy = vec2(x,y)/kernel;
                      if(sdCircle(xy, 0.5 + effectValue * 0.2) < 0.0) {
                          vec4 col = texture(sTexture, uv + d * vec2(x,y));
                          maxCol = max(maxCol, col * mask.a);
                      }
                  }
              }
              outColor = maxCol;
          }

          有了光斑效果和摳出來的人像,可以使用 Blend 濾鏡來驗證一波:

          //Blend
          #version 300 es
          precision highp float;
          in vec2 v_texCoord;
          uniform sampler2D sTexture;//做完光斑效果后的圖像
          uniform sampler2D sPortraitTexture;//mask 分割出來的人像
          layout(location = 0out vec4 outColor;

          void main({
              vec4 portraitCol = texture(sPortraitTexture, v_texCoord);
              vec4 srcCol = texture(sTexture, v_texCoord);
              outColor = mix(srcCol, portraitCol, portraitCol.a);
          }


          效果如下:


          “光斑”看起來很不自然,沒有虛化的感覺,接下來對圖像先做模糊再做光斑的效果,看看融合起來效果如何。


          模糊效果實現(xiàn)可以直接使用高斯模糊算法,參考鏈接:https://mp.weixin.qq.com/s/D53C1KtY2slLBX28Ggmx2g ,這里為了減少計算量選擇使用一個輕量的快速高斯模糊濾鏡,篇幅有限源碼不再貼出來,文末有獲取方式。


          加了模糊之后的效果,看起來自然了很多:


          細心觀察,發(fā)現(xiàn)了新的問題,人像邊緣有一圈黑色的邊,看起來很丑。



          由2個原因?qū)е碌倪@個問題,一是算法摳圖精確度不足,人像沒有扣干凈;二是融合的時候沒有 alpha 預乘導致半透明的邊緣發(fā)黑。針對這兩個原因優(yōu)化下我們的 blend shader :


          #version 300 es
          precision highp float;
          in vec2 v_texCoord;
          uniform sampler2D sTexture;//做完光斑和模糊效果后的圖像
          uniform sampler2D sPortraitTexture;/mask 分割出來的人像
          layout(location = 0) out vec4 outColor;

          void main() {
              vec4 portraitCol = texture(sPortraitTexture, v_texCoord);
              vec4 srcCol = texture(sTexture, v_texCoord);
              srcCol *= srcCol.a;// alpha 預乘
              portraitCol *= portraitCol.a;// alpha 預乘
              outColor = mix(srcCol, portraitCol, portraitCol.a);
              outColor.rgb /= max(0.000001, outColor.a);
          }


          來看最后的效果:

          后續(xù)優(yōu)化方向,使用景深(深度)圖控制不同區(qū)域光斑的大小和虛化的強度。需要完整代碼的同學可以在下方掃碼添加我的微信:Byte-Flow 獲取。


          -- END --


          進技術(shù)交流群,掃碼添加我的微信:Byte-Flow



          獲取相關(guān)資料和源碼


          學習音視頻、OpenGL ES、Vulkan 、Metal、圖像濾鏡、視頻特效及相關(guān)渲染技術(shù)的付費社群,面試指導,1v1 簡歷服務,職業(yè)規(guī)劃。


          我的付費社群


          推薦:

          Android FFmpeg 實現(xiàn)帶濾鏡的微信小視頻錄制功能

          全網(wǎng)最全的 Android 音視頻和 OpenGL ES 干貨,都在這了

          一文掌握 YUV 圖像的基本處理

          抖音傳送帶特效是怎么實現(xiàn)的?

          所有你想要的圖片轉(zhuǎn)場效果,都在這了

          面試官:如何利用 Shader 實現(xiàn) RGBA 到 NV21 圖像格式轉(zhuǎn)換?

          我用 OpenGL ES 給小姐姐做了幾個抖音濾鏡

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品国产精品国产专区不片 | 【乱子伦】国产精品www | 国产一级特黄 | 亚洲成色A片77777在线小说 | 逼逼网|