一文讀懂Image matting(圖像摳圖)

極市導(dǎo)讀
?本文為圖像摳圖的入門(mén)版介紹,作者詳細(xì)闡述了圖像摳圖的三種方法并介紹了一個(gè)圖像摳圖應(yīng)用倉(cāng)庫(kù),附有安裝以及使用步驟詳解。?>>加入極市CV技術(shù)交流群,走在計(jì)算機(jī)視覺(jué)的最前沿
今天禮拜六休息一天,閑著沒(méi)事干想給證件照換張背景顏色。上網(wǎng)隨手搜了下發(fā)現(xiàn)是屬于圖像摳圖的領(lǐng)域,本想著下個(gè)項(xiàng)目來(lái)玩玩,沒(méi)想到很多還要收費(fèi),要不然就是要會(huì)員。本著敬業(yè)的精神(為了省錢(qián)),特地花費(fèi)一天研究下什么是圖像摳圖。
1. What's the Image Matting?
圖像摳圖(Image Matting),是指從圖像中提取出我們所感興趣的前景目標(biāo),同時(shí)過(guò)濾掉背景部分。一張圖像可以簡(jiǎn)單的看成是由兩部分組成,即前景(Foreground)和背景(Background)。簡(jiǎn)單來(lái)說(shuō),摳圖,就是將一張給定圖像的前景和背景區(qū)分開(kāi)來(lái)。

版權(quán)所有,請(qǐng)勿盜用
假設(shè)原始圖像用?來(lái)表示,?表示對(duì)應(yīng)的Alpha通道,?和?分別表示對(duì)應(yīng)的前景圖像和背景圖像。那么,如上所示,我們可以看出,一張具有RGBA通道的圖像,它可以分解為如下幾部分的組合,即
上述公式最早出自于《Blue screen matting》[9],由Smith, Alvy Ray, and James F. Blinn兩人提出。Smith也算是圖形學(xué)的先驅(qū),同時(shí)也是HSV顏色空間的作者,據(jù)說(shuō)喬幫主第一款Mac的圖像界面就是他所設(shè)計(jì)的。Smith在1978年還創(chuàng)建了的一種著名的顏色空間HSV,也稱(chēng)六角錐體模型(Hexcone Model)注:HSV即Hue(色調(diào)色相)、 Saturation(飽和度、色彩純凈度)和Value(明度)。關(guān)于更多內(nèi)容大家有興趣的可以自行查閱。
當(dāng)?為0時(shí),圖像為背景圖像;當(dāng)?為1時(shí),圖像為前景圖像。因此,對(duì)于圖像中的每個(gè)像素點(diǎn),均可以表示為一個(gè)類(lèi)似于上述的線(xiàn)性方程組。因此,摳圖的主要目標(biāo)是根據(jù)原始輸入圖像,來(lái)獲得前景、背景和透明度。
Alpha通道,指的是一張圖片的透明度。比如真彩色圖像,它是24bit,含有RGB三彩色通道,每個(gè)通道占8位。在這個(gè)基礎(chǔ)上,我們可以給它擴(kuò)充到32bit,增加一個(gè)獨(dú)立的通道,即α通道(黑白灰通道),來(lái)控制圖片顯示的透明度,從而得到RGBA四個(gè)通道。其中,值越大,圖像的透明度越低。我們知道二進(jìn)制下的8位可以表示的范圍是0-255,即255代表不透明(白色),0表示完全透明(黑色),中間值則為半透明(灰色);因此只有當(dāng)α=255時(shí)疊加到原始圖像上才會(huì)顯示其真正的顏色。一般來(lái)說(shuō),TIFF、PNG和GIF均是支持Alpha通道的,我們經(jīng)常會(huì)利用Alpha通道的性質(zhì)來(lái)實(shí)現(xiàn)摳圖或者獲得具有透明背景的圖片。
2. Methods
2.1 Bayesian-based matting
貝葉斯摳圖是一種交互式的輸入摳圖,其中,對(duì)于一些像素點(diǎn)F(前景)、B(背景)及圖片C的alpha值我們是已知的。我們的目標(biāo)便是根據(jù)這些已知的值使求解出來(lái)的未知值F、B、C和alpha滿(mǎn)足最大概率。
argmax是一種函數(shù),用于對(duì)函數(shù)求參數(shù)(集合)的函數(shù)。求比如對(duì)于argmax(f(x)),可以簡(jiǎn)單理解為使得函數(shù)f(x)取得最大值所對(duì)應(yīng)的變量x,如果由多個(gè)變量均能滿(mǎn)足條件,則為變量點(diǎn)x的集合。
??
Bayesian Formula
這里?。對(duì)于多個(gè)概率連乘的形式,我們一般會(huì)求對(duì)數(shù),將其轉(zhuǎn)化為加法方便運(yùn)算。因此,我們需要求解出使上述公式概率最大化的最優(yōu)參數(shù)F、B和alpha的數(shù)值。
Grab cut算法是基于高斯混合模型對(duì)已知的前景和背景對(duì)象進(jìn)行建模。為了保證空間的連續(xù)性,基于貝葉斯的方法采用的是對(duì)每個(gè)未知像素的N個(gè)鄰域點(diǎn)進(jìn)行聚類(lèi)。對(duì)于上述公式,右邊第一項(xiàng)反映的是圖像顏色被賦予F、B和alpha值的可能性。因此,為了獲得一個(gè)更優(yōu)解,我們應(yīng)該保持摳圖方程不變,即第一項(xiàng)可以建模為:
注意到,這里?是一個(gè)可調(diào)參數(shù),它反映了與摳圖假設(shè)的預(yù)期偏差值。
對(duì)于公式中其它的三項(xiàng),則分別代表了前景、背景和α通道分布上的先驗(yàn)概率,這里我們可以根據(jù)用戶(hù)輸入的已知像素點(diǎn),計(jì)算出當(dāng)前顏色值屬于前景的概率。
是前景、背景和α分布上的先驗(yàn)概率。我們可以通過(guò)用戶(hù)輸入的已知像素來(lái)計(jì)算一個(gè)顏色值屬于前景的概率。如此一來(lái),我們便可以將高斯分布擬合到每個(gè)強(qiáng)度值的集合。對(duì)于顏色B,我們可以根據(jù)以下公式進(jìn)行估計(jì):

Gaussian distribution
上述其實(shí)是一個(gè)高斯分布的近似公式。這里均值和標(biāo)準(zhǔn)差分別為:

其實(shí),這些都是可以算出來(lái)的。這樣一來(lái),我們便可以得到前景和背景的先驗(yàn)分布估計(jì):

對(duì)于最后一項(xiàng),即?,可以假設(shè)它是一個(gè)常數(shù)項(xiàng)。這樣我們可以通過(guò)概率最大化方程求解偏導(dǎo)數(shù)并將其置為0即可,所以可以直接忽略掉。下面,我們通過(guò)最熟悉的聯(lián)立方程組,便可以解決貝葉斯摳圖問(wèn)題。:

最后,讓我們來(lái)梳理下整個(gè)流程的步驟吧:
對(duì)每個(gè)像素的alpha值進(jìn)行預(yù)估; 交替求解方程得到前景F和背景B; 固定F和B的值,聯(lián)立方程求解到alpha的值; 重復(fù)上述步驟,直至這三個(gè)變量值(F、B and Alpha)收斂。
2.2 Laplacian-based matting
首先,假設(shè)有一個(gè)小窗口?,我們考慮其周?chē)拿總€(gè)像素?:

那么在這個(gè)窗口上,我們可以近似地建立第1節(jié)所述的方程關(guān)系,即:

接下來(lái),化簡(jiǎn)、移項(xiàng),可得:

為了簡(jiǎn)要表述,這里我們令:

從上面公式也可以看出來(lái),我們近似的將其表達(dá)成一個(gè)線(xiàn)性方程,參數(shù)是a和b。假設(shè)一個(gè)窗口內(nèi)的α值和顏色是相關(guān)的,我們可以將其延申為一個(gè)帶成本函數(shù)(cost function)的摳圖問(wèn)題:

Laplace's equation
由于整張圖像是由許多重疊的窗口所組成的,所以整體的目標(biāo)函數(shù)可以表示為窗口的集合:

N is the number of windows
下面我們要做的工作便是最小化成本函數(shù)J,來(lái)尋找最佳的?以及每一個(gè)像素點(diǎn)?所對(duì)應(yīng)的窗口?的系數(shù)值?和?。為了防止0值,可以引入正則化,即對(duì)應(yīng)公式右邊的偏差項(xiàng)。根據(jù)經(jīng)驗(yàn)值,當(dāng)所有的顏色通道像素值范圍為[0, 1]時(shí),我們可以將?設(shè)置為1e-7。
接下來(lái),我們將上述公式寫(xiě)成矩陣的形式:

再簡(jiǎn)化下,可以寫(xiě)成:

假設(shè)這個(gè)矩陣是已知的,那么這個(gè)向量即為一個(gè)常量,我們可以單獨(dú)將?的方程最小化為一個(gè)標(biāo)準(zhǔn)的線(xiàn)性系統(tǒng):

對(duì)于給定的對(duì)于給定的α值,每個(gè)窗口中最優(yōu)的a和b是關(guān)于α的線(xiàn)性函數(shù)。當(dāng)我們把上式代入原式得到:

注意,這里?表示單位矩陣,其維度等于窗口大小。通過(guò)代數(shù)運(yùn)算,我們可以計(jì)算出拉普拉斯算子中的元素:

其中?和?是第k個(gè)窗口顏色的均值和協(xié)方差矩陣,而?是克羅內(nèi)克爾函數(shù)。
Kronecker delta,即克羅內(nèi)克函數(shù),是一個(gè)二元函數(shù),是由德國(guó)數(shù)學(xué)家利奧波德·克羅內(nèi)克所提出來(lái)的??肆_內(nèi)克函數(shù)的自變量一般時(shí)兩個(gè)整數(shù),當(dāng)兩者相等時(shí)輸出為1,否則為0。
下面,根據(jù)當(dāng)前像素點(diǎn)是屬于前景像素或者背景像素,給出兩個(gè)約束條件:

通過(guò)使用拉格朗日乘數(shù)法求解這個(gè)問(wèn)題,首先建立拉格朗日函數(shù):

拉格朗日乘數(shù)法是一種尋找變量受一個(gè)或多個(gè)條件所限制的多元函數(shù)的極值的方法。
到這里就好辦了,把高數(shù)用起來(lái)哈哈。求導(dǎo),令其等于0,完美解決:

最后,我們便能將問(wèn)題轉(zhuǎn)化為線(xiàn)性方程組進(jìn)行解決即可:

2.3 deep learning-based matting
傳統(tǒng)算法除了上述兩種,其實(shí)還有不少,比如基于KNN的matting等。由于篇幅內(nèi)容就不展開(kāi)了,有興趣的可以參考下相關(guān)領(lǐng)域大佬[10]發(fā)表的綜述文章。下面介紹下深度學(xué)習(xí)相關(guān)的摳圖方法?;谏疃葘W(xué)習(xí)的摳圖算法也屬于圖像分割(Image Segmentation)的范疇,只不過(guò)是一種軟分割。今天主要介紹的是CVPR 2020上的一篇摳圖相關(guān)的文章——U2-Net[6],框架圖如下所示:
硬分割(Hard Segmentation):一個(gè)像素點(diǎn)要么是前景,要么是背景;
軟分割(Soft Segmentation):一個(gè)像素點(diǎn)除了是前景和背景,還可能使由兩者共同決定

Schematic diagram of U2-Net framework
emmm,沒(méi)錯(cuò)!就是多個(gè)U-Net的的級(jí)聯(lián),將U-Net視為一個(gè)獨(dú)立的特征提取模塊,類(lèi)似于Residual block。U2-Net由于摳圖效果超群,思想簡(jiǎn)單,效率又高,一提出在Reddit上就被熱議,不然我們?cè)趺茨荜P(guān)注到它呢?
Reddit是一個(gè)集娛樂(lè)、社交及新聞的網(wǎng)站, 大家有空也可以多關(guān)注關(guān)注。
好了,廢話(huà)有點(diǎn)多,言歸正傳。在介紹U2-Net時(shí)我們先簡(jiǎn)單的回顧下U-Net。U-Net是和FCN在同一個(gè)時(shí)期出的產(chǎn)物,一個(gè)主攻數(shù)據(jù)量大樣本較為簡(jiǎn)單的自然圖像領(lǐng)域,另一個(gè)則主攻數(shù)據(jù)量小樣本較為困難的醫(yī)學(xué)圖像領(lǐng)域,只不過(guò)FCN比U-Net早提出。當(dāng)然,后面還出了還多基準(zhǔn)網(wǎng)絡(luò),比如提拉米蘇網(wǎng)絡(luò),將U-Net中的concatenate操作替換為element-wise sum操作。此外,還有類(lèi)似的很多網(wǎng)絡(luò),不多大同小異。U-Net可以看出是繼承了FCN的思想,為了進(jìn)一步地改善FCN分割粗糙的特點(diǎn),U-Net在FCN的基礎(chǔ)上,在編碼器和解碼器之間引入了長(zhǎng)距離跳躍連接(Long-range skip connection),通過(guò)結(jié)合來(lái)自底層的細(xì)節(jié),有效的彌補(bǔ)了因下采樣操作過(guò)程中空間信息缺失,幫助網(wǎng)絡(luò)恢復(fù)更加精確的定位,這對(duì)于醫(yī)學(xué)圖像分割、遙感圖像分割以及摳圖這種對(duì)細(xì)節(jié)非??粗氐拿芗头指钊蝿?wù)來(lái)說(shuō)是至關(guān)重要的。當(dāng)然U-Net也有很多可以改進(jìn)的地方,下面列舉一些關(guān)鍵的突破口:
特征提取。關(guān)于特征提取能力,原始的U-Net用的是兩個(gè)連續(xù)的plain卷積來(lái)提取特征。我們可以將其替換為Residual block、Recurrent block、Dilated conv、Dynamid conv等等。除此之外,還可以自己根據(jù)任務(wù)來(lái)設(shè)計(jì)。筆者前段時(shí)間也自行嘗試設(shè)計(jì)了一個(gè),在參數(shù)量和計(jì)算量更少的情況下提高了2-3個(gè)點(diǎn)。其實(shí)現(xiàn)在頂會(huì)頂刊上出現(xiàn)的絕大多數(shù)卷積都大同小異:如何在保證時(shí)間或空間復(fù)雜度的情況,盡可能地增強(qiáng)特征的表示能力。關(guān)于節(jié)省復(fù)雜度,我們可以結(jié)合到利用基(Radix)的優(yōu)勢(shì)以及1x1卷積之類(lèi)的操作進(jìn)行降維再生維的操作。而增強(qiáng)特征的表示能力也有好多種方式,最核心的兩點(diǎn)便是感受野和信息的有效利用。 特征抑制。許多圖像在成像過(guò)程中由于外部環(huán)境的因素總是不可避免的會(huì)遭到許多背景噪聲的干擾。不知道大家觀(guān)察到,U-Net類(lèi)型的網(wǎng)絡(luò)在引入跳躍連接操作時(shí),來(lái)自底層的信息如果我們直接利用,這時(shí)候或多或少會(huì)伴隨許多噪聲的干擾。關(guān)于抑制或去除噪聲,主要可以通過(guò)在數(shù)據(jù)上或模型上進(jìn)行改進(jìn)。數(shù)據(jù)改進(jìn)的話(huà)一般時(shí)通過(guò)一些CLAHE、Gamma增加等操作來(lái)增強(qiáng)對(duì)比度和抑制噪聲,或者對(duì)于一些肉眼可見(jiàn)的噪聲可以直接通過(guò)crop操作來(lái)去除。你會(huì)發(fā)現(xiàn)很多競(jìng)賽獲勝選手的方案里邊都會(huì)花費(fèi)大力氣對(duì)數(shù)據(jù)進(jìn)行清洗,純凈的數(shù)據(jù)往往是獲得高分性能的關(guān)鍵。而模型上的改進(jìn)也有不少,比如可以借助光流的思想通過(guò)高級(jí)特征的語(yǔ)義信息來(lái)校準(zhǔn)低級(jí)特征的分布。比較常規(guī)的方法可以是通過(guò)一些類(lèi)似于注意力的方式來(lái)進(jìn)行背景抑制,使用注意力方法可以對(duì)前景特征進(jìn)行加權(quán)輸出使模型更加關(guān)注,另一方面降低背景特征的權(quán)重,不失為一種良好的解決方案。關(guān)于不同的注意力方法筆者也做了一個(gè)總結(jié),可以參考下這篇文章:
特征融合。特征融合旨在融合盡可能多的信息來(lái)獲得更具有判別力的特征表示。一般可分為模塊內(nèi)的特征融合以及模塊間的特征融合。這里的模塊可以理解為特征提取器,好比如Residual block和Dense block,形式上可以看成是將前一級(jí)的信息和后一級(jí)或多級(jí)的信息融合起來(lái),以加強(qiáng)信息的傳遞。模塊間的融合方式可以參考深監(jiān)督的形式,本文的U2Net就利用到了多層級(jí)(multi-level)的融合,來(lái)學(xué)習(xí)更多的語(yǔ)義表示,獲得更加精確化的分割結(jié)果。再比如UNet++,直接再編解碼器之間進(jìn)行多層級(jí)融合。又或者HR-Net,將高、低分辨率特征的信息進(jìn)行融合。當(dāng)然,并不是說(shuō)融合越多的信息越好,畢竟不同層級(jí)的特征之間存在一個(gè)語(yǔ)義偏差(bias)。順著這一點(diǎn)我們又可以做很多工作,比如給不同層級(jí)的特征加不同的權(quán)重,設(shè)置幾個(gè)超參數(shù)讓網(wǎng)絡(luò)按照既定的規(guī)則進(jìn)行融合。如果不想調(diào)參,再改進(jìn)的話(huà)也不是不可以。
說(shuō)回U2-Net。其實(shí)上面分析了很多,能吸收的基本看一眼框架圖一眼就秒懂創(chuàng)新點(diǎn)。非要重述的話(huà),無(wú)非就是在保證計(jì)算效率的同時(shí),堆疊已有的經(jīng)過(guò)驗(yàn)證切實(shí)有效的模塊來(lái)融合具有不同尺度的感受野,捕獲更加充足的上下文信息,最后再通過(guò)融合多層級(jí)的特征獲得一個(gè)更加精細(xì)化的更具有判別力的特征。雖說(shuō)簡(jiǎn)單,不過(guò)筆者本人信奉“大道至簡(jiǎn)”的原則,越有效的東西往往是越簡(jiǎn)潔的,成天寫(xiě)一堆花里胡哨的話(huà)是秀給Reviewer看的,大家不用過(guò)度當(dāng)真,只需取其精華,去其糟粕即可。
3. How to implement Image Matting?
寫(xiě)了這么多理論(廢話(huà)),關(guān)鍵還是要用一用才舒坦。先給出U2-Ne的源github鏈接:NathanUA/U-2-Net。這是原作者的倉(cāng)庫(kù)鏈接,代碼看起來(lái)也很好理解。除了圖像摳圖以外,作者還列出了其它研究人員很多基于U2-Net開(kāi)發(fā)的有趣應(yīng)用,比如人像繪畫(huà)、肖像生成等,有興趣的可以自己去源倉(cāng)庫(kù)看看。不過(guò)今天給大家介紹另外一個(gè)圖像摳圖應(yīng)用倉(cāng)庫(kù),我們也不浪費(fèi)時(shí)間重復(fù)造輪子了,直接用rembg來(lái)生成即可。
rembg是一個(gè)外國(guó)小伙子基于U2-Net用python和flask開(kāi)發(fā)出來(lái)的背景移除工具。
好了,都到這里了,好人做到底,下面給出小白保姆級(jí)教程。注意:下面教程是針對(duì)Wins操作系統(tǒng)如何完美運(yùn)行rembg,Linux或Mac OS系統(tǒng)由于基本沒(méi)什么坑直接安裝即可。
3.1 Miniconda
第一步是安裝Miniconda,順手整理一波常用的配置指令,詳情可參考這篇:
Anaconda下conda的創(chuàng)建、激活、退出、刪除、配置虛擬環(huán)境以及pip的相關(guān)操作_Jack_0601的博客
https://blog.csdn.net/weixin_43509263/article/details/112097511
3.2 Pakages
第二步是安裝相關(guān)包,筆者電腦顯卡是基于CUDA 10.1版本,下面給出具體的操作步驟:
下載源代碼:
如果本地有安裝git,可以直接打開(kāi)cmd窗口,進(jìn)入到要保存文件的目錄,運(yùn)行:
git clone https://github.com/danielgatis/rembg.git
如果下載速度堪憂(yōu),可以直接打開(kāi)github,復(fù)制網(wǎng)址,直接用迅雷下載壓縮包,解壓放到本地。
按下快捷鍵Win+S,輸入Anaconda Prompt,打開(kāi)窗口新建一個(gè)虛擬環(huán)境:
conda create -n matting python=3.7 -y
激活環(huán)境:
conda activate matting
安裝pytorch:
大家先上pytorch官網(wǎng)查看自己適配的版本,比如我的:

可以把你的版本號(hào)對(duì)應(yīng)改下,使用以下指令進(jìn)行下載:
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
conda install pytorch torchvision torchaudio cudatoolkit=10.1
如果下載速度太慢,或者網(wǎng)絡(luò)不穩(wěn)定,由于Pytorch等包太大,很大概率會(huì)失敗。如果出現(xiàn):An HTTP error occurred when trying to retrieve this URL.錯(cuò)誤,可以參考下這篇博客(https://blog.csdn.net/weixin_36465540/article/details/111242733)。
安裝requirements.txt文件下的pkgs
將以下包替換掉requirements.txt這個(gè)文件下的包:
flask==1.1.2
numpy==1.19.3
pillow==8.0.1
scikit-image==0.17.2
waitress==1.4.4
tqdm==4.51.0
requests==2.24.0
scipy==1.5.4
pymatting==1.1.1
filetype==1.0.7
hsh==1.1.0
opencv-python==4.5.1.48
進(jìn)入到requirements.txt文件所在目錄,執(zhí)行一鍵安裝指令,體驗(yàn)飛一般的下載安裝速度:
pip install -r requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
下載訓(xùn)練好的U2-Net權(quán)重文件:
百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/11KD_r5dY-YOlOL9AE9PorQ
提取碼:6qjo
下載后在根目錄下新建一個(gè)u2net目錄,并將權(quán)重文件放置到該文件下,具體可參考:

3.3 Running
測(cè)試圖像
這個(gè)Project作者僅提供摳圖,而且作者并沒(méi)有提供script,隨便寫(xiě)了個(gè),不會(huì)寫(xiě)的可以參考下我的demo.py文件。將你想要測(cè)試的圖像放置到examples文件目錄下,具體文件目錄和名稱(chēng)可自行修改:
"""
demo.py
authored by @湃森 [https://www.zhihu.com/people/peissen]
"""
import io
import os
import cv2
import numpy as np
from PIL import Image, ImageFile
from src.rembg.bg import remove
ImageFile.LOAD_TRUNCATED_IMAGES = True
def show(img):
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def get_mask(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 圖像灰度化處理
img_gray = cv2.GaussianBlur(img_gray, (3, 3), 0) # 用(3, 3)的高斯核進(jìn)行模糊化處理
img_mask = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] # 使用自適應(yīng)閾值二值化處理
return img_mask
def get_path(file_path, file_name, extension):
"""
:param file_path: 文件路徑
:param file_name: 文件名
:param extension: 擴(kuò)展名
:return:
"""
total_name = file_name + extension
path = os.path.join(file_path, total_name)
return path
def get_background(img_src, img_1_alpha):
"""
:param img_src: 源圖像
:param img_1_alpha: 1-alpha
:return: 背景圖像
"""
img_src_np = np.array(img_src)
img_alpha_np = np.array(img_1_alpha)
img_alpha_np = np.expand_dims(img_alpha_np, axis=2)
img_merge = np.concatenate((img_src_np, img_alpha_np), axis=2)
res = Image.fromarray(img_merge)
return res
def get_foreground(path):
"""
:param path: 源文件輸入路徑
:return: 前景圖像
"""
file = np.fromfile(path) # 用numpy加載源圖像
img_fg = remove(file) # 實(shí)現(xiàn)摳圖
img_rgba = Image.open(io.BytesIO(img_fg)).convert("RGBA") # 轉(zhuǎn)換為RGBA的圖像格式
assert img_rgba.mode == 'RGBA' # 判斷是否成功轉(zhuǎn)換
return img_rgba
def joint_img_horizontal(img_list):
w, h = img_list[0].size
res = Image.new('RGBA', (w * len(img_list), h))
for idx, img in enumerate(img_list):
res.paste(img, box=(idx * w, 0))
return res
def background_color_transform(img_src_path, img_alpha_path, img_show=False):
# 獲取二值圖像
img_alpha = cv2.imread(img_alpha_path)
img_mask = get_mask(img_alpha)
if img_show:
show(img_mask)
# 加載源圖像
img_src = cv2.imread(img_src_path, cv2.IMREAD_COLOR)
if img_show:
show(img_src)
# 背景顏色替換
# 注意,這里替換的顏色通道是(B,G,R)
img_src[img_mask == 0] = (0, 0, 255)
if img_show:
show(img_src)
return img_src
def main():
# 文件路徑
file_path = './examples' # 文件所在目錄
file_name = 'photo' # 文件名
input_path = get_path(file_path, file_name, '.jpg') # 源圖像
background_path = get_path(file_path, 'back1', '.jpg') # 背景圖
out_alpha_path = get_path(file_path, file_name, '_alpha.png') # alpha通道
out_1_alpha_path = get_path(file_path, file_name, '_1-alpha.png') # 1-alpha通道
out_fg_path = get_path(file_path, file_name, '_fg.png') # 前景圖
out_bg_path = get_path(file_path, file_name, '_bg.png') # 背景圖
out_joint_path = get_path(file_path, file_name, '_joint.png') # 多圖拼接
out_bg_color_trans_path = get_path(file_path, file_name, '_bg_color_trans.png') # 背景替換
out_synthesis_path = get_path(file_path, file_name, '_synthesis.png') # 背景替換
# 加載源圖像
img_src = Image.open(input_path)
# 獲取并保存前景圖像
img_fg = get_foreground(input_path)
# print(len(img_fg.split())) = 4
img_fg.save(out_fg_path)
# 獲取并保存前景圖像的alpha通道
img_alpha = img_fg.split()[-1] # 通道分離,R/G/B/A
# print(len(img_alpha.split())) = 1
img_alpha.save(out_alpha_path)
# 獲取并保存對(duì)應(yīng)的1-alpha通道
img_1_alpha = img_alpha.point(lambda i: 255 - i)
# print(len(img_1_alpha.split())) = 1
img_1_alpha.save(out_1_alpha_path)
# 獲取并保存背景圖像
img_bg = get_background(img_src, img_1_alpha)
img_bg.save(out_bg_path)
# 拼接圖像
img_list = [img_src, img_fg, img_alpha, img_bg, img_1_alpha]
img_total = joint_img_horizontal(img_list)
img_total.save(out_joint_path)
# 背景遷移
img_bg_color_trans = background_color_transform(input_path, out_alpha_path, img_show=False)
cv2.imwrite(out_bg_color_trans_path, img_bg_color_trans)
if __name__ == '__main__':
main()
如果不出意外,可以得到結(jié)果:

源圖地址:https://www.google.com.hk/url?sa=i&url=https%3A%2F%2Fwww.pi7.com%2Farticle%2Fv34951.html&psig=AOvVaw199Fu3dgbSuqkrloA8fT36&ust=1610877033087000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCIDU6N-WoO4CFQAAAAAdAAAAABAD

要想圖方便的話(huà),作者使用了flask框架,提供了web端的接口測(cè)試,可以在終端執(zhí)行rembg-server啟動(dòng)后臺(tái)的相關(guān)服務(wù)。具體運(yùn)行指令可以根據(jù)官方提供的op進(jìn)行測(cè)試,我自己寫(xiě)了個(gè)還沒(méi)用過(guò),不過(guò)應(yīng)該得到的結(jié)果是一樣的。不過(guò)好像只提供摳圖,其它要自己寫(xiě)腳本來(lái)操作。事先聲明,未經(jīng)本人允許不得私自轉(zhuǎn)載。
有問(wèn)題的可在評(píng)論區(qū)反饋,謝絕私聊問(wèn)一堆問(wèn)題,下面根據(jù)大家反饋的常見(jiàn)錯(cuò)誤更新如下:
Attempted to compile AOT function without the compiler used by `numpy.distutils` present. Cannot find suitable msvc.
這個(gè)問(wèn)題是因?yàn)楸緳C(jī)還沒(méi)有裝C++ compiler,進(jìn)入visualstudio官網(wǎng)(https://visualstudio.microsoft.com/zh-hans/downloads/)下載:

展開(kāi),選擇Visual Studio 2019生成工具,點(diǎn)擊下載:

一路默認(rèn),到這里勾選C++ bulid tools即可,繼續(xù)安裝,重啟機(jī)器即可。

Reference
推薦閱讀

