全网首创Python算法自动剪辑视频,影视剧解说第一版
用 AI 托管量产原创电影解说视频?没错可以的。
当下自媒体账号中有大部分都是影视剧解说的内容,如果看的多了你会发现很多内容情节讲解的都大同小异,本身影视剧翻来覆去就那么点东西,我就琢磨了下这些能不能用Python直接一键生成这种解说视频。
答案是可以的,我尝试的做了几个发在我的抖音账号上。
目前版本是1.0版本功能有限,未来会继续在更新算法的基础上更新脚本。这里介绍大体的制作思路和方法和原创你们想要问的问题。
既然正儿八经的讲技术没人看那么就做这么一个号试试吧。
软硬件、技能需求
CPU最好是I7-8750以上,要不整体制作会非常慢
Python版本3.6以上
Moviepy模块暂时不支持GPU,因此显卡好坏无视
需要会写爬虫,抓视频素材。
需要掌握常规的文章洗稿方法,不然视频内容没法做
需要掌握常规的window系统操作,否则剪映某些操作无法完成
需要会操作Moviepy模块,不会的看我专栏里的对应介绍和操作方法
需要1-N个手机号,用于申请百度AI的免费API使用
需要有耐心
数据获取
这里的数据获取分两部分
能自己找到完整的电影素材,mkv格式最佳,mp4也能凑合用。比如去某些程序员论坛,这里影片都是质量非常高的原片而且无水印。不要问打马赛克的地方,老司机都懂的。
能自己写爬虫脚本抓取别人的电影解说视频,并去水印等等。这个对于一些程序员新手来说略有难度。比如说抖音吧抓取的视频,文章的水印你无视哈。
基础素材准备
这个对于之前《月产10000个中药科普短视频方法,Python编程AI教程》制作的需求素材相对于简单一些。
做一个片头,一个水印就行了。
流程与代码
了解业务处理制作流程有助于理解代码,或者流程了解了代码就很容易。
先看一下整体的工程目录,然后一步一步说。
基础数据应用部分
就是把你抓取的原影视剧文件或者解说视频下载到 source_video 下名称随意,只放1个,系统会自动识别名称。
配置时间和毫秒的转换方法,挺简单的玩python的都会,不会的自己对照着敲一遍。
必须手动的部分
就是剪辑到原来的片头,比如说电影这种无用无法配解说的镜头,其实就掐头去尾就行。
用moviepy剪切测试一下。
test_start_time = 5.7
test_end_time = 200
# 手动测试片头从对应时间切分
video_base = VideoFileClip("source_video/" + video)
video_base = video_base.subclip(test_start_time,test_end_time)
video_base.write_videofile("temp_data/cut_start.mp4")
设置画面截取的范围,有的电影或者视频是带黑边的要剪掉。
# 使用系统自带画图功能选择截取的坐标点
x1,y1 = 0,120 # 裁剪区域左上角坐标
x2,y2 = 1920,960 # 裁剪区域右下角坐标
width,height = None,None # 宽度和高度
x_center,y_center = None,None # X、Y轴中心点坐标
# 剔除上下黑边选取影响范围
video_base = VideoFileClip("temp_data/cut_start.mp4")
video_base = (video_base.fx(vfx.crop,x1,y1,x2,y2)).resize((1920, 1080))
video_base.write_videofile("temp_data/cut_frames.mp4")
然后按照像素框裁剪掉你需要的整个影片,并重置画面像素大小。
# 计算开始和截至时间
start_time = 200 # 这里根据影片开头的时间设置
video_base = VideoFileClip("source_video/" + video) # 手动测试片头从对应时间切分
end_time = video_base.duration
# 手动测试片头从对应时间切分
video_base = VideoFileClip("source_video/" + video)
# 按照测测试号的时间进行截取
video_base = video_base.subclip(test_start_time,end_time)
# 剔除视频无用部分
video_base = (video_base.fx(vfx.crop,x1,y1,x2,y2)).resize((1920, 1080))
video_base.write_videofile("temp_data/"+ video)
字幕处理方法
为了省钱用免费的剪映自动识别字幕,视频扔进去自动识别。如果有钱用科大讯飞或者百度的也行。最终效果是一样的,而且可以使用一些算法自动提取正文内容的摘要,方法百度上都有自己问。
字幕导出是剪映对应目录下的这个文件 draft_content.json 。
用代码解析一下就好生成时间轴数据列表用于后续的编辑。
黄色部分用于洗稿用的,就是按照你的理解编辑对应片段就行了,将做好的excel表格放到 temp_mp3 下。
文稿匹配拆分方案2,拆分时间进行进行文稿重塑
这里要注意的是影片你要自己先看过一遍,否则你都不知道里面演的是什么,可能后期做字幕会很尴尬。就是有选择的选择稿件中的文字信息,也可以根据自己的理解改写。
写好的稿子之后再执行生成合成语音方案
如果视频太长了稿子太长可以进行切分分成几个部分,每个部分限制字数使用each_str 实现。
# 文稿处理完毕后读取进行稿件拼接
df = pd.read_excel("temp_mp3/文稿2.xlsx")
df.dropna(axis=0,inplace=True)
df.reset_index(drop=True,inplace=True)
strs = ""
for i in range(len(df)):
strs = strs + df["new_content"][i] + "\n"
with open("temp_mp3/文稿2_new.txt",'w',encoding='utf-8') as f:
f.write(strs)
# 使用新的数据重复方案1的步骤生成新的稿子
# 文稿2_new == 文稿1
with open("temp_mp3/文稿2_new.txt",encoding='utf-8') as f:
txt_data = f.read()
# 将文稿2.xlsx数据格式转换成文稿2.txt按行读取
data_list=df[["time_str_1","time_str_2","new_content"]].values.tolist()
# 单个文稿设置文字总长度
each_str = 2500
# 最终文稿超出字数会新建文档看情况自己调配
匹配文稿语音合成
用API吧,如果自己有把握稿子不会念错自己念录制也行。
根据之前做好的excel表格把影片中无用的部分剪切掉
剪切的标准是时间点,就是excel表格中设置的时间点,有字幕解说的部分要,无字幕解说的部分直接砍掉,例如下面红色框的部分。根据这个时间节点会自动进行拼接。
生成的音频文件合并
这里要注意的是你制作的片段部分如果想和字幕对上需要进行一个加速。要么视频加速要么音频加速,如果是用moviepy的话用视频加速,因为音频加速会有些走掉。如果是用mmpeg合成就无所谓了。
加速的公式合成代码。
# 读取MP3配音文件
audio = AudioFileClip("temp_mp3/"+ file_name +"/all.mp3")
# 记录MP3的时间
audio_time = audio.duration
# 读取MP4视频文件
video = VideoFileClip("temp_mp4/"+ file_name +".mp4")
# 记录MP4的时间
video_time = video.duration
# 给视频进行加速 配合音频文件的字幕
factor = video_time/audio_time # 倍速播放倍数,视频时间/音频时间就是视频加速的时间
final_duration = None # 倍速播放持续时间 ,可以为空表使全部
video = video.fx(vfx.speedx, factor , final_duration)
最后直接等待结果的视频出来之后稍微手动加工一下就可以发自媒体啦。
伪原创的谣言
这个怎么说呢只有你试过了才知道不行。网上有很多方法还有卖各种软件的,我只能告诉你这个是教智商税,你买了以后完全没效果。
网上卖的软件能买么?
比如某地方卖的这个工具,这里面除了神经网络所有的功能都用moviepy能实现,不可信。
至于你会问神经网络去重?这玩意是用GPU跑的,你的机器没有配置对应的开发环境是执行不起来的。用过的人都知道CPU和GPU处理的视频时间比大概是20比1的样子。
这种能公开出来的人家平台就会不知道么?很容易被破解的。只能自己去慢慢尝试方法,然后自己用就是了。
毕竟好用能用的东西没人会拿出来卖的。
修改MD5?
代码其实很简单直接可以一步出结果,但是你能想到字节的工程师就想不到么?
def get_file_md5(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 modify_file_md5(file_path):
"""
修改文件的md5值
:param file_path:
:return:
"""
with open(file_path, 'a') as file:
file.write("####&&&&")