天天看點

聊聊人像摳圖背後的算法技術

本文分享自華為雲社群《人像摳圖:算法概述及工程實作(一)》,原文作者:杜甫蓋房子 。

本文将從算法概述、工程實作、優化改進三個方面闡述如何實作一個實時、優雅、精确的視訊人像摳圖項目。

什麼是摳圖

對于一張圖I, 我們感興趣的人像部分稱為前景F,其餘部分為背景B,則圖像I可以視為F與B的權重融合:I = alpha * F + (1 - alpha) * BI=alpha∗F+(1−alpha)∗B,而摳圖任務就是找到合适的權重alpha。值得一提的是,如圖,檢視摳圖ground truth可以看到,alpha是[0, 1]之間的連續值,可以了解為像素屬于前景的機率,這與人像分割是不同的。如圖,在人像分割任務中,alpha隻能取0或1,本質上是分類任務,而摳圖是回歸任務。

摳圖ground truth:

聊聊人像摳圖背後的算法技術

分割ground truth:

聊聊人像摳圖背後的算法技術

相關工作

我們主要關注比較有代表性的基于深度學習的摳圖算法。目前流行的摳圖算法大緻可以分為兩類,一種是需要先驗資訊的Trimap-based的方法,寬泛的先驗資訊包括Trimap、粗糙mask、無人的背景圖像、Pose資訊等,網絡使用先驗資訊與圖檔資訊共同預測alpha;另一種則是Trimap-free的方法,僅根據圖檔資訊預測alpha​,對實際應用更友好,但效果普遍不如Trimap-based的方法。

Trimap-based

Trimap是最常用的先驗知識,顧名思義Trimap是一個三元圖,每個像素取值為{0,128,255}其中之一,分别代表前景、未知與背景,如圖。

聊聊人像摳圖背後的算法技術

Deep Image Matting

多數摳圖算法采用了Trimap作為先驗知識。Adobe在17年提出了Deep Image Matting[^1],這是首個端到端預測alpha的算法,整個模型分Matting encoder-decoder stage與Matting refinement stage兩個部分,Matting encoder-decoder stage是第一部分,根據輸入圖像與對應的Trimap,得到較為粗略的alpha matte。Matting refinement stage是一個小的卷積網絡,用來提升alpha matte的精度與邊緣表現。

聊聊人像摳圖背後的算法技術
聊聊人像摳圖背後的算法技術

本文在當時達到了state-of-the-art,後續很多文章都沿用了這種“粗略-精細”的摳圖思路,此外,由于标注成本高,過去摳圖任務的資料是非常有限的。本文還通過合成提出了一個大資料集Composition-1K,将精細标注的前景與不同背景融合,得到了45500訓練圖像和1000測試圖像,大大豐富了摳圖任務的資料。

Background Matting

Background Matting[^2]是華盛頓大學提出的摳圖算法,後續釋出了Backgroun MattingV2,方法比較有創新點,并且在實際工程應用中取得了不錯的效果。

聊聊人像摳圖背後的算法技術

同時,由于Adobe的資料都是基于合成的,為了更好的适應真實輸入,文中提出一個自監督網絡訓練G_{Real}GReal​來對未标注的真實輸入進行學習。G_{Real}GReal​輸入與G_{Adobe}GAdobe​相同,用G_{Adobe}GAdobe​輸出的alpha matte與F來監督G_{Real}GReal​的輸出得到loss,此外,G_{Real}GReal​的輸出合成得到的RGB還将通過一個鑒别器來判斷真僞得到第二個loss,共同訓練G_{Real}GReal​。

聊聊人像摳圖背後的算法技術

文中列舉了一些使用手機拍攝得到的測試結果,可以看到大部分情況結果還是很不錯的。

聊聊人像摳圖背後的算法技術

Background Matting V2

Background Matting得到了不錯的效果,但該項目無法實時運作,也無法很好的處理高分辨率輸入。是以項目團隊又推出了Background Matting V2[^3],該項目可以以30fps的速度在4k輸入上得到不錯的結果。

聊聊人像摳圖背後的算法技術

文章實作高效高分辨率摳圖的一個重要想法是,alpha matte中大部分像素是0或1,隻有少量的區域包含過渡像素。是以文章将網絡分為base網絡和refine網絡,base網絡對低分辨率圖像進行處理,refine網絡根據base網絡的處理結果選擇原始高分辨率圖像上特定圖像塊進行處理。

聊聊人像摳圖背後的算法技術

base網絡輸入為c倍下采樣的圖像與背景,通過encoder-decoder輸出粗略的alpha matte、F、error map與hidden features。将采樣c倍得到的error map E_cEc​上采樣到原始分辨率的\frac{1}{4}41​為E_4E4​,則E_4E4​每個像素對應原圖4x4圖像塊,從E_4E4​選擇topk error像素,即為原始topk error 4x4圖像塊。在選擇出的像素周圍裁剪出多個8x8圖像塊送入refine網絡。refine網絡是一個two-stage網絡,首先将輸入通過部分CBR操作得到第一階段輸出,與原始輸入中提取的8x8圖像塊cat後輸入第二階段,最後将refine後的圖像塊與base得到的結果交換得到最終的alpha matte和F。

聊聊人像摳圖背後的算法技術
聊聊人像摳圖背後的算法技術

此外文章還釋出了兩個資料集:視訊摳圖資料集VideoMatte240K與圖像摳圖資料集PhotoMatte13K/85。VideoMatte240K收集了484個高分辨率視訊,使用Chroma-key軟體生成了240000+前景和alpha matte對。PhotoMatte13K/85則是在良好光照下拍攝照片使用軟體和手工調整的方法得到13000+前景與alpha matte資料對。大型資料集同樣是本文的重要貢獻之一。

聊聊人像摳圖背後的算法技術
聊聊人像摳圖背後的算法技術

此外還有一些文章如Inductive Guided Filter[^4]、MGMatting[^5]等,使用粗略的mask作為先驗資訊預測alpha matte,在應用時也比trimap友好很多。MGMatting同時也提出了一個有636張精确标注人像的摳圖資料集RealWorldPortrait-636,可以通過合成等資料增廣方法擴充使用。

Trimap-free

實際應用中先驗資訊擷取起來是很不友善的,一些文章将先驗資訊擷取的部分也放在網絡中進行。

Semantic Human Matting

阿裡巴巴提出的Semantic Human Matting[^6]同樣分解了摳圖任務,網絡分為三個部分,T-Net對像素三分類得到Trimap,與圖像concat得到六通道輸入送入M-Net,M-Net通過encoder-decoder得到較為粗糙的alpha matte,最後将T-Net與M-Net的輸出送入融合子產品Fusion Module,最終得到更精确的alpha matte。

聊聊人像摳圖背後的算法技術

網絡訓練時的alpha loss分為alpha loss與compositional loss,與DIM類似,此外還加入了像素分類lossL_tLt​,最終loss為:L = L_p + L_t=L_\alpha + L_c + L_tL=Lp​+Lt​=Lα​+Lc​+Lt​。文章實作了端到端Trimap-free的摳圖算法,但較為臃腫。此外文章提出Fashion Model資料集,從電商網站收集整理了35000+标注的圖檔,但并沒有開放。

Modnet

modnet[^7]認為神經網絡更擅長學習單一任務,是以将摳圖任務分為三個子任務,分别進行顯式監督訓練和同步優化,最終可以以63fps在512x512輸入下達到soft結果,是以在後續的工程實作中我也選擇了modnet作為Baseline。

網絡的三個子任務分别是Semantic Estimation、Detail Prediction和Semantic-Detail Fusion,Semantic Estimation部分由backbone與decoder組成,輸出相對于輸入下采樣16倍的semantics,用來提供語義資訊,此任務的ground truth是标注的alpha經過下采樣與高斯濾波得到的。 Detail Prediction任務輸入有三個:原始圖像、semantic分支的中間特征以及S分支的輸出S_pSp​,D分支同樣是encoder-decoder結構,值得留意的該分支的loss,由于D分支隻關注細節特征,是以通過ground truth alpha生成trimap,隻在trimap的unknown區域計算d_pdp​與\alpha_gαg​的L_1L1​損失。F分支對語義資訊與細節預測進行融合,得到最終的alpha matte與ground truth計算L_1L1​損失,網絡訓練的總損失為:L=\lambda_sL_s + \lambda_dL_d+\lambda_{\alpha}L_{\alpha}L=λs​Ls​+λd​Ld​+λα​Lα​。

聊聊人像摳圖背後的算法技術
聊聊人像摳圖背後的算法技術

最後,文章還提出了一種使視訊結果在時間上更平滑的後處理方式OFD,在前後兩幀較為相似而中間幀與前後兩幀距離較大時,使用前後幀的平均值平滑中間幀,但該方法會導緻實際結果比輸入延遲一幀。

聊聊人像摳圖背後的算法技術

此外,U^2U2-Net、SIM等網絡可以對圖像進行顯著性摳圖,感興趣的話可以關注一下。

資料集

  • Adobe Composition-1K
  • matting_human_datasets
  • VideoMatte240K
  • PhotoMatte85
  • RealWorldPortrait-636

評價名額

常用的客觀評價名額來自于2009年CVPR一篇論文[^8],主要有:

聊聊人像摳圖背後的算法技術

此外,可以在paperwithcode上檢視Image Matting任務的相關文章,在Alpha Matting網站上檢視一些算法的evaluation名額。

本項目的最終目的是在HiLens Kit硬體上落地實作實時視訊讀入與背景替換,開發環境為HiLens配套線上開發環境HiLens Studio,先上一下對比baseline的改進效果:

使用modnet預訓練模型modnet_photographic_portrait_matting.ckpt進行測試結果如下:

聊聊人像摳圖背後的算法技術

可以看到由于場景較為陌生、逆光等原因會導緻摳圖結果有些閃爍,雖然modnet可以針對特定視訊進行自監督finetune,但我們的目的是在普遍意義上效果更好,是以沒有對本視訊進行自監督學習。

優化後的模型效果如下:

聊聊人像摳圖背後的算法技術

本視訊并沒有作為訓練資料。可以看到,摳圖的閃爍情況減少了很多,毛發等細節也基本沒有損失。

工程落地

為了測試baseline效果,首先我們要在使用場景下對baseline進行工程落地。根據文檔導入/轉換本地開發模型可知

昇騰310 AI處理器支援模型格式為".om",對于Pytorch模型來說可以通過"Pytorch->Caffe->om"或"Pytorch->onnx->om"(新版本)的轉換方式得到,這裡我選擇的是第一種。Pytorch->Caffe模型轉換方法與注意事項在之前的部落格中有具體闡述過,這裡不贅述。轉換得到Caffe模型後,可以在HiLens Studio中直接轉為om模型,非常友善。

首先在HiLens Studio中建立一個技能,此處選擇了空模闆,隻需要修改一下技能名稱就可以。

聊聊人像摳圖背後的算法技術

将Caffe模型上傳到model檔案夾下:

聊聊人像摳圖背後的算法技術

在控制台中運作模型轉換指令即可得到可以運作的om模型:

/opt/ddk/bin/aarch64-linux-gcc7.3.0/omg --model=./modnet_portrait_320.prototxt --weight=./modnet_portrait_320.caffemodel --framework=0 --output=./modnet_portrait_320 --insert_op_conf=./aipp.cfg      
聊聊人像摳圖背後的算法技術

接下來完善demo代碼。在測試時HiLens Studio可以在工具欄選擇使用視訊模拟攝像頭輸入,或連接配接手機使用手機進行測試:

聊聊人像摳圖背後的算法技術

具體的demo代碼如下:

# -*- coding: utf-8 -*-
# !/usr/bin/python3
# HiLens Framework 0.2.2 python demo
​
import cv2
import os
import hilens
import numpy as np
from utils import preprocess
import time
​
​
def run(work_path):
    hilens.init("hello")  # 與建立技能時的校驗值一緻
​
    camera = hilens.VideoCapture('test/camera0_2.mp4')  # 模拟輸入的視訊路徑
    display = hilens.Display(hilens.HDMI)
​
    # 初始化模型
    model_path = os.path.join(work_path, 'model/modnet_portrait_320.om') # 模型路徑
    model = hilens.Model(model_path)
​
    while True:
        try:
            input_yuv = camera.read()
            input_rgb = cv2.cvtColor(input_yuv, cv2.COLOR_YUV2RGB_NV21)
            # 摳圖後替換的背景
            bg_img = cv2.cvtColor(cv2.imread('data/tiantan.jpg'), cv2.COLOR_BGR2RGB) 
            crop_img, input_img = preprocess(input_rgb)  # 預處理
            s = time.time()
            matte_tensor = model.infer([input_img.flatten()])[0]
            print('infer time:', time.time() - s)
            matte_tensor = matte_tensor.reshape(1, 1, 384, 384)
​
            alpha_t = matte_tensor[0].transpose(1, 2, 0)
            matte_np = cv2.resize(np.tile(alpha_t, (1, 1, 3)), (640, 640))
            fg_np = matte_np * crop_img + (1 - matte_np) * bg_img  # 替換背景
            view_np = np.uint8(np.concatenate((crop_img, fg_np), axis=1))
            print('all time:', time.time() - s)
​
            output_nv21 = hilens.cvt_color(view_np, hilens.RGB2YUV_NV21)
            display.show(output_nv21)
​
        except Exception as e:
            print(e)
            break
​
    hilens.terminate()      

其中預處理部分的代碼為:

import cv2
import numpy as np
​
​
TARGET_SIZE = 640
MODEL_SIZE = 384
​
​
def preprocess(ori_img):
    ori_img = cv2.flip(ori_img, 1)
    H, W, C = ori_img.shape
    x_start = max((W - min(H, W)) // 2, 0)
    y_start = max((H - min(H, W)) // 2, 0)
    crop_img = ori_img[y_start: y_start + min(H, W), x_start: x_start + min(H, W)]
    crop_img = cv2.resize(crop_img, (TARGET_SIZE, TARGET_SIZE))
    input_img = cv2.resize(crop_img, (MODEL_SIZE, MODEL_SIZE))
​
    return crop_img, input_img      

demo部分的代碼非常簡單,點選運作即可在模拟器中看到效果:

聊聊人像摳圖背後的算法技術

模型推理耗時44ms左右,端到端運作耗時60ms左右,達到了我們想要的實時的效果。

效果改進

預訓練模型在工程上存在着時序閃爍的問題,原論文中提出了一種使視訊結果在時間上更平滑的後處理方式OFD,即用前後兩幀平均誤差大的中間幀。但這種辦法隻适合慢速運動,同時會導緻一幀延遲,而我們希望可以對攝像頭輸入進行實時、普适的時序處理,是以OFD不适合我們的應用場景。

在Video Object Segmentation任務中有一些基于Memory Network的方法(如STM),摳圖領域也有新論文如DVM考慮引入時序記憶單元使摳圖結果在時序上更穩定,但這些方法普遍需要前後n幀資訊,在資源占用、推理實時性、适用場景上都與我們希望的場景不符合。

考慮到資源消耗與效果的平衡,我們采用将前一幀的alpha結果cat到目前幀RGB圖像後共同作為輸入的方法來使網絡在時序上更穩定。

網絡上的修改非常簡單,隻需在模型初始化時指定in_channels = 4:

modnet = MODNet(in_channels=4, backbone_pretrained=False)      

訓練資料方面,我們選擇一些VideoMatting的資料集:VideoMatte240K、ConferenceVideoSegmentationDataset。

最初,我們嘗試将前一幀alpha作為輸入、缺失前幀時補零這種簡單的政策對模型進行訓練:

if os.path.exists(os.path.join(self.alpha_path, alpha_pre_path)):
    alpha_pre = cv2.imread(os.path.join(self.alpha_path, alpha_pre_path))
else:
    alpha_pre = np.zeros_like(alpha)
 
net_input = torch.cat([image, alpha_pre], dim=0)      

收斂部署後發現,在場景比較穩定時模型效果提升較大,而在人進、出畫面時模型适應較差,同時如果某一幀結果較差,将對後續幀産生很大影響。針對這些問題,考慮制定相應的資料增強的政策來解決問題。

  • 人進、出畫面時模型适應較差:資料集中空白幀較少,對人物入畫出畫學習不夠,是以在資料處理時增加空白幀機率:
if os.path.exists(os.path.join(self.alpha_path, alpha_pre_path)) and random.random() < 0.7:
    alpha_pre = cv2.imread(os.path.join(self.alpha_path, alpha_pre_path))
else:
    alpha_pre = np.zeros_like(alpha)      
  • 某一幀結果較差,将對後續幀産生很大影響:目前的結果較為依賴前一幀alpha,沒有學會抛棄錯誤結果,是以在資料處理時對alpha_pre進行一定機率的仿射變換,使網絡學會忽略偏差較大的結果;
  • 此外,光照問題仍然存在,在背光或光線較強處摳圖效果較差:對圖像進行光照增強,具體的,一定機率情況下模拟點光源或線光源疊加到原圖中,使網絡對光照更魯棒。光照資料增強有兩種比較常用的方式,一種是通過opencv進行簡單的模拟,具體可以參考augmentation.py,另外還有通過GAN生成資料,我們使用opencv進行模拟。

重新訓練後,我們的模型效果已經可以達到前文展示的效果,在16T算力的HiLens Kit上完全達到了實時、優雅的效果。進一步的,我還想要模型成為耗時更少、效果更好的優秀模型~目前在做的提升方向是:

  • 更換backbone:針對應用硬體選擇合适的backbone一向是提升模型成本效益最高的方法,直接根據耗時與資源消耗針對硬體搜一個模型出來最不錯,目前搜出來的模型轉為onnx測試結果(輸入192x192):
GPU:
Average Performance excluding first iteration. Iterations 2 to 300. (Iterations greater than 1 only bind and evaluate)
  Average Bind: 0.124713 ms
  Average Evaluate: 16.0683 ms
​
  Average Working Set Memory usage (bind): 6.53219e-05 MB
  Average Working Set Memory usage (evaluate): 0.546117 MB
​
  Average Dedicated Memory usage (bind): 0 MB
  Average Dedicated Memory usage (evaluate): 0 MB
​
  Average Shared Memory usage (bind): 0 MB
  Average Shared Memory usage (evaluate): 0.000483382 MB
 
CPU:
Average Performance excluding first iteration. Iterations 2 to 300. (Iterations greater than 1 only bind and evaluate)
  Average Bind: 0.150212 ms
  Average Evaluate: 13.7656 ms
​
  Average Working Set Memory usage (bind): 9.14507e-05 MB
  Average Working Set Memory usage (evaluate): 0.566746 MB
​
  Average Dedicated Memory usage (bind): 0 MB
  Average Dedicated Memory usage (evaluate): 0 MB
​
  Average Shared Memory usage (bind): 0 MB
  Average Shared Memory usage (evaluate): 0 MB      
  • 模型分支:在使用的觀察中發現,大部分較為穩定的場景可以使用較小的模型得到不錯的結果,所有考慮finetune LRBranch處理簡單場景,HRBranch與FusionBranch依舊用來處理複雜場景,這項工作還在進行中。

[^1]: Xu, Ning, et al. “Deep image matting.” Proceedings of the IEEE conference on computer vision and pattern recognition. 2017

[^2]:Sengupta, Soumyadip, et al. “Background matting: The world is your green screen.” Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition. 2020.

[^3]:Lin, Shanchuan, et al. “Real-Time High-Resolution Background Matting.” arXiv preprint arXiv:2012.07810 (2020).

[^4]:Li, Yaoyi, et al. “Inductive Guided Filter: Real-Time Deep Matting with Weakly Annotated Masks on Mobile Devices.” 2020 IEEE International Conference on Multimedia and Expo (ICME). IEEE, 2020.

[^5]: Yu, Qihang, et al. “Mask Guided Matting via Progressive Refinement Network.” arXiv e-prints (2020): arXiv-2012.

[^6]: Chen, Quan, et al. “Semantic human matting.” Proceedings of the 26th ACM international conference on Multimedia. 2018.

[^7]: Ke, Zhanghan, et al. “Is a Green Screen Really Necessary for Real-Time Human Matting?.” arXiv preprint arXiv:2011.11961 (2020).

[^8]:Rhemann, Christoph, et al. “A perceptually motivated online benchmark for image matting.” 2009 IEEE Conference on Computer Vision and Pattern Recognition. IEEE, 2009.

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀