你這背景太假了,用AI自動合成,假嗎?
哈嘍,大家好。
前幾天大家是不是都刷到了下面這個視頻。
博主本來想證明自己背景是真的,結(jié)果引來網(wǎng)友惡搞,紛紛換成各種各樣的背景來“打假”。
今天咱也湊個熱鬧,用 AI 技術(shù)自動替換背景。
思路并不難,我們先從原視頻將人物分離出來,再將分離出來的人物“貼”到新背景視頻中即可。
從視頻中分類人物用到關(guān)鍵技術(shù)的是計算機視覺?中的實例分割?,我之前的文章中有介紹過目標檢測技術(shù),比如,人臉檢測
目標檢測?是通過矩形框標注檢測的目標,相對容易。而實例分割是一項更精細的工作,因為需要對每個像素點分類,物體的輪廓是精準勾勒的。
我們今天用 detectron2? 做實例分割?,它是Facebook AI研究院開源的項目,功能強大,使用簡單。
1. 安裝
detectron2? 支持在Linux和macOS?系統(tǒng)上安裝,Linux?可以直接通過pip?安裝,而mac?只能通過源碼編譯的方式安裝,建議大家用Linux。
支持GPU和CPU?運行,我使用的是3090顯卡、CUDA11.1、Pytorch1.8。
2. 運行
我們用官方提供的預(yù)訓(xùn)練模型對圖片做實例分割。
2.1 加載模型配置文件
from detectron2.config import get_cfg
from detectron2 import model_zoo
cfg = get_cfg()
model_cfg_file = model_zoo.get_config_file('COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml')
cfg.merge_from_file(model_cfg_file)
COCO-InstanceSegmentation?代表用coco?數(shù)據(jù)集訓(xùn)練的實例分割模型。
mask_rcnn_R_50_FPN_3x.yaml是模型訓(xùn)練用到的配置信息。
從下圖也可以看到,detectron2?除了提供實例分割?模型,還提供目標檢測、關(guān)鍵點檢測等模型,還是比較全面的。
2.2 加載模型
model_weight_url = model_zoo.get_checkpoint_url('COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml')
cfg.MODEL.WEIGHTS = model_weight_url
mask_rcnn_R_50_FPN_3x.yaml?文件中存放了預(yù)訓(xùn)練模型的url?。當進行實例分割?時,程序會自動從url處將模型下載到本地。存放的位置為:
但程序自動下載的方式可能會比較慢,這時候你可以用迅雷自己下載模型文件,放到對應(yīng)的路徑中即可。
2.3 實例分割
首先,讀取一張圖片,圖片大小480 * 640。
img = cv2.imread('./000000439715.jpg')
實例化DefaultPredictor對象。
from detectron2.engine import DefaultPredictor
predictor = DefaultPredictor(cfg)
對圖片進行實例分割
out = predictor(img)
out?變量中存放的是分割出來每個目標的類別id、檢測框和目標遮罩。
out["instances"].pred_classes?獲取目標的類別id
這里一共檢測到了 15 個目標,在配置文件中可以找到類別id和類別名稱?的映射關(guān)系。其中,0?代表人,17代表馬。
out["instances"].pred_masks?獲取目標的遮罩?,我們?nèi)蝹€目標的遮罩研究一下它的用處。
可以看到,它的取值是布爾類型,并且shape和圖片大小一樣。
所以,遮罩是實例分割?的結(jié)果,里面每個元素對應(yīng)圖片一個像素,取值為True代表該像素是檢測出來的目標像素。
因此,我們可以通過遮罩給目標加上一層不透明度,從而把目標精確標注出來。
img_copy = img.copy()
alpha = 0.8
color = np.array([0, 255, 0])
img_copy[mask > 0, :] = img_copy[mask > 0, :] * alpha + color * (1-alpha)
上述給目標加上一層綠色的不透明度,效果如下:
可以看到,騎在馬上的人已經(jīng)被標注出來了。
3. 自動合成背景
有了上面的基礎(chǔ),我們就很容易合成視頻了。
讀取原視頻每一幀中將人物分割出來,將分割出來的人物直接覆蓋到新背景視頻中對應(yīng)的幀即可。
核心代碼:
# 讀取原視頻
ret, frame_src = cap.read()
# 讀取新背景視頻
ret, frame_bg = cap_bg.read()
# 調(diào)整背景尺寸跟原視頻一樣
frame_bg = cv2.resize(frame_bg, sz)
# 分割原視頻人物
person_mask = instance_seg.predict(frame_src)
# 合成
frame_bg[person_mask, :] = frame_src[person_mask, :]