在上一篇文章中,我們介紹了用深度學(xué)習(xí)結(jié)合攝像機(jī)的方法自動(dòng)檢測(cè)并拍攝小鳥(niǎo)的照片。今天,我們用另一種新穎的深度學(xué)習(xí)模型——Mask R-CNN,自動(dòng)從視頻中制作目標(biāo)物體的GIF動(dòng)圖。
Mask R-CNN已經(jīng)有很多應(yīng)用了,論智君此前還介紹過(guò)Facebook利用這一模型實(shí)現(xiàn)全身AR的項(xiàng)目。不過(guò)在這個(gè)項(xiàng)目中,作者Kirk Kaiser使用的是MatterPort版本。它支持Python 3,擁有超棒的樣本代碼,也許是最容易安裝的版本了。
第一步,輸入正確的內(nèi)容
在開(kāi)始制作gif自動(dòng)生成器時(shí),我選擇先做一件最蠢的事,這種模式在有創(chuàng)意性編碼項(xiàng)目中表現(xiàn)得很好。
首先,輸入的視頻中只能含有一個(gè)人,不要嘗試跟蹤監(jiān)測(cè)視頻中的多個(gè)人。這樣我們就可以將目標(biāo)物體與其他對(duì)象隔離開(kāi),同時(shí)更容易評(píng)估模型掩蓋目標(biāo)對(duì)象的程度如何。如果目標(biāo)對(duì)象不見(jiàn)了,我們就能發(fā)現(xiàn),同時(shí)還能看到模型識(shí)別邊框的噪聲。
我選用的是自己在后院拍攝的視頻。
用Python處理視頻
盡管用Python處理視頻有其他方法,但我更喜歡將視頻轉(zhuǎn)換為圖像序列,然后再使用ffmpeg將其轉(zhuǎn)換回來(lái)。
使用以下命令,我們就能從輸入的視頻中獲取一系列圖像。根據(jù)輸入的視頻來(lái)源,它可能在每秒24到60幀之間。你需要跟蹤每秒輸入的視頻幀數(shù),以便在轉(zhuǎn)換后保持同步。
$ ffmpeg -i FILENAME.mp4 -qscale:v 2 %05d.jpg
這將創(chuàng)建一個(gè)5位、0填充的圖像序列,如果您輸入的視頻長(zhǎng)度超過(guò)5位,則可以將%05d改成%09d。
數(shù)字序列將與視頻持續(xù)的時(shí)間一樣長(zhǎng)(以秒為單位),乘以每秒的幀數(shù)。所以一個(gè)時(shí)長(zhǎng)為三秒、每秒24幀的視頻,將有72幀。
由此,我們得到了一系列靜止的圖像,可以使用我們的靜態(tài)掩碼R-CNN代碼輸入。
完成了對(duì)圖像的處理后,稍后將使用以下命令把它們重新放回視頻中:
$ ffmpeg -r 60 -f image2 -i %05d.jpg OUTPUT.mp4
參數(shù)-r規(guī)定了每秒中我們需要使用構(gòu)建輸出視頻的幀數(shù)。如果我們想放慢視頻,可以降低參數(shù)的值,如果想加快速度,可以增加參數(shù)的值。
按照順序,讓我們先用Mask R-CNN來(lái)檢測(cè)并處理圖像。
檢測(cè)并標(biāo)記圖像
Matterport版的Mask R-CNN附帶了Jupyter Notebook,幫助深入了解Mask R-CNN的工作原理。
一旦你在本地設(shè)置好了repo,我建議在demo筆記本上運(yùn)行,并評(píng)估圖像檢測(cè)工作的水平。
通常掩碼是無(wú)符號(hào)的8位整數(shù),形狀與輸入的圖像一致。當(dāng)沒(méi)有檢測(cè)到目標(biāo)對(duì)象時(shí),掩碼是0或者黑色。當(dāng)檢測(cè)到對(duì)象時(shí),掩碼是255或白色。
為了處理蒙版,我們需要把它作為一個(gè)通道,復(fù)制或粘貼另一張圖像。用類似下面的代碼,可以從每個(gè)視頻的圖像中將單個(gè)人物摳出來(lái),生成一張透明底的圖像:
import numpy as np
import os
import coco
import model as modellib
import glob
import imageio
import cv2
# Root directory to project
ROOT_DIR = os.getcwd()
# Directory to save logs and trained model
MODEL_DIR = os.path.join(ROOT_DIR, "logs")
# Path to trained weights file
# Download this file and place in the root of your
# project (See README file for details)
COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5")
classInferenceConfig(coco.CocoConfig):
# Set batch size to 1 since we'll be running inference on
# one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU
GPU_COUNT = 1
IMAGES_PER_GPU = 1
config = InferenceConfig()
# Create model object in inference mode.
model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=config)
# Load weights trained on MS-COCO
model.load_weights(COCO_MODEL_PATH, by_name=True)
class_names = ['BG', 'person', 'bicycle', 'car', 'motorcycle', 'airplane',
'bus', 'train', 'truck', 'boat', 'traffic light',
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird',
'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear',
'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie',
'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
'kite', 'baseball bat', 'baseball glove', 'skateboard',
'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup',
'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed',
'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote',
'keyboard', 'cell phone', 'microwave', 'oven', 'toaster',
'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors',
'teddy bear', 'hair drier', 'toothbrush']
numFiles = len(glob.glob('extractGif/*.jpg'))
counter = 0
for i in range(1, numFiles):
filename = 'extractGif/%05d.jpg' % i
print("doing frame %s" % filename)
frame = cv2.imread(filename)
results = model.detect([frame], verbose=0)
r = results[0]
masky = np.zeros((frame.shape[0], frame.shape[1]), dtype='uint8')
humans = []
if r['rois'].shape[0] >= 1:
for b in range(r['rois'].shape[0]):
if r['class_ids'][b] == class_names.index('person'):
masky += r['masks'][:,:,b] * 255
humansM = r['masks'][:,:,b] * 255
y1, x1, y2, x2 = r['rois'][b]
humansCut = frame[y1:y2, x1:x2]
humansCut = cv2.cvtColor(humansCut.astype(np.uint8), cv2.COLOR_BGR2RGBA)
humansCut[:,:,3] = humansM[y1:y2, x1:x2]
humans.append(humansCut)
if len(humans) >= 1:
counter += 1
for j, human in enumerate(humans):
fileout = 'giffer%i/%05d.png' % (j, counter)
ifnot os.path.exists('giffer%i' % j):
os.makedirs('giffer%i' % j)
print(fileout)
#frame = cv2.cvtColor(frame.astype('uint8'), cv2.COLOR_BGRA2BGR)
imageio.imwrite(fileout, human)
其中的class_names變量非常重要,它表示我們用COCO數(shù)據(jù)集分出的不同事物的類別。然后只需要把列表中的任意類別的名字更換成if r[class_ids][b] == class_names.index(‘person’),你就可以從視頻中獲取帶有蒙版的版本了。
把圖片轉(zhuǎn)換成GIF
現(xiàn)在我們有了一組透明圖像,可以打開(kāi)看看它們的效果。我的結(jié)果并不是很好,人物摳的不是很精致,不過(guò)也挺有趣的。
然后我們就可以將圖像輸入進(jìn)ffmpeg中制作動(dòng)圖了,只需要找到圖像序列的最大寬度(width)和高度(height),然后將其粘貼到一個(gè)新的圖像序列中:
import glob
from PIL importImage
maxW = 0
maxH = 0
DIRECTORY = 'wave-input'
numFiles = len(glob.glob(DIRECTORY + '/*.png'))
for num in range(numFiles - 1):
im = Image.open(DIRECTORY + '/%05d.png' % (num + 1))
if im.width > maxW:
maxW = im.width
if im.height > maxH:
maxH = im.height
for num in range(numFiles - 1):
each_image = Image.new("RGBA", (maxW, maxH))
im = Image.open(DIRECTORY + '/%05d.png' % (num + 1))
each_image.paste(im, (0,0))
each_image.save('gifready/%05d.png' % num)
上面的代碼打開(kāi)了我們的giffer0這個(gè)目錄,并在所有圖像中迭代,尋找最大尺寸圖像的width和height。然后它將這些圖像都放到一個(gè)新目錄(gifready)中,我們就能將其生成gif。
在這里,我們利用Imagemagick生成gif:
$ convert -dispose Background *.png outty.gif
但是僅僅從視頻中自動(dòng)生成動(dòng)圖也沒(méi)什么好激動(dòng)的,讓我們繼續(xù)把它們混合起來(lái),看看會(huì)發(fā)生什么……
在Pygame或視頻中應(yīng)用生成的GIFs
最近,我直接將這些提取的圖像用在了Pygame中。我并沒(méi)有將它們轉(zhuǎn)換成gifs,而是保留了原始PNG格式。
我自創(chuàng)了一個(gè)創(chuàng)意性小編程環(huán)境,其中包括一個(gè)setup和draw功能,將圖像序列作為輸入。使用這個(gè)設(shè)置,我可以將圖像旋轉(zhuǎn)、縮放或干擾它們。以下是代碼:
import pygame
import random
import time
import math
import os
import glob
imageseq = []
def setup(screen, etc):
global imageseq
numIn = len(glob.glob('wave-input/*.png'))
for i in range(numIn):
if os.path.exists('wave-input/%05d.png' % (i + 1)):
imagey = pygame.image.load('wave-input/%05d.png' % (i + 1)).convert_alpha()
imageseq.append(imagey)
counter = 1
def draw(screen, etc):
# our current animation loop frame
global counter
current0 = imageseq[counter % len(imageseq)]
counter += 1
for i in range(0, 1920, 200):
screen.blit(current0, (i, 1080 // 2 - 230))
它將每個(gè)目錄中的圖像加載到一個(gè)alphapygame.surface中。其中的每一個(gè)都被添加到列表中,然后我們可以在循環(huán)中blit或?qū)⒚繌垐D片畫(huà)到屏幕上。
這只是基本設(shè)置,更高級(jí)的操作請(qǐng)看上面的代碼,或者到我的GitHub中查看其他有趣的實(shí)驗(yàn)。
用提取的Mask修改輸入視頻
為了產(chǎn)生上圖的效果,我記錄了視頻的前n幀,以及人物(person)和滑板(skateboard)的位置。
然后我將把之前摳出來(lái)的圖一個(gè)一個(gè)疊好,最后粘貼最后一張圖像。
除此之外我還試著將我的蒙版和其他視頻混合起來(lái)。這里就是合成的一個(gè)案例:
同時(shí)調(diào)試環(huán)境和滑板者的每一幀,然后在環(huán)境上蓋上蒙版,覆蓋在滑板視頻的頂部。這個(gè)代碼也可以在我的GitHub里找到。
結(jié)語(yǔ)
想將深度學(xué)習(xí)與藝術(shù)結(jié)合,這種項(xiàng)目只是一個(gè)開(kāi)始。另外還有一個(gè)名為OpenPose的模型,能夠預(yù)測(cè)一個(gè)人的動(dòng)作,并且模型十分穩(wěn)定。我計(jì)劃將OpenPose合并到未來(lái)的項(xiàng)目中,創(chuàng)建更有趣的作品。
-
視頻
+關(guān)注
關(guān)注
6文章
1958瀏覽量
73167 -
python
+關(guān)注
關(guān)注
56文章
4809瀏覽量
85071 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5517瀏覽量
121601
原文標(biāo)題:用Mask R-CNN自動(dòng)創(chuàng)建動(dòng)圖
文章出處:【微信號(hào):jqr_AI,微信公眾號(hào):論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
深度卷積神經(jīng)網(wǎng)絡(luò)在目標(biāo)檢測(cè)中的進(jìn)展
![深度卷積神經(jīng)網(wǎng)絡(luò)在<b class='flag-5'>目標(biāo)</b>檢測(cè)<b class='flag-5'>中</b>的進(jìn)展](https://file1.elecfans.com//web2/M00/A6/E6/wKgZomUMQSSATF0xAABzUtc-31U758.png)
介紹目標(biāo)檢測(cè)工具Faster R-CNN,包括它的構(gòu)造及實(shí)現(xiàn)原理
![介紹<b class='flag-5'>目標(biāo)</b>檢測(cè)工具Faster <b class='flag-5'>R-CNN</b>,包括它的構(gòu)造及實(shí)現(xiàn)原理](https://file.elecfans.com/web1/M00/45/72/pIYBAFpr-EGAbkntAAAJYBXr1Dk609.png)
什么是Mask R-CNN?Mask R-CNN的工作原理
引入Mask R-CNN思想通過(guò)語(yǔ)義分割進(jìn)行任意形狀文本檢測(cè)與識(shí)別
手把手教你操作Faster R-CNN和Mask R-CNN
一種新的帶有不確定性的邊界框回歸損失,可用于學(xué)習(xí)更準(zhǔn)確的目標(biāo)定位
![一種新的帶有不確定性的邊界框回歸損失,可用于學(xué)習(xí)更準(zhǔn)確的<b class='flag-5'>目標(biāo)</b>定位](https://file.elecfans.com/web1/M00/8F/94/pIYBAFy-z0-AZYoUAAAJr01Obn4101.png)
基于MASK模型的視頻問(wèn)答機(jī)制設(shè)計(jì)方案
![基于<b class='flag-5'>MASK</b>模型的<b class='flag-5'>視頻</b>問(wèn)答機(jī)制設(shè)計(jì)方案](https://file.elecfans.com/web1/M00/E4/E7/pIYBAGBJwCuAczA4AAGGXhsIh-Y587.png)
基于改進(jìn)Faster R-CNN的目標(biāo)檢測(cè)方法
![基于改進(jìn)Faster <b class='flag-5'>R-CNN</b>的<b class='flag-5'>目標(biāo)</b>檢測(cè)方法](https://file.elecfans.com/web1/M00/E6/CD/pIYBAGBZkOuAHA8JAAIGNFDuYus265.png)
用MATLAB制作GIF格式動(dòng)圖資料下載
![用MATLAB<b class='flag-5'>制作</b><b class='flag-5'>GIF</b>格式<b class='flag-5'>動(dòng)</b><b class='flag-5'>圖</b>資料下載](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
一種基于Mask R-CNN的人臉檢測(cè)及分割方法
![一種基于<b class='flag-5'>Mask</b> <b class='flag-5'>R-CNN</b>的人臉檢測(cè)及分割方法](https://file.elecfans.com/web1/M00/E8/BB/pIYBAGBlM5uAWH5-AAHRX5rrBh8066.png)
基于Mask R-CNN的遙感圖像處理技術(shù)綜述
用于實(shí)例分割的Mask R-CNN框架
PyTorch教程14.8之基于區(qū)域的CNN(R-CNN)
![PyTorch教程14.8之基于區(qū)域的<b class='flag-5'>CNN</b>(<b class='flag-5'>R-CNN</b>)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評(píng)論