嗯,好久没写文章了。因为最近没有熬夜了,天天背电脑也很辛苦。 工作嘛,手工为主,没有啥技术成长,也没啥好写的。 疫情期间,总听到有人叹气,总听到抖音里面“我太难了”。
特别是高铁,地铁里面,那种抖音小视频里面的大声傻笑,让我反感。 我不喜欢抖音,发现里面的有价值有营养的东西太少。都是无聊的人,发无聊的东西,给无聊的人打发无聊的时间。然后收割一波流量。整个网络充斥着太多的垃圾,以及垃圾信息。
其实要自己原创,做个走心的视频真的很难。如果up主坚持原创有意义的视频,我还是双手赞成。
自己最近也不务正业,天天看小视频,看多了,都看麻木了。
我自己也尝试搞视频,用手工亲历亲为,好累,特别费时间。何不用自动化来实现呢?
有的时候,自己拍摄的一些视频,用一些免费的视频剪接软件,它会加水印,或者广告。 有的时候,没有素材,在网上下载一些素材,也会有水印,或者不喜欢它的背景音乐,可以自己弄出来。
主要是利用 moviepy 这个库, 里面提供了丰富的功能, 我们只需要使用简单的拼接函数。
视频剪辑过程中,Python 一些比较实用的技能,帮助我们更快地进行短视频的创作。 安装 moviepy 命令行执行:
代码语言:javascript复制pip install moviepy
1、提取背景音乐和修改音量
下载视频文件,利用 moviepy 依赖库就可以提取到背景音乐。
代码语言:javascript复制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
一个短视频中,可能包含多个背景音乐,需要对背景音乐的音量进行调整。
代码语言:javascript复制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 依赖库。这里主要讲第三种方法
代码语言:javascript复制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 段音频 设置音频文件 保存视频文件
代码语言:javascript复制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、坡度变速
为了使视频更加酷炫,很多后期高手都会对视频进行了坡度变速操作,使得原本枯燥无味的视频变得生动很多。当然你可以用视频编辑软件做,如果你熟悉的话,如果批量来做,可以用代码 常用的方式是:先慢速播放,然后恢复正常速度,中间加过渡音效。
代码语言:javascript复制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 实现鬼畜视频也很简单。
代码语言:javascript复制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 可以很方便的加入图片水印和视频字幕。
代码语言:javascript复制# 加入图片水印
# 包含:水印的时长、位置、透明度等
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 依赖库可以快速进行转码和压缩文件。
代码语言:javascript复制# 快速转码压缩
alias zh='ffmpeg -i source.mov -qscale 0 output.mp4'
8、说点其他的
以上介绍的操作基本上囊括了视频剪辑创作中大部分内容,其他操作可以点击原文链接查看官方文档。
我们也可以通过 moviepy和 opencv进行视频剪辑,先分别安装两个模块:
代码语言:javascript复制pip install opencv-python
pip install moviepy
9、视频剪辑 我们看看使用 moviepy 如何剪辑视频:
代码语言:javascript复制from moviepy.editor import *
# 剪切视屏bws.mp4中第50秒到第60秒
clip = VideoFileClip('bws.mp4').subclip(50, 60)
# 将剪切的片段保存
clip.write_videofile("clip.mp4")
9.2、提取音频文件 在 VideoFileClip 类中,音频文件作为其中的一个参数,我们可以直接获取:
代码语言:javascript复制from moviepy.editor import *
# 读取视频文件
video = VideoFileClip('bws.mp4')
# 获取其中音频
audio = video.audio
# 保存音频文件
audio.write_audiofile('audio.mp3')
9.3、混流 我们还可以将音频同视频混流,在moviepy中,提供了一个读取音频文件的类,我们设置视频的音频需要创建这个类的对象:
代码语言:javascript复制from moviepy.editor import *
# 读取视频
video = VideoFileClip('bws.mp4')
# 读取音频
audio = AudioFileClip('百年孤独.mp3')
# 设置视频的音频
video = video.set_audio(audio)
# 保存新的视频文件
video.write_videofile('bws_audio.mp4')
9.4、逐帧提取画面 我们都知道,视频是由一帧一帧的图片组成的,我们也可以将画面一帧一帧提取出来:
代码语言:javascript复制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的大小,我们通常会对视频进行尺寸缩放:
代码语言:javascript复制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秒
给视频加水印:
代码语言:javascript复制#!/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
我们常用这个来操作视频的声音: 提取声音
代码语言:javascript复制from moviepy.editor import *
avifilename=""
mp3filename=""
video =VideoFileClip(avifilename)
video.audio.write_audiofile(mp3filename)
删除声音:
代码语言:javascript复制from moviepy.editor import *
avifilename=""
mp3filename=""
video =VideoFileClip(avifilename)
# delete audio
video=video.without_audio()
video.write_videofile(mp3filename)
有的时候,如果需要视频拼接,就可以这样写:
代码语言:javascript复制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中的相关方法 视频时间获取
代码语言:javascript复制clip.duration #这个就是视频的时间
视频剪辑
代码语言:javascript复制clip=VideoFileClip(文件名).subclip(开始时间,结束时间)
具体代码为:
代码语言:javascript复制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的值,截取一部分宽度,写了个代码:
代码语言:javascript复制from moviepy.editor import *
import hashlib
import os
threads =8
start_h=0
end_h=60
file_path=r'C:workauto'
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/ 当然你也可以自动化实现。
当然你可以将声音,转化成字幕,或者调用翻译接口,翻译。然后再合成进去。字幕可以用网易建外。 如果要加音频,可以将文字朗读出来,下篇再讲。