Python实现高级电影特效,CXK也能影分身

一、前言
前几天写了个实现特效的博客,感觉有点差强人意,只是简简单单的换背景应用场景不是非常多,今天就来实现一个更加复杂的特效“影分身”。下面有请我们本场的主演,坤制作人为我们表演他拿手的鸡你太美。

关于实现原理,和上一篇没有本质区别,同样是逐帧处理,但是这里还是详细说一下。
光理论是不够的,在此送大家一套2020最新Python全栈项目视频教程,点击此处 进来获取 跟着练习下,希望大家一起进步哦!

二、实现原理
首先我们要准备一个视频,作为我们的素材。然后我们要逐帧提取视频中的图像,接下来我们利用paddlehub逐帧抠取人像。这样就有了我们的主体,和分身了。最后我们需要在写入视频的时候对图像进行处理,我直接在原图像上粘贴了两个人物分身,最后合成的视频效果就是上面的效果了。当然我们还需要添加音频,所以最后我们需要读取音频并将新视频同音频混流。我们将整个过程分为以下几个步骤:

逐帧提取图像
批量抠图
合成图像(影分身)
写入视频
读取音频
混流
最终我们就能实现一个完整的视频了。

三、模块安装
为了方便,我们全都使用pip安装:

pip install pillow
pip install opencv-python
pip install moviepy
# 安装paddlepaddle
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
# 安装paddlehub
pip install -i https://mirror.baidu.com/pypi/simple paddlehub
1
2
3
4
5
6
7
也就不废话了,如果安装过程中出了什么问题可以自行百度或者联系博主,我会尽量解答的,毕竟我也只是个菜鸡。

四、代码实现
我们先看看导入的一些模块:

import cv2
import math
import numpy as np
from PIL import Image
import paddlehub as hub
from moviepy.editor import *
1
2
3
4
5
6
我们按照上面的步骤,一步一步来。

4.1、逐帧提取图像
这就需要使用到我们的opencv了,具体代码如下:

def getFrame(video_name, save_path):
    """
    传入视频名称,将图像帧保存到save_path下
    """
    # 读取视频
    video = cv2.VideoCapture(video_name)

    # 获取视频帧率
    fps = video.get(cv2.CAP_PROP_FPS)
    # 获取画面大小
    width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
    size = (width, height)

    # 获取帧数
    frame_num = str(video.get(7))
    name = int(math.pow(10, len(frame_num)))
    ret, frame = video.read()
    while ret:
        cv2.imwrite(save_path + str(name) + '.jpg', frame)
        ret, frame = video.read()
        name += 1
    video.release()
    return fps, size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
这里我们只需要注意OpenCV版本需要在3.0以上,如果是低版本的话会出现兼容问题。

4.2、批量抠图
批量抠图需要使用到我们的paddhub模型库,而抠图的实现也只需要几行代码:

def getHumanseg(frames):
    """
    对frames路径下所以图片进行抠图
    """
    # 加载模型库
    humanseg = hub.Module(name='deeplabv3p_xception65_humanseg')
    # 遍历路径下文件
    files = [frames + i for i in os.listdir(frames)]
    # 抠图
    humanseg.segmentation(data={'image': files})
1
2
3
4
5
6
7
8
9
10
我们调用该方法后会在目录下生成humanseg_output目录,抠好的图像就在里面。

4.3、合成图像(影分身)
这里需要使用到我们的Pillow模块,该模块中提供了图像粘贴的函数:

def setImageBg(humanseg, bg_im):
    """
    将抠好的图和背景图片合并
    :param humanseg:
    :param bg_im:
    :return:
    """
    # 读取透明图片
    im = Image.open(humanseg)
    # 分离色道
    r, g, b, a = im.split()
    # 在图片右边粘贴一个人物分身
    bg_im.paste(im, (bg_im.size[0]//3, 0), mask=a)
    # 在图片左边粘贴一个人物分身
    bg_im.paste(im, (-bg_im.size[0]//3, 0), mask=a)
    # 将图形转换成opencv能正常读取的类型,并返回
    return np.array(bg_im.convert('RGB'))[:, :, ::-1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上面主要就是使用paste函数。

4.4、写入视频
写入视频的操作同样是OpenCV来实现的:

def writeVideo(humanseg_path, frames, fps, size):
    """
    传入抠好的人像,和原图像,以及原视频帧率,大小,写入新视频
    """
    # 写入视频
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter('green.mp4', fourcc, fps, size)

    # 将每一帧设置背景
    humanseg = [humanseg_path + i for i in os.listdir(humanseg_path)]
    frames = [frames + i for i in os.listdir(frames)]
    for i in range(humanseg.__len__()):
        # 读取原图像
        bg_im = Image.open(frames[i])
        # 设置分身
        im_array = setImageBg(humanseg[i], bg_im)
        # 写入视频
        out.write(im_array)
    out.release()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
到这里我们就实现了一个视频,但是现在还没有声音,接下来就需要我们用moviepy进行音频的混流了。

4.5、混流
我们混流的操作就是先获取音频,然后再混流,而音频我们只需要读取原视频的音频即可:

def getMusic(video_name):
    """
    获取指定视频的音频
    """
    # 读取视频文件
    video = VideoFileClip(video_name)
    # 返回音频
    return video.audio
1
2
3
4
5
6
7
8
其中VideoFileClip是moviepy中的一个视频处理的类。下面我们来添加音乐:

def addMusic(video_name, audio):
    """实现混流,给video_name添加音频"""
    # 读取视频
    video = VideoFileClip(video_name)
    # 设置视频的音频
    video = video.set_audio(audio)
    # 保存新的视频文件
    video.write_videofile(output_video)
1
2
3
4
5
6
7
8
output_video是我们自己定义的一个存放文件保存路径的变量,需要注意,该全路径(路径+名称)不能和原视频相同。

4.6、实现特效
也就是将整个流程整合到一起:

def changeVideoScene(video_name):
    """
    :param video_name: 视频的文件
    :param bgname: 背景图片
    :return:
    """

    # 读取视频中每一帧画面
    fps, size = getFrame(video_name, frames)

    # 批量抠图
    getHumanseg(frames)

    # 将画面一帧帧写入视频
    writeVideo(humanseg_path, frames, fps, size)

    # 混流
    addMusic('green.mp4', getMusic(video_name))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在上面有些变量我们还没有定义,我们在main函数中定义一下:

if __name__ == '__main__':

    # 当前项目根目录
    BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "."))
    # 每一帧画面保存的地址
    frames = BASE_DIR + '\\frames\\'
    # 抠好的图片位置
    humanseg_path = BASE_DIR + '\\humanseg_output\\'
    # 最终视频的保存路径
    output_video = BASE_DIR + '\\result.mp4'

    # 创建文件夹
    if not os.path.exists(frames):
        os.makedirs(frames)
    if not os.path.exists(background_path):
        os.makedirs(background_path)
    # 给视频添加特效
       changeVideoScene('jntm.mp4')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
最后送大家一套2020最新Pyhon项目实战视频教
————————————————
版权声明:本文为CSDN博主「ZackSock」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ZackSock/article/details/105702717

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值