AI一鍵去紋身,還原明星「廬山真面目」
大家好,我是Jack。
這兩天在 Reddit 上看到了一個(gè)挺好玩的算法,立馬連夜寫文過來分享一波。
AI去除紋身:

國(guó)內(nèi)的一些影視作品、綜藝節(jié)目、B站視頻等,都有一些去除紋身的需求。
有些時(shí)候,我們需要把一些人身上的紋身覆蓋掉,以避免引人效仿。
來自印度的機(jī)器學(xué)習(xí)研究者 Vijish Madhavan 最近開源的一個(gè)機(jī)器學(xué)習(xí)工具 SkinDeep 滿足了我們這個(gè)需求。
項(xiàng)目靈感來源于賈斯汀 · 比伯一次拍 MV ,化妝師花費(fèi)幾個(gè)小時(shí)的時(shí)間才把一身的紋身覆蓋掉,采用圖像的處理方式可以更省事省力。
SkinDeep
項(xiàng)目地址:https://github.com/vijishmadhavan/SkinDeep

使用 SkinDeep 相比于 Photoshop 更省事一些,畢竟節(jié)省了幾個(gè)小時(shí)的時(shí)間去修修補(bǔ)補(bǔ)。
我們先看下效果,下圖中第一行為輸入圖像,第二行為輸出圖像,輸出結(jié)果明顯感覺到,紋身被去除了。

臉部有大量密集紋身的圖像,還有其他裝飾,AI 的紋身去除效果也非常好:

與專業(yè)圖像處理軟件 photoshop 相比,效果也不錯(cuò):

看起來 SkinDeep 的效果還不錯(cuò),但如果紋身是彩色的,還會(huì)有一些痕跡。
數(shù)據(jù)集
完成這個(gè)項(xiàng)目需要大量的圖像對(duì),因?yàn)闆]有合適的數(shù)據(jù)集,很多時(shí)候訓(xùn)練內(nèi)容采用合成數(shù)據(jù)來完成,具體來說:
首先將 APDrawing 數(shù)據(jù)集圖像對(duì)與一些背景去掉紋身設(shè)計(jì)的圖像疊加在一起,使用 Python OpenCV 實(shí)現(xiàn); 繪制數(shù)據(jù)集模擬紋身線條,有助于模型學(xué)習(xí)和刪除這些線條; APDrawing 數(shù)據(jù)集只有頭像,對(duì)于全身圖像,項(xiàng)目作者采用了以前的項(xiàng)目 ArtLine,并將輸出與輸入圖像疊加在一起;


ImageDraw.Draw 與森林綠色(forest green colour)色碼一起使用,并隨機(jī)放置在身體圖像上,類似于 fast.ai 中的 Crappify ;
Photoshop 也被用來在需要彎曲和角度改變的對(duì)象上放置紋身。

簡(jiǎn)單看了下代碼,實(shí)現(xiàn)很簡(jiǎn)單,采用 fast.ai 封裝的 unet 進(jìn)行端到端的訓(xùn)練,并不復(fù)雜。
算法測(cè)試
開源代碼使用 ipynb 文件,測(cè)試方法很簡(jiǎn)單,就兩種:
本地:安裝 fast.ai ,用 jupyter 打開 ipynb。 colab:直接用 colab 打開。
本地搭建環(huán)境,所需要安裝的依賴:
fastai==1.0.61
numpy==1.17.2
pandas==1.1.2
torch==1.6.0
torchvision===0.7.0
本地用 Anaconda 安裝好第三方庫(kù),下載好代碼后,用 jupyter 打開 ipynb 運(yùn)行。
代碼并不復(fù)雜,核心代碼,就這幾行:
import fastai
from fastai.vision import *
from fastai.utils.mem import *
from fastai.vision import open_image, load_learner, image, torch
import numpy as np
import urllib.request
import PIL.Image
from io import BytesIO
import torchvision.transforms as T
from PIL import Image
import requests
from io import BytesIO
import fastai
from fastai.vision import *
from fastai.utils.mem import *
from fastai.vision import open_image, load_learner, image, torch
import numpy as np
import urllib.request
import PIL.Image
from io import BytesIO
import torchvision.transforms as T
class FeatureLoss(nn.Module):
def __init__(self, m_feat, layer_ids, layer_wgts):
super().__init__()
self.m_feat = m_feat
self.loss_features = [self.m_feat[i] for i in layer_ids]
self.hooks = hook_outputs(self.loss_features, detach=False)
self.wgts = layer_wgts
self.metric_names = ['pixel',] + [f'feat_{i}' for i in range(len(layer_ids))
] + [f'gram_{i}' for i in range(len(layer_ids))]
def make_features(self, x, clone=False):
self.m_feat(x)
return [(o.clone() if clone else o) for o in self.hooks.stored]
def forward(self, input, target):
out_feat = self.make_features(target, clone=True)
in_feat = self.make_features(input)
self.feat_losses = [base_loss(input,target)]
self.feat_losses += [base_loss(f_in, f_out)*w
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.feat_losses += [base_loss(gram_matrix(f_in), gram_matrix(f_out))*w**2 * 5e3
for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
self.metrics = dict(zip(self.metric_names, self.feat_losses))
return sum(self.feat_losses)
def __del__(self): self.hooks.remove()
當(dāng)然,也可以直接打開 Colab 運(yùn)行,省去配置環(huán)境的麻煩。
https://colab.research.google.com/github/vijishmadhavan/SkinDeep/blob/master/SkinDeep_good.ipynb
測(cè)試效果:

絮叨
SkinDeep 的效果,作者還在優(yōu)化,一些紋身覆蓋面大、花色紋身等效果要差一些。
這個(gè)不是什么新的、高端算法,只是一個(gè)好玩、實(shí)用的應(yīng)用。
記得給 Jack 來個(gè)星標(biāo)哦,我們下期見。

推薦閱讀
? 聊聊自學(xué),我私藏的學(xué)習(xí)網(wǎng)站和工具? 你說,我畫,AI工具人石錘。? 萬字長(zhǎng)文,60分鐘閃電戰(zhàn)
