日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python合并视频和音频_真没想到,Python 还能实现 5 毛特效

發(fā)布時間:2024/7/23 python 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python合并视频和音频_真没想到,Python 还能实现 5 毛特效 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 | ZackSock

來源 | ZackSock(ID:ZackSock)

Python牛已經(jīng)不是一天兩天的事了,但是我開始也沒想到,Python能這么牛。前段時間接觸了一個批量摳圖的模型庫,而后在一些視頻中找到靈感,覺得應(yīng)該可以通過摳圖的方式,給視頻換一個不同的場景,于是就有了今天的文章。

我們先看看能實現(xiàn)什么效果,先來個正常版的,先看看原場景:

下面是我們切換場景后的樣子:

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

實現(xiàn)步驟

我們都知道,視頻是由一幀一幀的畫面組成的,每一幀都是一張圖片,我們要實現(xiàn)對視頻的修改就需要對視頻中每一幀畫面進(jìn)行修改。所以在最開始,我們需要獲取視頻每一幀畫面。

在我們獲取幀之后,需要摳取畫面中的人物。

摳取人物之后,就需要讀取我們的場景圖片了,在上面的例子中背景都是靜態(tài)的,所以我們只需要讀取一次場景。在讀取場景之后我們切換每一幀畫面的場景,并寫入新的視頻。

這時候我們只是生成了一個視頻,我們還需要添加音頻。而音頻就是我們的原視頻中的音頻,我們讀取音頻,并給新視頻設(shè)置音頻就好了。

具體步驟如下:

  • 讀取視頻,獲取每一幀畫面
  • 批量摳圖
  • 讀取場景圖片
  • 對每一幀畫面進(jìn)行場景切換
  • 寫入視頻
  • 讀取原視頻的音頻
  • 給新視頻設(shè)置音頻
  • 因為上面的步驟還是比較耗時的,所以在視頻完成后通過郵箱發(fā)送通知,告訴我視頻制作完成。

    模塊安裝

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

    pillow
    opencv
    moviepy
    paddlehub

    我們都可以直接用pip安裝:

    pip install pillow
    pip install opencv-python
    pip install moviepy

    其中OpenCV有一些適配問題,建議選取3.0以上版本。

    在我們使用paddlehub之前,我們需要安裝paddlepaddle:具體安裝步驟可以參見官網(wǎng)。用paddlehub摳圖參考:別再自己摳圖了,Python用5行代碼實現(xiàn)批量摳圖。我們這里直接用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

    有了這些準(zhǔn)備工作就可以開始我們功能的實現(xiàn)了。

    具體實現(xiàn)

    我們導(dǎo)入如下包:

    import cv2 # opencv
    import mail # 自定義包,用于發(fā)郵件
    import math
    import numpy as np
    from PIL import Image # pillow
    import paddlehub as hub
    from moviepy.editor import *

    其中Pillow和opencv導(dǎo)入的名稱不太一樣,還有就是我自定義的mail模塊。另外我們還要先準(zhǔn)備一些路徑:

    # 當(dāng)前項目根目錄,系統(tǒng)自動獲取當(dāng)前目錄
    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 + 'esult.mp4'

    接下來我們按照上面說的步驟一個一個實現(xiàn)。

    (1)讀取視頻,獲取每一幀畫面

    OpenCV中提供了讀取幀的函數(shù),我們只需要使用VideoCapture類讀取視頻,然后調(diào)用read函數(shù)讀取幀,read方法返回兩個參數(shù),ret為是否有下一幀,frame為當(dāng)前幀的ndarray對象。完整代碼如下:def getFrame(video_name, save_path):
    """
    讀取視頻將視頻逐幀保存為圖片,并返回視頻的分辨率size和幀率fps
    :param video_name: 視頻的名稱
    :param save_path: 保存的路徑
    :return: fps幀率,size分辨率
    """
    # 讀取視頻
    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)
    # ?獲取幀數(shù),用于給圖片命名
    frame_num = str(video.get(7))
    name = int(math.pow(10, len(frame_num)))
    # 讀取幀,ret為是否還有下一幀,frame為當(dāng)前幀的ndarray對象
    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

    在標(biāo)?處,我獲取了幀的總數(shù),然后通過如下公式獲取比幀數(shù)大的整十整百的數(shù):

    frame_name = math.pow(10, len(frame_num))

    這樣做是為了讓畫面逐幀排序,這樣讀取的時候就不會亂。另外我們獲取了視頻的幀率和分辨率,這兩個參數(shù)在我們創(chuàng)建視頻時需要用到。這里需要注意的是opencv3.0以下版本獲取幀率和畫面大小的寫法有些許差別。

    (2)批量摳圖

    批量摳圖需要用到paddlehub中的模型庫,代碼很簡單,這里就不多說了:

    def getHumanseg(frames):
    """
    對幀圖片進(jìn)行批量摳圖
    :param frames: 幀的路徑
    :return:
    """
    # 加載模型庫
    humanseg = hub.Module(name='deeplabv3p_xception65_humanseg')
    # 準(zhǔn)備文件列表
    files = [frames + i for i in os.listdir(frames)]
    # 摳圖
    humanseg.segmentation(data={'image': files})

    我們執(zhí)行上面函數(shù)后會在項目下生成一個humanseg_output目錄,摳好的圖片就在里面。

    (3)讀取場景圖片

    這也是簡單的圖片讀取,我們使用pillow中的Image對象:

    def readBg(bgname, size):
    """
    讀取背景圖片,并修改尺寸
    :param bgname: 背景圖片名稱
    :param size: 視頻分辨率
    :return: Image對象
    """
    im = Image.open(bgname)
    return im.resize(size)

    這里的返回的對象并非ndarray對象,而是Pillow中定義的類對象。

    (4)對每一幀畫面進(jìn)行場景切換

    簡單來說就是將摳好的圖片和背景圖片合并,我們知道摳好的圖片都在humanseg_output目錄,這也就是為什么最開始要準(zhǔn)備相應(yīng)的變量存儲該目錄的原因:

    def setImageBg(humanseg, bg_im):
    """
    將摳好的圖和背景圖片合并
    :param humanseg: 摳好的圖
    :param bg_im: 背景圖片,這里和readBg函數(shù)返回的類型一樣
    :return: 合成圖的ndarray對象
    """
    # 讀取透明圖片
    im = Image.open(humanseg)
    # 分離色道
    r, g, b, a = im.split
    # ?復(fù)制背景,以免源背景被修改
    bg_im = bg_im.copy
    # 合并圖片
    bg_im.paste(im, (0, 0), mask=a)
    return np.array(bg_im.convert('RGB'))[:, :, ::-1]

    在標(biāo)?處,我們復(fù)制了背景,如果少了這一步的話,生成的就是我們上面的“千手觀音效果”了。

    其它步驟都很好理解,只有返回值比較長,我們來詳細(xì)看一下:

    # 將合成圖轉(zhuǎn)換成RGB,這樣A通道就沒了
    bg_im = bg_im.convert('RGB')
    # 將Image對象轉(zhuǎn)換成ndarray對象,方便opencv讀取
    im_array = np.array(bg_im)
    # 此時im_array為rgb模式,而OpenCV為bgr模式,我們通過下面語句將rgb轉(zhuǎn)換成bgr
    bgr_im_array = im_array[:, :, ::-1]

    最后bgr_im_array就是我們最終的返回結(jié)果。

    (5)寫入視頻

    為了節(jié)約空間,我并非等將寫入圖片放在合并場景后面,而是邊合并場景邊寫入視頻:

    def writeVideo(humanseg, bg_im, fps, size):
    """
    :param humanseg: png圖片的路徑
    :param bgname: 背景圖片
    :param fps: 幀率
    :param size: 分辨率
    :return:
    """
    # 寫入視頻
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter('green.mp4', fourcc, fps, size)
    # 將每一幀設(shè)置背景
    files = [humanseg + i for i in os.listdir(humanseg)]
    for file in files:
    # 循環(huán)合并圖片
    im_array = setImageBg(file, bg_im)
    # 逐幀寫入視頻
    out.write(im_array)
    out.release

    上面的代碼也非常簡單,執(zhí)行完成后項目下會生成一個green.mp4,這是一個沒有音頻的視頻,后面就需要我們獲取音頻然后混流了。

    (6)讀取原視頻的音頻

    因為在opencv中沒找到音頻相關(guān)的處理,所以選用moviepy,使用起來也非常方便:

    def getMusic(video_name):
    """
    獲取指定視頻的音頻
    :param video_name: 視頻名稱
    :return: 音頻對象
    """
    # 讀取視頻文件
    video = VideoFileClip(video_name)
    # 返回音頻
    return video.audio

    然后就是混流了。

    (7)給新視頻設(shè)置音頻

    這里同樣使用moviepy,傳入視頻名稱和音頻對象進(jìn)行混流:

    def addMusic(video_name, audio):
    """實現(xiàn)混流,給video_name添加音頻"""
    # 讀取視頻
    video = VideoFileClip(video_name)
    # 設(shè)置視頻的音頻
    video = video.set_audio(audio)
    # 保存新的視頻文件
    video.write_videofile(output_video)

    其中output_video是我們在最開始定義的變量。

    (8)刪除過渡文件

    在我們生產(chǎn)視頻時,會產(chǎn)生許多過渡文件,在視頻合成后我們將它們刪除:

    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)

    最后就是將整個流程整合一下。

    (8)整合

    我們將上面完整的流程合并成一個函數(shù):

    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

    (9)在main中調(diào)用

    我們可以把前面定義的路徑也放進(jìn)了:

    if __name__ == '__main__':
    # 當(dāng)前項目根目錄
    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 + 'esult.mp4'
    if not os.path.exists(frame_path):
    os.makedirs(frame_path)
    try:
    # 調(diào)用函數(shù)制作視頻
    changeVideoScene('jljt.mp4', 'bg.jpg')
    # 當(dāng)制作完成發(fā)送郵箱
    mail.sendMail('你的視頻已經(jīng)制作完成')
    except Exception as e:
    # 當(dāng)發(fā)生錯誤,發(fā)送錯誤信息
    mail.sendMail('在制作過程中遇到了問題' + e.__str__)

    這樣我們就完成了完整的流程。

    發(fā)送郵件

    郵件的發(fā)送又是屬于另外的內(nèi)容了,我定義了一個mail.py文件,具體代碼如下:

    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart # 一封郵件
    def sendMail(msg):
    #
    sender = '發(fā)件人'
    to_list = [
    '收件人'
    ]
    subject = '視頻制作情況'
    # 創(chuàng)建郵箱
    em = MIMEMultipart
    em['subject'] = subject
    em['From'] = sender
    em['To'] = 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的python合并视频和音频_真没想到,Python 还能实现 5 毛特效的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。