簡單用Python就能實現電影特效


一、前言

 

我們先看看能實現什麼效果,先來個正常版的,先看看原場景:
下面是我們切換場景後的樣子:

看起來效果還是不錯的,有了這個我們就可以隨意切換場景,墳頭蹦迪不是夢。另外,我們再來看看另外一種效果,相比之下要狂放許多:

二、實現步驟


 視頻是有一幀一幀的畫面組成的,每一幀都是一張圖片,我們要實現對視頻的修改就需要對視屏中每一幀畫面進行修改。所以在最開始,我們需要獲取視頻每一幀畫面。

具體步驟如下:

讀取視頻,獲取每一幀畫面
批量摳圖
讀取場景圖片
對每一幀畫面進行場景切換
寫入視頻
讀取原視頻的音頻
給新視頻設置音頻
因爲上面的步驟還是比較耗時的,所以我在視頻完成後通過郵箱發送通知,告訴我視頻製作完成。

三、模塊安裝


我們需要使用到的模塊主要有如下幾個:

pillow
opencv
moviepy
paddlehub


其中OpenCV建議選取3.0以上版本。

在我們使用paddlehub之前,我們需要安裝paddlepaddle:具體安裝步驟可以參見大佬教你,Python用5行代碼實現批量摳

我們直接用pip安裝cpu版本的:

# 安裝paddlepaddle
python -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple
# 安裝paddlehub
pip install -i https://mirror.baidu.com/pypi/simple paddlehub


有了這些準備工作就可以開始我們功能的實現了。

四、具體實現


直接附全碼:

import cv2
import math
import numpy as np
from PIL import Image
import paddlehub as hub
from moviepy.editor import *

#將視頻逐幀保存爲圖片
def getFrame(video_name, 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

#對幀圖片進行批量摳圖
def getHumanseg(frames):
    humanseg = hub.Module(name='deeplabv3p_xception65_humanseg')
    files = [frames + i for i in os.listdir(frames)]
    humanseg.segmentation(data={'image': files})  # 摳圖

def setGreenBg(humanseg):
    """
    給摳好的圖設置綠幕
    :param humanseg: 摳好的png圖片
    :return: 返回圖片的ndarray對象
    """
    im = Image.open(humanseg).convert('RGBA')
    # 遍歷圖片的每個像素
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            r, g, b, a = im.getpixel((i, j))
            if a == 0:
                im.putpixel((i, j), (0, 255, 0, 0))
    im = im.convert('RGB')
    im_array = np.array(im)
    im_array = im_array[:, :, ::-1]
    return im_array
def readBg(bgname, size):
    """
    讀取背景圖片,並修改尺寸
    :param bgname: 背景圖片名稱
    :param size: 視頻分辨率
    :return: Image對象
    """
    im = Image.open(bgname)
    return im.resize(size)
#將摳好的圖和背景圖片合併
def setImageBg(humanseg, bg_im):
    # 讀取透明圖片
    im = Image.open(humanseg)
    # 分離色道
    r, g, b, a = im.split()

    # 將合成圖轉換成RGB,這樣A通道就沒了
    #bg_im = bg_im.copy()#少了這一步的話,生成“千手觀音效果”
    bg_im.paste(im, (0, 0), mask=a)
    return np.array(bg_im.convert('RGB'))[:, :, ::-1]

def writeVideo(humanseg, bg_im, fps, size):
    """
    :param frames: 幀的路徑
    :param bgname: 背景圖片
    :param fps: 幀率
    :param size: 分辨率
    :return:
    """
    # 寫入視頻
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter('green.mp4', fourcc, fps, size)

    # 將每一幀設置背景
    files = [humanseg + i for i in os.listdir(humanseg)]
    for file in files:
        im_array = setImageBg(file, bg_im)
        out.write(im_array)
    out.release()
#獲取指定視頻的音頻
def getMusic(video_name):
    """
    :param video_name:
    :return:
    """
    # 讀取視頻文件
    video = VideoFileClip(video_name)
    # 返回音頻
    return video.audio
#實現混流,給video_name添加音頻
def addMusic(video_name, audio):
    # 讀取視頻
    video = VideoFileClip(video_name)
    # 設置視頻的音頻
    video = video.set_audio(audio)
    # 保存新的視頻文件
    video.write_videofile(output_video)
"""刪除過渡文件"""
def deleteTransitionalFiles():
    frames = [frame_path + i for i in os.listdir(frame_path)]
    humansegs = [humanseg_path + i for i in os.listdir(humanseg_path)]
    for frame in frames:
        os.remove(frame)
    for humanseg in humansegs:
        os.remove(humanseg)
def changeVideoScene(video_name, bgname):
    """
    :param video_name: 視頻的文件
    :param bgname: 背景圖片
    :return:
    """
    # 讀取視頻中每一幀畫面
    fps, size = getFrame(video_name, frame_path)
    # 批量摳圖
    getHumanseg(frame_path)
    # 讀取背景圖片
    bg_im = readBg(bgname, size)
    # 將畫面一幀幀寫入視頻
    writeVideo(humanseg_path, bg_im, fps, size)
    # 混流
    addMusic('green.mp4', getMusic(video_name))
    # 刪除過渡文件
    #deleteTransitionalFiles()
if __name__ == '__main__':
    # 當前項目根目錄
    BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "."))
    # 每一幀畫面保存的地址
    frame_path = BASE_DIR + '\\frames\\'
    # 摳好的圖片位置
    humanseg_path = BASE_DIR + '\\humanseg_output\\'
    # 最終視頻的保存路徑
    output_video = BASE_DIR + '\\result2.mp4'

    if not os.path.exists(frame_path):
        os.makedirs(frame_path)
    changeVideoScene('155小分隊.mp4', 'ba.jpg')
    
    


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章