前言
这段时间疫情严重,在家就找些视频看,然后就发现了一部蛮有意思的纪录片——《生命·觉者》
这是一部主持人和嘉宾问答过程中传递思想和观点的纪录片
可能是因为做节目的关系,一些观点的表达方式容易引起争议,但是他们看待事物的角度和思想的高度令人叹服
视频中的很多观点都发人深省,但我总觉得视频播放这种媒介形式对有深度的思想的传播不利,当我需要专注于讲话者的言语时,主持人的神情形态、视频的 BGM 和穿插的影视片段等等都是一种噪声
要是能将讲话者的言谈记录下来整理成笔记,当作书本一样阅读就好了
基于这一想法,又因该纪录片没有字幕文件,所以我就开始自己动手制作”笔记“
视频下载
视频我是 YouTube 上在线观看的,要做后期处理的话,首先要将视频下载下来
一开始我选择了 pytube 这个第三方库,结果遇到了不少麻烦
因为作者有几个月没有更新了,YouTube 的一些规则变化的很快,爬取过程会出现各种 BUG
然后我就针对一个个 BUG 去改源码,修改的过程中虽然发现了有人在做同样的事并且推出了 pytube3,但是还需要进一步的修改
为了避免重复造轮子,我最后尝试了下 youtube-dl,这是用 Python 写的一个命令行程序
项目地址:
https://github.com/ytdl-org/youtube-dl
我本来不喜欢用这种写好的程序,印象中操作都太傻瓜化,总觉得灵活度会受到限制,但是接下来的使用感受却颠覆了我最初的想法
该程序的参数十分之多,可定制性非常高,基本上你能想到的问题都能在这些参数中找到
比如说 -c 参数是开启断点续传功能,--yes-playlist 是下载整个播放列表的,-f best 默认下载最佳品质视频,-o 是对文件输出名做格式化,这些还是基本功能
其他的一些参数,比如 --proxy 挂代理的作用我就不解释了,主要是 --socket-time 和 -R 参数,不知道是因为网络环境的问题还是 Youtube 的规则又发生了变化,每下载一条视频段,程序就会卡住,默认时间后会重试
这里的 --socket-timeout 可以缩短延迟时间,加快下载速度, -R 参数控制重连次数,默认上限 10 次,改成"infinite"后去除上限
差不多我想从源码处进行修改的点,参数上都提供了对应的接口,对开发人员十分友好
通过上面的配置,这才解决了网络环境对 YouTube 视频下载的限制,然后用笔记本跑了一晚上将视频下载到磁盘
字幕提取
下载完成后,就要开始对视频做字幕提取的工作了
本次基于图像识别对视频所做的字幕提取工作都是通过 Python 的 OpenCV 库完成的
比如初始化时对视频基本信息所做的读取工作:
该库的具体使用方法可参考:
https://github.com/skvark/opencv-python
首先要知道,视频由很多帧组成,比如下面演示中的视频的总帧数是 90986,帧率(fps)是 29.97,其数值等于该视频每秒连续出现多少帧
现在的电影的帧率一般都大于 24fps,这时人眼观影时就会有流畅的感觉
随便选取一帧如下:
然后用任意作图软件定位到字幕位置的 Y 轴坐标范围,这里我选取(325, 360),截取如下:
重复这一步骤就可以把每一帧图片中的字幕提取出来了
但是接下来还有两个问题需要解决:
如何判断某一帧图像上是否有字幕?
如何判断这一帧同上一帧之间是否存在字幕切换?
如果能解决以上问题,则可以:
遍历每一帧,去除无字幕图像
遍历过程中判断是否发生字幕切换,如果有则保留该图,否则去除
综上所述,我们需要做一些简单的图像识别
首先,要对图像做二值化处理,先得选取阈值(threshold)
简单点可以自己赋值,黑色像素值是 0,白色像素值是 255,字幕通常是黑底白字,我们可以选个中间值 150
高级点的可以借助OTSU算法,来确定一个自适应的阈值
但是部分处理结果会出现下面的情况:
所以最后我选择在OTSU算法的结果上加了个常量 15,用以消除未知的噪声
接下来,需要引进一个指标,来衡量图像相似度
这里我选择用均方误差(MSE),计算两图像间对应位置像素点的平方误差之和的均值百分比:
比如取 b=0 时,上面第一张字幕图片与 0 值图像的误差 e 值计算为 3.128
简单地归纳总结后发现:
每张图像与 0 值图像的误差 e > 1时,有字幕;
不同字幕图像的误差 e > 1时,发生字幕切换
之后就可以遍历视频的每一帧并按以上步骤处理
最后我将其中一部 50 分钟的视频浓缩成了一张 1M 大小的字幕长图
如果只想选取视频片段呢?
那么首先要根据播放时间大致定位到是哪一帧
然后跳转到那一帧,再按上述步骤处理
文字识别
最后一步就是将上面制作完成的字幕图片整理成文字了
网上有各种OCR文字识别平台的接口可供调用,这里我以百度AI开放平台为例:
接口的具体调用方法可以参考官方文档,不过这里要注意下 image 参数的要求
而我最后生成的图像显然超过了要求数值
所以在合成字幕图像的时候要做个切割处理,不过每张图片集合的字幕数量不能简单的依据上面的 4096px 来计算,还要考虑到识别的准确度,单张图片集合字幕数量太多会造成识别出错
然后我将 50 条字幕集成一张图片,一共生成 34 张图,每张图都可以准确识别出文字
图像切割和生成的核心代码如下:
输出效果图:
单张图片OCR文字识别结果:
最后将识别结果整合一下
最后
从上面的使用中,我感受到 Python 的 OpenCV 库确实十分强大
其本身的定位是用于解决计算机视觉领域的问题,运用好不仅能完成视频字幕提取这种简单的任务,包括人脸识别,运动检测等更广泛更实用的应用场景都能借助它来搞定
尤其这几天大家都需要闭门不出,正好有时间来鼓捣鼓捣这些有意思的事情!
本文首发于公众号: 慕长风的小酒馆