利用百度 PaddlePaddle 平台的 PaddleHub 工具实现一键抠图,结合 opencv 等工具进行视频合成创作。
本视频为2.0版本,相比于第一版,自认为还是有所提升的。。。。。
1.0版本链接如下:
AI人像抠图及视频合成:让你体验复仇者联盟的终局之战
全套代码:
# 首先安装所需的包
# pip install paddlehub==1.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
# pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple
# 这里指定从清华源下载,速度快
import cv2
from PIL import Image
import numpy as np
import os
import paddlehub as hub
from moviepy.editor import *
# 从视频提取图片
def video2img(video_path, out_path):
cap = cv2.VideoCapture(video_path)
i=1
while True:
ret, frame = cap.read()
if frame is None:
break
else:
cv2.imwrite(out_path + str(i) + ".jpg", frame)
i+=1
return
# 抠图
def img2seg(img_path, out_path):
# load model
module = hub.Module(name="deeplabv3p_xception65_humanseg")
# config
test_img_path = [os.path.join(img_path, f_name) for f_name in os.listdir(img_path)]
input_dict = {"image": test_img_path}
results = module.segmentation(data=input_dict, output_dir=out_path)
# 合成图片
def blend_images(fore_image, base_image, out_path, img_num):
# def blend_images(fore_image, base_image):
"""
将抠出的人物图像换背景
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))
f_name = str(img_num) + ".jpg"
res_image.save(os.path.join(out_path, f_name))
# 把图片合成视频
def img2video(img_path, org_video_path, out_path):
# 查看原始视频的参数
cap = cv2.VideoCapture(org_video_path)
ret, frame = cap.read()
height = frame.shape[0]
width = frame.shape[1]
fps = cap.get(cv2.CAP_PROP_FPS) # 返回视频的fps--帧率
# 把参数用到我们要创建的视频上
video = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc('m', 'p', '4', 'v'), fps, (width, height)) # 创建视频流对象
"""
参数1 即将保存的文件路径
参数2 VideoWriter_fourcc为视频编解码器 cv2.VideoWriter_fourcc('m', 'p', '4', 'v') 文件名后缀为.mp4
参数3 为帧播放速率
参数4 (width,height)为视频帧大小
"""
# 获取图片总数
file_list = os.listdir(img_path)
img_num = len(file_list)
for i in range(img_num):
f_name = str(i + 1) + '.jpg'
item = os.path.join(img_path, f_name)
img = cv2.imread(item) # 使用opencv读取图像,直接返回numpy.ndarray 对象,通道顺序为BGR ,注意是BGR,通道值默认范围0-255。
video.write(img) # 把图片写进视频
video.release() # 释放
# 从原始视频上提取声音合成到新生成的视频上
def sound2video(org_video_path, new_video_path, out_video_path):
# 读取原始视频
video_o = VideoFileClip(org_video_path)
# 获取原始视频的音频部分
audio_o = video_o.audio
# 读取新生成视频
video_clip = VideoFileClip(new_video_path)
# 指向新生成视频的音频部分
video_clip2 = video_clip.set_audio(audio_o)
# 修改音频部分并输出最终视频
video_clip2.write_videofile(out_video_path)
# Config
# 人物视频地址
human_video_path = './a.mp4'
# 背景视频地址
back_video_path = './b.mp4'
# 提取人物视频图像的存放地址
human_video_img_path = './human_video_img/'
# 提取背景视频图片的存放地址
back_video_img_path = './back_video_img/'
# 抠图后存放地址
human_img_seg_path = './human_img_seg/'
# 人物和背景合成后图片存放地址
blend_img_path = './blend_img/'
# 合成视频存放地址
img2video_path = './c.mp4'
# 添加声音后的视频最终输出地址
out_video_path = './d.mp4'
if __name__ == "__main__":
# 第一步:人物视频->人物图像
if not os.path.exists(human_video_img_path):
os.mkdir(human_video_img_path)
video2img(video_path=human_video_path, out_path=human_video_img_path)
# 第二步:抠图
if not os.path.exists(human_img_seg_path):
os.mkdir(human_img_seg_path)
img2seg(img_path=human_video_img_path, out_path=human_img_seg_path)
# 第三步:背景视频->背景图片
if not os.path.exists(back_video_img_path):
os.mkdir(back_video_img_path)
video2img(video_path=back_video_path, out_path=back_video_img_path)
# 第四步:抠图+背景图片->合成
if not os.path.exists(blend_img_path):
os.mkdir(blend_img_path)
# 由于人物视频长度和背景视频长度可能不同,所以要以短的为准
if len(os.listdir(human_img_seg_path)) < len(os.listdir(back_video_img_path)):
img_num = len(os.listdir(human_img_seg_path))
else:
img_num = len(os.listdir(back_video_img_path))
# 对所有图片按顺序合成
for i in range(img_num):
blend_images(base_image=back_video_img_path+str(i+1)+'.jpg', fore_image=human_img_seg_path+str(i+1)+'.png',
out_path=blend_img_path, img_num=i+1)
# 第五步:合成视频
if not os.path.exists(img2video_path):
img2video(img_path=blend_img_path, org_video_path=human_video_path, out_path=img2video_path)
else:
print('视频已存在,请查看输出路径')
# 第六步:加上音频
if not os.path.exists(out_video_path):
sound2video(org_video_path=human_video_path, new_video_path=img2video_path, out_video_path=out_video_path)
else:
print('最终视频已存在,请查看输出路径')
成果展示:
Bilibili 的视频合成地址:
基于百度PaddleHub实现一键抠图+视频合成(附代码)
欢迎留言交流!
转载:https://blog.csdn.net/qq_42067550/article/details/105457679
查看评论