首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python带你剪辑视频

python带你剪辑视频

作者头像
赵云龙龙
发布2020-08-13 16:07:47
2.6K0
发布2020-08-13 16:07:47
举报

嗯,好久没写文章了。因为最近没有熬夜了,天天背电脑也很辛苦。 工作嘛,手工为主,没有啥技术成长,也没啥好写的。 疫情期间,总听到有人叹气,总听到抖音里面“我太难了”。

特别是高铁,地铁里面,那种抖音小视频里面的大声傻笑,让我反感。 我不喜欢抖音,发现里面的有价值有营养的东西太少。都是无聊的人,发无聊的东西,给无聊的人打发无聊的时间。然后收割一波流量。整个网络充斥着太多的垃圾,以及垃圾信息。

其实要自己原创,做个走心的视频真的很难。如果up主坚持原创有意义的视频,我还是双手赞成。

自己最近也不务正业,天天看小视频,看多了,都看麻木了。

我自己也尝试搞视频,用手工亲历亲为,好累,特别费时间。何不用自动化来实现呢?

有的时候,自己拍摄的一些视频,用一些免费的视频剪接软件,它会加水印,或者广告。 有的时候,没有素材,在网上下载一些素材,也会有水印,或者不喜欢它的背景音乐,可以自己弄出来。

主要是利用 moviepy 这个库, 里面提供了丰富的功能, 我们只需要使用简单的拼接函数。

视频剪辑过程中,Python 一些比较实用的技能,帮助我们更快地进行短视频的创作。 安装 moviepy 命令行执行:

pip install moviepy

1、提取背景音乐和修改音量

下载视频文件,利用 moviepy 依赖库就可以提取到背景音乐。

def get_audio_from_video(video_path): 
    """
    从视频中提取音频
    :param video:
    :return:
    """ 
    file_path = './source/' + gene_random() + '.wav' 
    video = VideoFileClip(video_path)
    audio = video.audio
    audio.write_audiofile(file_path)
    return file_path

一个短视频中,可能包含多个背景音乐,需要对背景音乐的音量进行调整。

def handle_bgm(bgm_path, coefficient): 
    music = AudioFileClip(bgm_path)
 
   # 音量调整为原来音量的倍数
   out_music = music.fx(afx.volumex, coefficient).fx(afx.audio_fadein, 0.5).fx(
        afx.audio_fadeout, 1)
 
   # 保存背景音乐
   out_music.write_audiofile('./source/output.wav')

2、变声

变声也是视频创作中比较实用的一个技能,有三种方式可以实现。 使用 AU 做变调处理,修改调用百度云 API,使用 librosa 依赖库。这里主要讲第三种方法

import librosa
 
source = "./source/source.wav" 
 
# 加载背景音乐
y, sr = librosa.load(source)
 
# 修改
librosa.effects.pitch_shift(y, sr, n_steps=6)
y = shrinkstep(10, y, sr)
 
# 生成新的背景音乐文件
outputpath = "./source/result.wav" 
librosa.output.write_wav(outputpath, y, sr)

3、视频转场

视频间加入转场使视频播放更加流畅,Python 通过下面 7 个步骤实现视频转场。

分离 2 段视频的视频 Clip、音频 Clip 统一视频的分辨率 分别对视频的开头和结尾加入转场效果,比如淡入淡出效果 合并 2 段视频 合并 2 段音频 设置音频文件 保存视频文件

def transitions_animation(path_video1, path_video2): 
    """
    两段视频中转场动画(以淡入淡出为例)
    注意:保证视频拍摄帧率一致
    :param video1:
    :param video2:
    :return:
    """ 
    # 获取视频时长
    clip_video1 = VideoFileClip(path_video1)
    duration_video1 = clip_video1.duration
 
    # 获取视频音频
    path_audio1 = get_audio_from_video(path_video1)
    path_audio2 = get_audio_from_video(path_video2)
 
    audio_video1 = AudioFileClip(path_audio1)
    audio_video2 = AudioFileClip(path_audio2)
 
    clip_video2 = VideoFileClip(path_video2)
    duration_video2 = clip_video2.duration
 
    print(f'两段视频的时长分别为:{duration_video1},{duration_video2}')
 
    # 统一视频分辨率
    w, h, fps = clip_video1.w, clip_video1.h, clip_video1.fps
    clip_video2_new = clip_video2.resize((w, h))
 
    # 转场时长,默认2s
    transitions_time = 2 
 
    # 第一段视频执行淡出效果
    subVideo1_part1 = clip_video1.subclip(0, duration_video1 - 2)
    subVideo1_part2 = clip_video1.subclip(duration_video1 - 2).fadeout(2, (1, 1, 1))
 
    # 第二段视频执行淡入效果
    subVideo2_part1 = clip_video2_new.subclip(0, 3).fadein(3, (1, 1, 1))
    subVideo2_part2 = clip_video2_new.subclip(3)
 
    # 合并4段视频
    result_video = concatenate_videoclips([subVideo1_part1, subVideo1_part2, subVideo2_part1, subVideo2_part2])
 
    # 合并音频
    result_audio = concatenate_audioclips([audio_video1, audio_video2])
 
    # 视频设置音频文件
    final_clip = result_video.set_audio(result_audio)
     
    # pass 写入视频文件

4、坡度变速

为了使视频更加酷炫,很多后期高手都会对视频进行了坡度变速操作,使得原本枯燥无味的视频变得生动很多。当然你可以用视频编辑软件做,如果你熟悉的话,如果批量来做,可以用代码 常用的方式是:先慢速播放,然后恢复正常速度,中间加过渡音效。

def change_video_speed(video_path, speed, start, end): 
    """
    改变视频的速度
    [MoviePy clip相关的重要api](https://juejin.im/post/5d1c4318f265da1ba9159912)
    :param video_path:视频路径
    :param speed:速度
    :param start:开始时间
    :param end:结束时间
    :return:
    """ 
    video = VideoFileClip(video_path)
 
    # 速度变换
    part1 = video.fl_time(lambda t: speed * t, apply_to=['mask', 'video', 'audio']).set_start(start).set_end(
        end / speed)
 
    # 余下时长恢复速度
    part2 = video.subclip(end)
 
    # 合成视频
    result_video = concatenate_videoclips([part1, part2])
 
    result_path = './source/result.mp4' 
    result_video.write_videofile(result_path)

5、鬼畜视频

鬼畜视频来源于 B 站,在抖音上很多搞笑类视频剪辑都会使用到鬼畜处理,包含:画面帧重复、画面坐标轴映射等。

使用 Python 实现鬼畜视频也很简单。

def ghost_video(video_path, repeat_time, location): 
    """
    生成鬼畜视频
    :param video_path: 视频路径
    :param repeat_time: 重复次数
    :param location: 处理位置
    :return:
    """ 
    video = VideoFileClip(video_path)
 
    # 视频前部分
    part1 = video.subclip(0, location)
 
    # 视频目标部分,进行重复操作
    target = video.subclip(location, location + 1)
 
    # 视频后部分
    part2 = video.subclip(location + repeat_time)
 
    targets = []
 
    # 分别加入 3 个部分
    targets.append(part1)
 
    for _ in range(repeat_time):
        targets.append(target)
 
    targets.append(part2)
 
    # 合成、生成视频
    pass 

6、字幕水印

有的时候为了防盗版,可以加水印,利用 ImageClip 和 TextClip 可以很方便的加入图片水印和视频字幕。

# 加入图片水印
# 包含:水印的时长、位置、透明度等
logo = (ImageClip("./source/logo.png")
            .set_duration(video.duration)
            .resize(height=50)
            .margin(right=8, top=8, opacity=1)
            .set_pos(("right", "top")))
 
final = CompositeVideoClip([video, logo])
 
# 加入文字字幕
clip = VideoFileClip(video_path)
 
# 字幕,文字内容、位置、展示时长
texpClip = TextClip(subtitle, fontsize=30, color='white').set_pos('bottom').set_duration(duration)
 
video = CompositeVideoClip([clip,texpClip.set_start(start)])

7、转码

需要说明的是,如果使用 AE 制作动画视频,最后的视频文件会非常大,使用ffmpeg 依赖库可以快速进行转码和压缩文件。

# 快速转码压缩
alias zh='ffmpeg -i source.mov -qscale 0 output.mp4' 

8、说点其他的

以上介绍的操作基本上囊括了视频剪辑创作中大部分内容,其他操作可以点击原文链接查看官方文档。

我们也可以通过 moviepy和 opencv进行视频剪辑,先分别安装两个模块:

pip install opencv-python
pip install moviepy

9、视频剪辑 我们看看使用 moviepy 如何剪辑视频:

from moviepy.editor import *
# 剪切视屏bws.mp4中第50秒到第60秒
clip = VideoFileClip('bws.mp4').subclip(50, 60)
# 将剪切的片段保存
clip.write_videofile("clip.mp4")

9.2、提取音频文件 在 VideoFileClip 类中,音频文件作为其中的一个参数,我们可以直接获取:

from moviepy.editor import *
# 读取视频文件
video = VideoFileClip('bws.mp4')
# 获取其中音频
audio = video.audio
# 保存音频文件
audio.write_audiofile('audio.mp3')

9.3、混流 我们还可以将音频同视频混流,在moviepy中,提供了一个读取音频文件的类,我们设置视频的音频需要创建这个类的对象:

from moviepy.editor import *
# 读取视频
video = VideoFileClip('bws.mp4')
# 读取音频
audio = AudioFileClip('百年孤独.mp3')
# 设置视频的音频
video = video.set_audio(audio)
# 保存新的视频文件
video.write_videofile('bws_audio.mp4')

9.4、逐帧提取画面 我们都知道,视频是由一帧一帧的图片组成的,我们也可以将画面一帧一帧提取出来:

import cv2
# 读取视频
video = cv2.VideoCapture('bws.mp4')
# 逐帧读取,当还有画面时ret为True,frame为当前帧的ndarray对象
ret, frame = video.read()
i = 0
# 循环读取
while ret:
    i += 1
    cv2.imwrite('v'+str(i) + '.jpg', frame)
    ret, frame = video.read()

上述代码就能将视屏的每一帧以图片的形式保存下来。

9.5、截取gif 截取gif和截取视频没有什么区别,不过为了减少gif的大小,我们通常会对视频进行尺寸缩放:

from moviepy.editor import *
# 读取视频
video = VideoFileClip('bws.mp4')
# 裁剪视频,并缩小一半
video = video.subclip(20, 30).resize((0.5))
# 保存gif图片
video.write_gif('bws.gif')

在上面subclip方法中,我们可以传入元组,例如:

video.subclip((1, 20), (2, 30)) 其含义为从1分20秒截取到2分30秒

给视频加水印:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import moviepy.editor as mp

video = mp.VideoFileClip("video.mp4")

logo = (mp.ImageClip("baoqing.jpg")
        .set_duration(video.duration) # 水印持续时间
        .resize(height=100) # 水印的高度,会等比缩放
        #.margin(right=8, top=8, opacity=1) # 水印边距和透明度
        .set_pos(("left","top"))) # 水印的位置

final = mp.CompositeVideoClip([video, logo])
# mp4文件默认用libx264编码, 比特率单位bps
final.write_videofile("test.mp4", codec="libx264", bitrate="10000000")

第一步:导入moviepy 模块
第二步:实例化对象
第三步:载入水印logo,并设置属性
第四步:合成影像
第五步:写入新的video

我们常用这个来操作视频的声音: 提取声音

from moviepy.editor import *
avifilename=""
mp3filename=""
video =VideoFileClip(avifilename)
video.audio.write_audiofile(mp3filename)

删除声音:

from moviepy.editor import *
avifilename=""
mp3filename=""
video =VideoFileClip(avifilename)
# delete audio
video=video.without_audio()
video.write_videofile(mp3filename)

有的时候,如果需要视频拼接,就可以这样写:

from moviepy.editor import *
import os

# 定义一个数组
L = []

# 访问 video 文件夹 (假设视频都放在这里面)
for root, dirs, files in os.walk("./video"):
    # 按文件名排序
    files.sort()
    # 遍历所有文件
    for file in files:
        # 如果后缀名为 .mp4
        if os.path.splitext(file)[1] == '.mp4':
            # 拼接成完整路径
            filePath = os.path.join(root, file)
            # 载入视频
            video = VideoFileClip(filePath)
            # 添加到数组
            L.append(video)

# 拼接视频
final_clip = concatenate_videoclips(L)

# 生成目标视频文件
final_clip.to_videofile("./target.mp4", fps=24, remove_temp=False)

如果用视频编辑软件,例如爱剪辑剪过的视频,有普遍的特征,也就是他的片头由6s的展示片段。片尾有6.5s的展示片段。我们需要的就是把前6s和后6.5s的时间视频减掉。

moviepy中的相关方法 视频时间获取

clip.duration #这个就是视频的时间

视频剪辑

clip=VideoFileClip(文件名).subclip(开始时间,结束时间)

具体代码为:

from moviepy.editor import VideoFileClip
import os
import sys
import argparse
import pathlib

def get_file_times(filename):
       u"""
       获取视频时长(s:秒)
       """
       clip = VideoFileClip(filename)
       return clip.duration

def video_process(filename):
 u"""
     剪辑的区间在6到视频的总时长-6.5
       """
     clip=VideoFileClip(filename).subclip(6,int(get_file_times(filename))-6.5)
     file_name=os.path.splitext(filename)[0] #获取文件名(不带后缀)
     clip.write_videofile(file_name+"_fuck.mp4") #将文件变成文件名+fuck格式

def check_dir(path):
   u"""
   用来判断是文件,还是文件夹的方法
       """
    my_path=pathlib.Path(path)
    ex = my_path.exists()
    if ex:
        is_dir = my_path.is_dir()
        is_file = my_path.is_file()
    else:
        is_dir=False
        is_file=False
    return ex,is_dir,is_file

def fuck_dir(filepath):
           u"""
                文件夹的处理方法
       """
    pathDir =  os.listdir(filepath)
    for allDir in pathDir:
        filepath = os.path.abspath(filepath)
        child = os.path.join('%s/%s' % (filepath, allDir))
        file_format=os.path.splitext(child)[1]
        if file_format == ".mp4":
            print(child)
            video_process(child)

def fuck_file(path):
   u"""
    文件的处理方法
       """
    print("fuck from file")
    filepath = os.path.abspath(path)
    file_format=os.path.splitext(filepath)[1]
    if file_format == ".mp4":
        video_process(path)
    pass

parse=argparse.ArgumentParser(description="fuck ajj") #解析命令行参数
parse.add_argument("-i","--input",type=str,help="video item")
args = parse.parse_args()
video_item=args.input
ex,is_dir,is_file=check_dir(video_item)
print(ex,is_dir,is_file)
if not ex:
    print("the file is not exist!!!!!!\nPlease reinput")
else:
    if is_dir:
       fuck_dir(video_item)
    elif is_file:
        fuck_file(video_item)

如果需要改变MD5的值,截取一部分宽度,写了个代码:

from moviepy.editor import *
import hashlib
import os

threads =8
start_h=0
end_h=60
file_path=r'C:\work\auto'

def crop_file(filename,filebak):
    clip= VideoFileClip(filename).fx(vfx.crop,start_h,end_h)
    print(clip.h,clip.w)
    #clip.crop(y1=(clip.h)/9)
    clip.write_videofile(filebak,threads=threads)

def get_file_md5_2(file_path):
    """
    分段读取,获取文件的md5值
    :param file_path:
    :return:
    """
    with open(file_path, 'rb') as file:
        md5_obj = hashlib.md5()
        while True:
            buffer = file.read(8096)
            if not buffer:
                break
            md5_obj.update(buffer)
        hash_code = md5_obj.hexdigest()
    md5 = str(hash_code).lower()
    return md5


def solve_video():
    if os.listdir(file_path):
        for file in os.listdir(file_path):

            file_name= os.path.join(file_path,file)
            if os.path.isfile(file_name):
                print("start to solve the file {}".format(file_name))
                file_bak_name = file.split(".")[0]+"bak"+"."+file.split(".")[1]
                file_bak=os.path.join(file_path,file_bak_name)
                crop_file(file_name,file_bak)
                get_file_md5_2(file_bak)


if __name__ == '__main__':
    solve_video()

当你发现别人的视频很不错,想截取其中一段时,可以下载下来。 小技巧,如果用360浏览器,装上一个叫猫爪的插件,下视频那速度,飞一般地感觉。 用IDM也可以,不过只有几天免费。 如果要下载B站地视频,可以将路径放入这个工具里,就很方便下载了。 https://xbeibeix.com/api/bilibili/ 当然你也可以自动化实现。

当然你可以将声音,转化成字幕,或者调用翻译接口,翻译。然后再合成进去。字幕可以用网易建外。 如果要加音频,可以将文字朗读出来,下篇再讲。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python粉丝团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档