用Python+OpenCV截取视频中所有含有字幕的画面

1、需求背景

有的视频文件的字幕已经压制到了视频的图像中,不能单独提取出字幕文件。网上的 “提取视频字幕” 网站多为提取视频中的字幕文件,而非识别视频图像中的字幕。少数通过OCR技术识别画面中字幕的工具需要在线运行、运行速度较慢,或者需要收费,使用不够灵活。

我希望实现在视频中提取字幕截图的程序,需要解决两个关键问题:一是如何判断视频中是否出现了字幕,二是如何确定字幕何时发生变化。然后在有字幕且字幕刚刚发生变化时,截取并保存字幕图片。

为了解决这两个问题,我的主要思路是利用视频中字幕的固定位置和特殊颜色进行提取。通常情况下,字幕会出现在视频的特定区域,并且其颜色与周围背景颜色不同、并使用固定颜色。我们可以通过指定字幕所在的区域坐标和颜色来提取字幕图像。

然后通过判断在指定区域内符合指定颜色的像素值是否超过阈值,来判断是否存在字幕。而通过判断两帧画面之间的像素差异数是否超过阈值,来判断字幕是否变化

通过这种方式,并根据实际情况调整参数,可以达到比较合适的漏检率和误检率,从而实现较好的字幕提取效果。

2、设计思路

2.1 读取视频的迭代器函数 VideoIter

函数实现从视频中迭代获取指定时间范围内的帧图像,它接受4个参数:file表示视频文件路径,start_time表示开始时间(单位秒,后同),end_time表示结束时间,step_time表示迭代步长。其中start_timeend_time可以设置为负数,表示为相对于总时长的倒数时间位置,step_time设置为负数时表示为倒序迭代视频中的图像。

函数从视频的start_time开始时间开始截取图像,每间隔step_time步长时间捕获一张图像,将帧图像作为生成器(yield)的输出,直到达到end_time结束时间停止。

2.2 图像预处理函数 ProcessImage

函数实现从传入图像中裁剪指定区域、并根据给定的颜色和浮动值进行颜色分割,它接受4个参数:img表示输入的图像,area表示要裁取的区域边界坐标(格式为 (x1, y1, x2, y2)),color表示要分割的颜色(格式为 (r, g, b)),float表示颜色分割时的容差范围值。

函数设计从视频画面中裁取字幕出现位置的区域,然后根据设定的字幕颜色和允许容差匹配出文字区域的蒙版。最后,使用OpenCV的方法根据颜色阈值对图像进行转换,并将函数处理过的图像返回。

2.3 提取视频中字幕图像的主函数 ExtractSubtitle

函数实现从视频中提取字幕图像,它接受7个参数:file表示视频文件路径,area表示字幕所在区域的边界坐标(格式为 (x1, y1, x2, y2)),color表示字幕的颜色(格式为 (r, g, b)),float表示颜色判断时的容差范围值,count_thresh表示像素计数阈值,diff_thresh表示像素差异阈值,delay表示显示图像的延迟时间。

函数通过循环调用VideoIter函数迭代读取视频中的帧图像,并使用ProcessImage函数处理图像,将字幕部分提取出来。在处理过程中,函数统计处理后图像中非零像素的数量,并计算当前图像与上一帧图像的像素差异。如果像素数量和像素差异数值均超过了各自设定的阈值,就将当前帧图像显示输出(作为调试)、并将视频帧图像保存到视频文件同名的文件夹中。文件命名包含帧序号、像素数量、和像素差异数(用于调试参考)。

3、实现代码

import os
import cv2
import numpy as npdef imshow(img, delay=1, title=''):cv2.imshow('', img)cv2.setWindowTitle('', title)cv2.waitKey(delay)def imwrite(file, im):cv2.imencode('.jpg', im)[1].tofile(file)def VideoIter(file, start_time, end_time, step_time):cap = cv2.VideoCapture(file)fps = cap.get(cv2.CAP_PROP_FPS)total_time = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) / fpsif np.signbit(start_time):start_time += total_timeif np.signbit(end_time):end_time += total_timefor current_time in np.arange(start_time, end_time, step_time):cap.set(cv2.CAP_PROP_POS_FRAMES, int(fps * current_time))ret, img = cap.read()if not ret:breakyield imgcap.release()def ProcessImage(img, area, color, float):x1, y1, x2, y2 = areaimg = img[y1:y2, x1:x2]r, g, b = colorrgb1 = (r - float, g - float, b - float)rgb2 = (r + float, g + float, b + float)img = cv2.inRange(img, rgb1, rgb2)return imgdef ExtractSubtitle(file, area, color, float, count_thresh, diff_thresh, delay):folder = os.path.splitext(file)[0]os.makedirs(folder, exist_ok=True)img1 = Nonediff = 0for id, img in enumerate(VideoIter(file, 0, -1, 1), 1):img2 = ProcessImage(img, area, color, float)count = cv2.countNonZero(img2)if img1 is not None:diff = cv2.countNonZero(img1 ^ img2)img1 = img2if count > count_thresh and diff > diff_thresh:imshow(img2, delay=delay, title=f'count={count}, diff={diff}')save_path = f'{folder}/img_{id:06}@count={count}@diff={diff}.jpg'imwrite(save_path, img)if __name__ == '__main__':video_path = '三体.S01E01.HD1080P.mp4'area_xyxy = (564, 722, 1328, 784)subtitle_rgb = (250, 250, 250)floating_range = 10count_thresh = 1000diff_thresh = 400delay = 1ExtractSubtitle(video_path, area_xyxy, subtitle_rgb, floating_range, count_thresh, diff_thresh, delay)

函数运行前有若干参数需要确定,首先是字幕出现的位置字幕的颜色

截取若干典型的视频中包含字幕的图像,然后通过图画板确定字幕出现的位置,用取色器获得字幕的RGB值。

读取字幕位置坐标:

读取字幕位置坐标

字幕颜色取色:

字幕颜色取色

另外两个需要设定的参数,是判断图像中存在字幕的阈值、和字幕发生变化的阈值。很显然,这两个数值都应大于0。

其中,存在字幕的阈值设置得越低,则会有越多的本不包含字幕,但是由于背景色中存在和字幕相同颜色而被误判断成为含有字幕的图片。

发生变化的阈值设置得越低,则会有越多的相同的字幕画面由于图片压缩或背景差异,有少量像素存在区别,被误判断成字幕已经发生变化,导致截取出多余的字幕画面图像

在具体调试时,可以先将这两个参数设定为0,然后运行程序。在弹出的可视化窗口中,在标题中可以看到我设置的这两个参数的计算数值。

结合实际裁取出的图像,我们可以适当地设计这两个门限参数的数值,通过调整参数并观察提取结果,以获得较好的字幕图像截取效果。

4、运行效果

测试运行60分钟的网飞《三体》第一集,一共提取出了600张截图,有比较良好的漏检率和误检率。如果按照1秒钟看5张图的话,2分钟就可以看完60分钟的第一集。

程序运行结果:

程序运行结果

拼合字幕图片:

import glob
import cv2
import numpy as npimread = lambda file: cv2.imdecode(np.fromfile(file, np.uint8), -1)
imwrite = lambda file, img: cv2.imencode('.jpg', img)[1].tofile(file)def MergeSubtitles(folder, h1, h2):imgs = []for path in glob.glob(f'{folder}/*.jpg'):img = imread(path)imgs.append(img[h1:h2])final_image = cv2.vconcat(imgs)imwrite(f'{folder}.jpg', final_image)if __name__ == '__main__':MergeSubtitles('三体.S01E01.HD1080P', 722, 784)

最终图片效果:

截图效果展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/802355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯练习笔记(十八)

蓝桥杯练习笔记(十八) 一、用辅助栈来优化递归深度过大的问题 输入示例 0000100010000001101010101001001100000011 0101111001111101110111100000101010011111 1000010000011101010110000000001011010100 0110101010110000000101100100000101001001 0…

QT打包生成.exe可执行文件

QT打包生成.exe可执行文件 程序运行图标如何设置快捷方式显示图标QT打包成可执行文件将可执行文件打包成安装包程序运行图标 如何生成如下图标? 首先将你的图标(ico文件)放入当前工程目录,即含有.pro文件的同级目录 右击项目,选择ADD New,选择Qt Resource File, 这是一个…

吴恩达2022机器学习专项课程(一) 5.7 检测梯度下降是否收敛

问题预览/关键词 什么是梯度下降收敛?哪些方法可以检测梯度下降是否收敛?什么是学习曲线?曲线上升代表什么?什么原因造成的?如何检测梯度下降是否收敛?多少次迭代,梯度下降会收敛?什…

C++:初步接触C++(2)

hello,各位小伙伴,本篇文章跟大家一起学习C,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 文章目录 内联函数1.概念2.特性 auto关键字1.auto简介2.auto的使用细则3.auto不能推导的场景 基于范围…

RTThread studio 驱动开发

rtthread 驱动使用的两种情况 rtthread studio 自动生成 由 RT Thread Studio 自动生成,无需修改任何文件或者简单定义几个宏即可直接使用的驱动,如 GPIO,UART,I2C,SPI,SDIO 和 ETH 等。 使用 RT-Thread S…

如何定位和优化程序CPU、内存等性能之巅

如何定位和优化程序CPU、内存等性能之巅 摘要 性能优化指在不影响系统运行正确性的前提下,使之运行得更快,完成特定功能所需的时间更短,或拥有更强大的服务能力。本文将介绍性能优化的基本概念以及如何定位和优化程序中的CPU、内存和IO瓶颈…

信息泄露漏洞的JS整改方案

引言 🛡️ 日常工作中,我们经常会面临线上环境被第三方安全厂商扫描出JS信息泄露漏洞的情况,这给我们的系统安全带来了潜在威胁。但幸运的是,对于这类漏洞的整改并不复杂。本文将介绍几种可行的整改方法,以及其中一种…

指挥中心控制台厂家定制控制台技术规范全方位指南

指挥中心控制台作为现代化管理的重要组成部分,在整个企业的运行中起着重要作用,为了保证指挥中心的正常运行,控制台的定制不可缺少,那么指挥中心控制台厂家定制控制台技术规范是什么? 1. 结构性能规范:控制台需采用优…

kmeans聚类sklearn实现(Python实验)

Kmeans毫无疑问,好用又“便宜”的算法,经常在很多轻量化场景中实现。所谓的“聚类”(Clustering),就是通过欧氏距离找哪些点构成一个簇。假设我们空间中有一堆点,通过肉眼大概可以看出有两簇,思…

jmeter压测websocket协议

一、jmeter 安装websocket插件 1、选项--插件管理 2、搜索WebSocket Samplers by Peter Doornbosch插件 进行安装 3、 重启 jmeter 二、jmeter压测websocket协议实战 2.1、以网站为例: websocket在线测试 1、断开连接 2、打开F12,查看WS数据 3、…

DragonIM龙通讯

前言 龙通讯是一款C/S架构的即时通讯软件,实现了用户注册、登录、好友私聊、群聊(文字、表情、文件),群文件上传/下载,群公告,朋友圈(可点赞和评论),AI聊天,…

剪切助手-高颜值的跨平台剪切板工具

高颜值的跨平台剪切板工具来了!! http://t.csdnimg.cn/xKB3B 出于我的一些日常使用需求以及在对比了其他剪切板软件后,我决定做一个跨平台的高颜值剪切板工具《剪切助手》! 废话不多说,你可以来这里 下载体验 它&…

day76 jquery

知识点: 1 在HTML中引入jQuery 2 jQuery中就绪函数 3 jQuery中选择器 4 使用jQuery获取表单元素的值 及标签中间的内容 5 jQuery中获取标签属性 6 jQuery设置和获取标签样式 ----------------------------------- 一 在HTML中引入jQuery 1/*! jQuery…

RFID涉密载体柜 RFID智能文件柜系统

涉密载体管控RFID智能柜(载体柜DW-G101R)通过对涉密物资、设备进行RFID唯一标识并放置于RFID设备涉密物资柜柜体,通过定位每台设备每件涉密物资的位置,实现涉密物资审批、自助借还、防盗等出入库全流程自动化管理。主要管理对象移…

redis 集群模式(redis cluster)介绍

目录 一 redis cluster 相关定义 1, redis cluster 是什么 2,redis 集群的组成 3,集群的作用 4,集群架构图 二 Redis集群的数据分片 1,哈希槽是什么 2,哈希槽如何排布 3,Redis集…

五边形信息图表绘制方法

五边形信息图表绘制方法 在网络科技发展进步的当下,原来一些传统的统计图表都有了进一步的创新。以前企业的PPT都依赖微软的各应用软件来制作图表,现时企业的PPT展示的图表应用不再满足于原来的图表绘制方法,进而使用一些第三方应用软件来制作…

Linux_进程的优先级环境变量上下文切换优先级队列

文章目录 一、进程的优先级二、进程的四个重要概念三、上下文切换四、环境变量查看当前shell环境下的环境变量与内容 五、Linux2.6内核进程调度队列一个CPU拥有一个runqueue优先级活动队列过期队列active指针和expired指针 一、进程的优先级 什么是优先级? 指定一个…

如何使用宝塔面板搭建MySQL数据库并实现无公网IP远程访问

文章目录 前言1.Mysql服务安装2.创建数据库3.安装cpolar3.2 创建HTTP隧道 4.远程连接5.固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 宝塔面板的简易操作性,使得运维难度降低,简化了Linux命令行进行繁琐的配置,下面简单几步,通过宝塔面板cp…

rhce复习3

DNS DNS(Domain Name System)是互联网上的一项服务,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网。 DNS系统使用的是网络的查询,那么自然需要有监听的port。DNS使用的是53端口&#x…

本地MinIO存储服务通过Java程序结合cpolar实现远程连接上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统,它可以100%的运行在标准硬件上,即X86等…