likes
comments
collection
share

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

作者站长头像
站长
· 阅读数 15

脚本三:视频处理及信息获取

前几章我们完成了基于Pytube的所有Youtube操作,包括频道轮询和影片下载,这个功能保证了我们Python自动化脚本已经能够守候在油管后台,对关注的频道进行第一时间的高清影片获取。按照我们第一篇中描述的流程,接下来,在发布到我们自己的自媒体平台之前,需要对视频本身做一些必要的处理,并提取一些视频的信息如封面帧,标题翻译等。前者是为了避免平台搬运监测(本篇只是浅测有效,具体还需要更多的扩展),后者是为发布到中文自媒体平台做资料准备。

1. 视频处理

视频处理的工具是在本系列第二篇文章里所介绍过的FFmpeg:《躺着就能涨粉?Python自动化短视频搬运(二)|合并影片》,在那篇文章里我们用FFmpeg完成了最基本的音频文件和视频文件的合并。本篇我们将继续深入使用FFmpeg执行更多的操作。

FFmpeg有大量的滤镜(filter)功能,只要输入合适的参数,就能得到经过滤镜处理的视频。在我的实际应用中,我主要用了锐化,对比度,亮度,缩放及裁剪等常用的滤镜,下面就一一来介绍:

使用滤镜的格式:

在介绍具体滤镜前,让我们先把FFmpeg针对多滤镜的命令框架搭一下,分享下我使用的命令:

ffmpeg -i <源文件> -filter_complex <滤镜列表> -c:v libx264 \
 -c:a copy -f mp4 <输出文件> -y

<源文件>:需要进行处理的原始视频文件 <滤镜列表>:下面会介绍 <输出文件>:经过滤镜处理完的视频文件

在此系列的第二篇《躺着就能涨粉?Python自动化短视频搬运(二)|合并影片》的实战例子中,我们有个油管下载和合成的现成视频文件:v1080p+audio.mp4,我们可以直接用它来做测试,并命令输出文件:v1080p+audio_output.mp4。

ffmpeg -i v1080p+audio.mp4 -filter_complex <滤镜列表> -c:v libx264 \
-c:a copy -f mp4 v1080p+audio_output.mp4 -y

<滤镜列表>的格式是 "filter1=para1, filter2=para2, filter3=para3, ..." (注意,双引号是必须的)

ffmpeg -i v1080p+audio.mp4 -filter_complex "filter1=para1, filter2=para2, \
filter3=para3, ..." -c:v libx264 -c:a copy -f mp4 v1080p+audio_output.mp4 -y

滤镜1: 锐化

因为毕竟是搬运来的视频,画面的给人的距离感还是挺远的,为了增加“亲切感”,一般我会使用锐化效果来让画面更锐利,细节可以更加容易的体现出来。

锐化的滤镜名称是unsharp(竟然是unsharp?),它的一般格式是unsharp=x:y:c,x和y是明亮度矩阵xy,默认是5*5,而c是“浓度”,默认值是1,快速应用的话,只修改c就能达到想要的目的。c的数字越大,画面越锐利,但随之而来的就是噪点的增加,所以要选择适中的参数,基于我的实战经验,对于国外下载的视频,使用5:5:2的效果比较好。

unsharp=5:5:2

我们在命令行下面尝试下组合好的锐化命令:

$ ffmpeg -i v1080p+audio.mp4 -filter_complex "unsharp=5:5:2" -c:v libx264 \
-c:a copy -f mp4 v1080p_audio_output.mp4 -y

耐心等待一段时间的FFmpeg处理log结束后,就可以在当前文件夹下找到v1080p+audio_output.mp4文件,播放该文件和源文件对比,能看到画面有比较明显的锐化效果,对清晰度有比较大的提升。

左图为锐化后,右图为原图:

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

滤镜2: 对比度和亮度

这个比较简单,参数格式是"eq=contrast=c:brightness=b..."其中,c是对比度值,1是不调整,>1是对比度加强,<1是对比度减弱,我目前使用的值是1.2。b是亮度值,0是不调整,>0是变亮,<0是变暗,我目前使用的值是0.1。另外,eq滤镜下还有不少其他的参数,如色温等,有需求完全可以自行添加。 我们在命令行下面尝试下组合好的对比度和亮度调整命令:

$ ffmpeg -i v1080p+audio.mp4 -filter_complex "eq=contrast=1.2:brightness=0.1" \
-c:v libx264 -c:a copy -f mp4 v1080p_audio_output.mp4 -y

耐心等待后,播放两个视频,查看区别。

左图为调整完对比度和亮度,右图为原图:

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

滤镜3:缩放和裁剪

缩放和裁剪在视频剪辑里非常常用,同样用FFmpeg也是非常地方便。首先看缩放滤镜,它的滤镜格式是scale=x:y,其中x是缩放后的x方向像素数目,y是缩放后的y方向像素数目,比如原视频的分辨率是1024*640,如果scale=1025:641就是指放大图像,scale=1023:639就是指缩小图像。如果想保持原视频的长宽比,可以把x或y的值设成-1,如scale=1280:-1。

在实际应用中,光把视频画面放大,提交到平台后往往还是会呈现出一样的大小,如果我们想要画面更大,通常需要在放大画面的同时配合裁剪,把画面裁切到原来一样的大小。裁剪的滤镜格式是crop=w:h:x:y,其中w是裁剪后的x像素数目,h是y像素数目,x是从原视频的左边开始第几个像素开始截取,y是在从原视频的上方开始第几个像素开始截取。

如我们想要一个1024*640的视频,并画面的左上角是从原视频的10*20位置开始裁剪:crop=1024:640:10:20。

现在我们尝试把测试视频略微放大,并裁减到原尺寸(原视频分辨率为1080*1920):

$ ffmpeg -i v1080p+audio.mp4 -filter_complex "scale=1180:-1, crop=1080:1920:150:100" \
-c:v libx264 -c:a copy -f mp4 v1080p_audio_output.mp4 -y

效果如下,左图为放大裁剪后的视频,右图为原视频:

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

合并滤镜

最后,我们把三组滤镜合并在一起,以一句FFmpeg执行以上所有操作:

$ ffmpeg -i v1080p+audio.mp4 -filter_complex "unsharp=5:5:2, \
                                              eq=contrast=1.2:brightness=0.1, \
                                              scale=1180:-1, crop=1080:1920:150:100" \
          -c:v libx264 -c:a copy -f mp4 v1080p_audio_output.mp4 -y

最后的执行效果,左图为滤镜后的视频,右图为原视频:

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

好了,这就是我们需要的待发布视频了。我们只要把这句FFmpeg命令加入到python代码里即可:

import os
os.system(f"ffmpeg -i {input_file} -filter_complex \"unsharp=5:5:2, \
                                              eq=contrast=1.2:brightness=0.1, \
                                              scale=1180:-1, crop=1080:1920:150:100\" \
          -c:v libx264 -c:a copy -f mp4 {output_file} -y")

2. 获取和编辑封面

由于发布到自媒体平台时,平台都会要求提供一张封面图用于展示使用,如果不主动提供,系统往往会默认使用第一帧或自动随机选一帧,这样一般展示效果不佳。建议我们自己可以主动从视频里获取一帧图片,作为封面图,在Youtube里,可以使用pytube调用接口得到原视频作者提供的封面,但是经过我的测试,这些图片分辨率都很低,没有办法下载到原图。所以我们还是使用强大的FFmpeg,从视频里“抽帧”。抽帧的细节就不介绍了,总的来说使用I帧比较保险,在自动化脚本里,就定义获取影片的第一个I帧作为封面图。抽I帧的命令如下:

ffmpeg -i {source_file} -vf "select=eq(pict_type\\,I)" \
           -vframes 1  -vsync vfr -qscale:v 2 -f image2 {output_file} -y

我们就用本章新创建的视频文件v1080p_audio_output.mp4做测试:

ffmpeg -i v1080p_audio_output.mp4 -vf "select=eq(pict_type\,I)" \
           -vframes 1  -vsync vfr -qscale:v 2 -f image2 v1080p_audio_output.jpeg -y

可以看到,我们得到了一张还不错的封面图。

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

同样,合并到python代码里:

os.system(f"ffmpeg -i {input_file} -vf \"select=eq(pict_type\\,I)\" \
           -vframes 1  -vsync vfr -qscale:v 2 -f image2 {output_file} -y")

光有封面图片还不够专业,一般的视频封面我们都会见到一些醒目的艺术字,来简要描述视频内容,达到吸睛的效果,当然这个python也是完全可以做到的。

封面图加字幕

编辑图片的功能,我们会同时使用opencv和pillow。这两个都是非常强大的图像处理第三方库,如果只是给画面添加文字,opencv足矣,不过我们需要对文字有些艺术化编辑,如边框高亮等,那就需要pillow比较强大的绘图功能。

首先,先下载安装这两个库,并加上计算库numpy:

$ pip install opencv-python
$ pip install pillow
$ pip install numpy

在代码里导入它们,主要导入模块名和库名并不相同:

import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image

我们可以用cv2把图片读取进来给PIL使用,我们接下来的操作都是基于draw对象来进行,在测试中我们就使用之前生成的现成文件v1080p_audio_output.jpeg:

img = cv2.imread("./v1080p_audio_output.jpeg")
imgpil = Image.fromarray(img)
draw = ImageDraw.Draw(imgpil)

draw.text()函数是pillow中用来给图片加字幕的方法,因为我们需要给字幕加彩色边框,所以需要一定的巧妙处理。我没有找到直接可以使用的边框接口,自己写了一个text_board函数,主要功能就是黄色的文字周边2个像素写一圈白色的相同文字,最后在效果上起到了边框的效果。(这里的实现不用太纠结,无脑抄代码即可)

def text_border(draw, text, x, y, font, shadowcolor, fillcolor):
    draw.text((x-2, y), text, font=font, fill=shadowcolor)
    draw.text((x+2, y), text, font=font, fill=shadowcolor)
    draw.text((x, y-2), text, font=font, fill=shadowcolor)
    draw.text((x, y+2), text, font=font, fill=shadowcolor)
    draw.text((x-2, y-2), text, font=font, fill=shadowcolor)
    draw.text((x+2, y-2), text, font=font, fill=shadowcolor)
    draw.text((x-2, y+2), text, font=font, fill=shadowcolor)
    draw.text((x+2, y+2), text, font=font, fill=shadowcolor)
    draw.text((x, y), text, font=font, fill=fillcolor)

接下来,我们需要设置一下字体,你可以从系统字体库或直接到网上下载免费的.ttf字体文件,存放到代码所在文件夹下。我使用的是汉仪笔染甜甜圈 W字体免费下载和在线预览-字体天下下载下来的HYBiRanTianTianQuanW-2.ttf,比较适合做封面字幕。有了字体文件,并设置字体大小80,我们就用pillow导入,生成font对象:

fontpath = "./HYBiRanTianTianQuanW-2.ttf"
fontsize = 80
font = ImageFont.truetype(fontpath, fontsize)

接着让我们来随意定义一段需要绘制的文字:

title = "一段不错的街头舞蹈!"

我们就可以调用text_border()绘制文字图像了,这段文字的起始位置在100*400,(0,0,0)为黄色字体,(0,255,255)为白色边框:

text_border(draw, title, 100, 400, font, (0,0,0), (0,255,255))

最后,把绘制完draw对象的impil,用numpy和cv2规整保存进v1080p_audio_output_with_title.jpeg文件里。

retext = np.array(imgpil)
cv2.imwrite("./v1080p_audio_output_with_title.jpeg", retext)

让我们来最终效果,挺醒目的!

躺着就能涨粉?Python自动化短视频搬运(五)|视频处理

3. 文字翻译

上文中描述了如何得到封面图和为该封面图添加标题,那这个文字本身从哪里来呢?当然你可以自定义或为每个视频都固定同一个标题,作为自动化脚本,更好的方式当然是获取到原版影片的标题。这里就涉及到第一篇中的内容《躺着就能涨粉?Python自动化短视频搬运(一)|下载影片》,通过Pytube获得youtube影片的title,这里快速把代码再复习一遍:

from pytube import YouTube
video = YouTube("https://www.youtube.com/watch?v=tO_L8bik10k")
title = video.title

由于是从国外网站下载的影片,它们都是英文标题,而在国内的视频平台上,英文标题很难吸引绝大多数人的关注,因此我们需要自动翻译成中文。这里推荐translators库,它能自动对接到指定翻译接口上进行自动的全文翻译。同样下载安装translators:

$ pip install translators

在代码中对title字符串进行外中翻译,这里我选择iciba接口,感觉对外译中把握得比较好,当然其他也都可以用。

import translators as ts
title_cn = ts.iciba(title, to_language='zh-CN')
print(title)
print(title_cn)

打印:

Los Angeles Clippers vs. Brooklyn Nets Full Game Highlights | Nov 12 | 2022-23 NBA Season
洛杉矶快船队vs。布鲁克林篮网队全比赛亮点|11月12日| 2022-23 NBA赛季

通过这一篇的介绍,我们成功生成了一张带有中文字幕的封面图,和这一段经过翻译的中文标题,供我们后面发布使用。接下来我们就可以向自己的视频账号进行搬运了。

进入下一篇: 《躺着就能涨粉?Python自动化短视频搬运(六)|自动发布》

返回上一篇: 《躺着就能涨粉?Python自动化短视频搬运(四)|多频道管理》

本篇用到的代码:

thumbnails.py

import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image

def text_border(draw, text, x, y, font, shadowcolor, fillcolor):
    draw.text((x-2, y), text, font=font, fill=shadowcolor)
    draw.text((x+2, y), text, font=font, fill=shadowcolor)
    draw.text((x, y-2), text, font=font, fill=shadowcolor)
    draw.text((x, y+2), text, font=font, fill=shadowcolor)
    draw.text((x-2, y-2), text, font=font, fill=shadowcolor)
    draw.text((x+2, y-2), text, font=font, fill=shadowcolor)
    draw.text((x-2, y+2), text, font=font, fill=shadowcolor)
    draw.text((x+2, y+2), text, font=font, fill=shadowcolor)
    draw.text((x, y), text, font=font, fill=fillcolor)

img = cv2.imread("v1080p_audio_output.jpeg")
imgpil = Image.fromarray(img)
draw = ImageDraw.Draw(imgpil)

fontpath = "./HYBiRanTianTianQuanW-2.ttf"
fontsize = 80
font = ImageFont.truetype(fontpath, fontsize)
title = "一段不错的街头舞蹈!"
text_border(draw, title, 100, 400, font, (0,0,0), (0,255,255))
retext = np.array(imgpil)
cv2.imwrite("./v1080p_audio_output_with_title.jpeg", retext) 

trans.py

import translators as ts
from pytube import YouTube

video = YouTube("https://www.youtube.com/watch?v=tO_L8bik10k")
title = video.title
print(title)
title_cn = ts.iciba(title, to_language='zh')
print(title_cn)