结合图片相似度计算与PaddleOCR:打造高效视频字幕快速提取工具

目录

1 确定思路

1.1 问题分析

1.2 来自ScreenToGif的启发

2 图片相似度计算

2.1 概念引入

2.1.1 哈希算法计算图片的相似度

2.1.2 直方图计算图片的相似度

2.1.3 余弦相似度(cosin)

2.1.4 图片SSIM(结构相似度量)

2.2 算法实现

3 实现效果

4 FAQ

4.1 是否需要加入文本相似度检测

4.2 如何剔除视频下部非字幕的文字LOGO


1. 什么是PaddleOCR?

PaddleOCR是PaddlePaddle生态的一个重要组成部分,专为OCR任务定制,将最先进的OCR算法集成到了一款易于使用的库中。PaddleOCR不仅支持25种以上的全球主流语言,而且性能优秀,准确率高。

2. 如何提取视频字幕?

视频字幕提取主要可以分为三个步骤:视频帧提取、字幕区域检测和字符识别。

  • 视频帧提取:首先,我们需要从视频中提取帧。每一帧都是一个静态图像,我们可以将它们保存下来,以便后续处理。

  • 字幕区域检测:在获取了视频帧之后,我们需要找出其中的字幕区域。这可以通过图像处理技术实现,例如图像二值化、边缘检测和连通组件分析等。

  • 字符识别:找到字幕区域后,我们需要识别出其中的字符。这就需要用到OCR技术。在这里,我们可以使用PaddleOCR来完成这个任务。

3. 如何利用图片相似度计算来提高效率?

在视频字幕提取的过程中,我们需要处理大量的视频帧。然而,许多连续的视频帧可能十分相似,字幕区域也相同。如果我们对每一帧都进行字幕区域检测和字符识别,可能会浪费大量的计算资源。

为了提高效率,我们可以利用图片相似度计算来找出相似的视频帧。具体来说,我们可以将每一帧与前一帧进行比较,如果它们足够相似(例如,相似度超过一个阈值),那么我们就可以直接复用前一帧的字幕区域和识别结果,从而避免重复计算。

1 确定思路

1.1 问题分析

但是,上面两种字幕生成方案,有一个共同的问题:慢!

比如语音识别吧,装个模型需要各种依赖,词典库、模型库等等,而且预测起来速度也不快,关键准确率距离100%还有一定差距,还要频繁回头改,不行不行!

1.2 来自ScreenToGif的启发

要说小而精的开源生产力工具,对于经常需要录制屏幕并制作gif图的笔者,ScreenToGif那叫一个好用。

当然大家也知道,gif文件很容易变得很大,这时,ScreenToGif就提供了一个非常实用的功能:去除重复帧。

其效率之高,类似度量学习这类深度学习算法,只能暂时靠边站了。对于我们现在面临的这个字幕演讲稿提取场景,似乎去除重复帧也非常重要吧?

接下来,我们就来分析下具体的实现方法。

2 图片相似度计算

2.1 概念引入

2.1.1 哈希算法计算图片的相似度

提到检测“某某”的相似度相信很多人第一想法就是将需要比较的东西构建成两个向量,然后利用余弦相似度来比较两个向量之间的距离,这种方法应用很广泛,例如比较两个用户兴趣的相似度、比较两个文本之间的相似度。但是这个方法在比较图片相似度的时候用到的并不多。因为在Python里,通过哈希算法去实现也是一个很有效的方式。

这里,我们从均值哈希算法(aHash)的实现来引入这个概念,这里推荐一篇公众号文章《图像相似度中的Hash算法》,感兴趣的同学可以去学习一下。

我们从Python图像处理中,大家最熟悉的一张图说起: 

图1 Lena(Origin)图

为了便于理解,我们将它转为8x8尺寸

图2 转为8x8尺寸的Lena图

三个颜色通道也不利于我们理解,继续转成灰度图

图3 转为灰度8x8尺寸的Lena图

其中转为8x8尺寸的Lena对应的数据矩阵为:

很容得到如上矩阵所有元素的均值a= 121.328125, 将上述矩阵中大于或等于a的元素置为1, 小于a的元素置为0,可得:

所以可得Lena图的aHash为

1011111010011110100111011010100110101011101000110000111000101100

将二进制形式ahash转十六进制hash为

be9e9da9aba30e2c

为了测试aHash算法的效果,我们用一张带噪声Lena(noise)图和与Lena不一样的Barbara做图片相似度对比实验,

其中Lena(noise)和Barbara如下:

图4 Lena(noise)图

图5 Barbara图

通过aHash算法容易得三个图片的hash值,然后根据hanming距离计算Lena(origin).png和Lena(noise).png Barbar.png之间汉明距离,具体如下:

从上面的结果可以看出,均值哈希算法(aHash)能区别相似图片和差异大的图片。

当然,如果不用均值,还可以有其它形式的哈希算法,总结下来,在Python中我们能实现3种图片相似度算法:

  1. 均值哈希算法
  2. 差值哈希算法
  3. 感知哈希算法

2.1.2 直方图计算图片的相似度

颜色直方图是一个很“古老”的图片相似度比较方法了。

利用直方图计算图片的相似度时,是按照颜色的全局分布情况来看待的,无法对局部的色彩进行分析,同一张图片如果转化成为灰度图时,在计算其直方图时差距就更大了。

2.1.3 余弦相似度(cosin)

和各种文本相似度计算类似,余弦相似度就是把图片表示成一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度。

2.1.4 图片SSIM(结构相似度量)

SSIM是一种全参考的图像质量评价指标,分别从亮度、对比度、结构三个方面度量图像相似性。SSIM取值范围[0, 1],值越大,表示图像失真越小。在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差,然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性SSIM。

两行代码实现SSIM

from skimage.metrics import structural_similarity as compare_ssim
ssim1 = compare_ssim(img1, img2, multichannel=True)

参考资料:

2.2 算法实现

综合考虑之下,我们可以先选简单的来,比如就用两行代码能搞定的图片SSIM(结构相似度量)吧!

In [29]

!pip install scikit-image
!pip install -U paddleocr

In [9]

import os
import cv2
from PIL import Image
import numpy as np
from skimage.metrics import structural_similarity as compare_ssim
from tqdm import tqdm

In [26]

from paddleocr import PaddleOCR, draw_ocr
# Paddleocr目前支持的多语言语种可以通过修改lang参数进行切换
# 例如`ch`, `en`, `fr`, `german`, `korean`, `japan`
ocr = PaddleOCR(use_angle_cls=False, lang="ch") 

为减少干扰,进一步提高识别效果和速度,对于字幕固定在下方的视频,我们最好通过抠图,把会出现字幕的部分裁剪出来,然后用这些数据预测。

In [28]

src_video = cv2.VideoCapture('Trim.mp4')

prev_frame = None # 用于保存上一帧图像
total_frame = int(src_video.get(cv2.CAP_PROP_FRAME_COUNT)) # 计算视频总帧数
save_text = []
last_res = None
for i in range(total_frame):    
    success, frame = src_video.read()
    if i == 0:
        prev_frame = frame[-120:-30,:] # 裁剪视频的下方部分
    src_video.release()       

src_video = cv2.VideoCapture('Trim.mp4')
for i in tqdm(range(total_frame)):    
# for i in tqdm(range(2400)):    
    success, frame = src_video.read()
    # if not firstlaunch:
    if success:
        ssim1 = compare_ssim(frame[-120:-30,:], prev_frame, multichannel=True)
        # print(ssim1)
        if ssim1 > 0.9:
            pass
        else:
            result = ocr.ocr(frame[-120:-30,:], cls=True)
            # print(result)
            if len(result)> 0: 
                res = result[0][1][0]
                if res != last_res:
                    print(result[0][1][0])
                    save_text.append(res)
                    last_res = res
            prev_frame = frame[-120:-30,:].copy() # 存储此帧

In [18]

# 输出结果
save_text
['让我们从一次时光旅行',
 '开启植物天堂的故事',
 '地球的午夜',
 '是在火山喷发中度过的',
 '到了凌晨三四点',
 '在海洋深处有了生命的迹象',
 '清晨6点多',
 '更加壮丽的生命乐章开始了',
 '一种蓝藻细菌',
 '种蓝藻细菌',
 '学会利用二氧化碳',
 '学会利用二氧化碳水和阳光',
 '制造生命所需能量',
 '同时释放出了氧气',
 '这个被称为光合作用的过程',
 '为植物世界打开了大门',
 '此时',
 '中国的陆地',
 '也逐渐从海洋露出形成岛屿',
 '但在相当长的时间里',
 '陆地十分荒凉没有生机',
 '这些岩石坚硬',
 '无法储存水分',
 '是当时陆地环境的写照',
 '直到晚上九点多',
 '也就是四亿年前左右',
 '些矮小的生命',
 '开始征服陆地']

In [ ]

# 保存读取的字幕文件
with open('output.txt','w') as f:
    for i in save_text:
        f.writelines(i+'\n')
    f.close()

3 实现效果

我们处理上面这个1分44秒的视频,提取字幕的运行时间为121.578秒——约2min,这个效率还是非常高的吧。

大功告成!

4 FAQ

4.1 是否需要加入文本相似度检测

从上面的运行结果中,我们也能看出,即使是OCR识别字幕,有时会因为个别字没有识别到,导致出现两个相似的句子。

那么,是否需要加入文本相似度检测来去重呢?让这个pipeline更加智能?

个人建议不加,主要有两个原因:

  1. 其实我们可以看到,标准字体的字幕,OCR识别效果已经非常好了,字幕因识别出错导致重复句的情况不多,手动微调下工作量不大;加入文本相似度检测算法会进一步增加字幕生成所需时间,浪费这个时间还不如手动调整。

  2. 剔除规则不好界定,如果是首句识别出错,剔除了后面相似的正确文本,反而不对。

这个目前没有想到特别好的办法,读者可能需要初步确认下视频字幕生成范围,并与LOGO出现的位置进行比对,看是否需要在处理视频帧时,抠掉LOGO出现的位置

猜你喜欢

转载自blog.csdn.net/m0_68036862/article/details/131359425