我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!
【谁说视频不能P】之基于PaddleHub的100行代码P阿力木视频,顾名思义,就是通过简单的几行python代码实现P视频,比如最近的那个“疆域阿力木”视频背景切换。话不多说,下面就开干。
一、环境设置
话不多说,主要做以下工作。
1.安装依赖
pip安装嘛,主要有以下包需要安装。。。。。。
- 安装PaddePaddle-gpu (gpu快啊)
- 安装PaddleHub
- 其他依赖若干
2.引入包
import cv2
import os
import numpy as np
from PIL import Image
import paddlehub as hub
%set_env GPU_NUM=1
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
复制代码
二、视频切分转图片
主要是以下功能
- 从摄像头获取视频切分为图片帧
- 从视频文件获取视频切分为图片帧
def CutVideo2Image(video_path, img_path):
cap = cv2.VideoCapture(video_path)
index = 0
while(True):
ret,frame = cap.read()
if ret:
cv2.imwrite('video/frame/%d.jpg'%index, frame)
# img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# imgs.append(img_rgb)
index += 1
else:
break
cap.release()
print('Video cut finish, all %d frame' % index)
复制代码
三、人像抠图
很简单,直接调用paddlehub的deeplabv3p_xception65_humanseg人像抠图模块进行抠图。
def GetHumanSeg(in_path, out_path):
# load model
module = hub.Module(name="deeplabv3p_xception65_humanseg")
# config
frame_path = in_path
test_img_path = [os.path.join(frame_path, fname) for fname in os.listdir(frame_path)]
input_dict = {"image": test_img_path}
print('file len: %d'% len(test_img_path))
total_num = len(test_img_path)
loop_num = int(np.ceil(total_num / 10))
for iter_id in range(loop_num):
batch_data=list()
handle_id=iter_id *10
for image_id in range(10):
try:
batch_data.append(test_img_path[handle_id +image_id])
print(handle_id +image_id)
print(test_img_path[handle_id +image_id])
except:
pass
batch_input_dict={"image": batch_data}
results = module.segmentation(data=batch_input_dict, use_gpu=True, visualization=True, output_dir=out_path)
# del results
# del batch_input_dict
复制代码
四、人像背景替换
def BlendImg(fore_image, base_image, output_path):
"""
将抠出的人物图像换背景
fore_image: 前景图片,抠出的人物图片
base_image: 背景图片
"""
# 读入图片
base_image = Image.open(base_image).convert('RGB')
fore_image = Image.open(fore_image).resize(base_image.size)
# 图片加权合成
scope_map = np.array(fore_image)[:,:,-1] / 255
scope_map = scope_map[:,:,np.newaxis]
scope_map = np.repeat(scope_map, repeats=3, axis=2)
res_image = np.multiply(scope_map, np.array(fore_image)[:,:,:3]) + np.multiply((1-scope_map), np.array(base_image))
#保存图片
res_image = Image.fromarray(np.uint8(res_image))
res_image.save(output_path)
def BlendHumanImg(in_path, screen_path, out_path):
humanseg_png = [filename for filename in os.listdir(in_path)]
for i, img in enumerate(humanseg_png):
img_path = os.path.join(in_path + '%d.png' % (i))
output_path_img = out_path + '%d.png' % i
BlendImg(img_path, screen_path, output_path_img)
def init_canvas(width, height, color=(255, 255, 255)):
canvas = np.ones((height, width, 3), dtype="uint8")
canvas[:] = color
return canvas
def GetGreenScreen(width, height, out_path):
canvas = init_canvas(width, height, color=(0, 255, 0))
cv2.imwrite(out_path, canvas)
复制代码
五、合并还原视频
合并嘛,很简单不讲了。
def CombVideo(in_path, out_path, size):
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(out_path,fourcc, 30.0, size)
files = os.listdir(in_path)
for i in range(len(files)):
img = cv2.imread(in_path + '%d.png' % i)
# cv2.imshow("test", img)
# cv2.waitKey(0)
# img = cv2.resize(img, (1280,720))
out.write(img)#保存帧
out.release()
复制代码
六、运行
由于是jupyter写的,所以都是代码段,后续将进行优化整理。运行程序如下。
- 视频-图像转换
- 抠图
- 生成绿幕并合并
- 合并视频
# Config
Video_Path = 'video/2.mp4'
FrameCut_Path = 'video/frame/'
FrameSeg_Path = 'video/frame_seg/'
FrameCom_Path = 'video/frame_com/'
GreenScreen_Path = 'video/base_image.png'
ComOut_Path = 'output.mp4'
# 第一步:视频->图像
if not os.path.exists(FrameCut_Path):
os.mkdir(FrameCut_Path)
CutVideo2Image(Video_Path, FrameCut_Path)
# 第二步:抠图
if not os.path.exists(FrameSeg_Path):
os.mkdir(FrameSeg_Path)
GetHumanSeg(FrameCut_Path, FrameSeg_Path)
# 第三步:生成绿幕并合成
if not os.path.exists(GreenScreen_Path):
GetGreenScreen(720, 480, GreenScreen_Path)
if not os.path.exists(FrameCom_Path):
os.mkdir(FrameCom_Path)
BlendHumanImg(FrameSeg_Path, GreenScreen_Path, FrameCom_Path)
# 第四步:合成视频
if not os.path.exists(ComOut_Path):
CombVideo(FrameCom_Path, ComOut_Path, (720, 480))
复制代码
\