【谁说视频不能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))