【class19】人工智能初步---语音识别(5)

【class19】

上节课,我们学习了:
语音识别模型的结构和原理,同时调用创建好的AipSpeech客户端实现了语音转文字功能。

本节课,我们将初识字幕,学习这些知识点:
1. srt字幕               2. 获取时间数据                             3. 时间换算

我们先来了解一下什么是外挂字幕?这类字幕有三个特点:
1. 独立于视频的字幕文件                             2. 不破坏视频画面,可随时根据需要更换字幕语言
3. 可随时编辑字幕内容,方便修改错误

我们今天要学习和自动生成的srt字幕,就是一种外挂字幕。当你在观看视频的时候,下面的那些字幕可能就是通过srt文件播放的哦~

srt字幕

定义

srt字幕的全称是SubRip Text,是一种文本格式的外挂字幕,也是目前最常用的外挂字幕格式之一。
srt字幕制作规范简单,格式为:序号+时间+字幕,修改十分方便!

我们以文本格式(如word文档,以Unicode(UTF-8)编码方式)打开一个标准的srt字幕文件,可以看到每段字幕由三部分组成:
                 1. 序号                  2. 时间                         3. 字幕

           

学习完srt字幕的概念和内容组成之后:
我们实现“生成标准srt字幕文件”的第一步——从音频中获取时间数据

接下来,我们需要从视频中获取时间数据,以便制作srt字幕中的时间部分~
让我们一起尝试一下吧~

代码结构

将从音频文件中获取时间数据分为两部分:
part1. 导入模块
part2. 获取时间数据

分析代码:

获取时间数据

代码的作用

第12-16行,导入模块,获取语音段的时间信息;第16行,使用detect_nonsilent()获取语音段时间信息。

导入detect_nonsilent类

需要使用的是pydub.silence模块里面的detect_nonsilent类。使用from...import从pydub.silence导入detect_nonsilent类。

detect_nonsilent()

导入模块后,通过detect_nonsilent()获取语音段时间信息。
detect_nonsilent()与前面切分音频中学到的split_on_silence()传入参数和用法一样。

不同之处在于:detect_nonsilent()通过传入静音段的参数min_silence_len, silence_thresh去除静音段,来定位语音段的位置,从而获取语音段时间信息,返回值为列表。

必选参数:sound

sound为必选参数,即待提取时间信息的音频对象。

可选参数:min_silence_len

min_silence_len为可选参数,它表示的是静音段的最小长度,默认值:1000(毫秒)。
设置min_silence_len = 500,表示静音部分长度任何比这大的值将被视为静音段。

可选参数:silence_thresh

silence_thresh为可选参数,它表示的是静音段的最小声音强度,默认值:-16dbfs
设置silence_thresh = -50,表示任何比这安静(如-55)的值将被视为静音。

返回值

将获取的语音段时间信息返回值赋值给变量timestamp_list,返回值为列表。

总结:

获取时间数据
首先,使用from...import从pydub.silence导入detect_nonsilent
然后,使用detect_nonsilent()获取语音段时间信息。

获取语音段时间信息后保存至列表timestamp_list中。输出查看列表timestamp_list,结果为语音段开始时间和结束时间的二维列表

         

二维列表中的每个列表元素为单段语音段的开始时间和结束时间。时间单位为毫秒
二维列表中共12个列表元素,对应着获取的12个音频片段的开始时间的结束时间。
举例说明:图中绿色框内的数据表明,音频片段11.wav在整段音频的22640ms开始,至23048ms结束

              

以文本格式(如word文档)打开一个标准的srt字幕文件,可以看到:
在标准的srt字幕中,时间格式为【时:分:秒,毫秒】。其中,时:分:秒的位数均为两位数毫秒位数为三位数

              

获取了语音段时间数据之后,我们需要进行格式转换:
我们实现“生成标准srt字幕文件”的第二步——毫秒换算成【时:分:秒,毫秒】格式

接下来,我们通过数学计算模和余数,进行时间换算         将毫秒时间换算成【时:分:秒,毫秒】格式。
学习代码前你需要知道的:1秒=1000毫秒,1分钟=60秒,1小时=60分钟。

代码结构

将时间数据格式转换分为两部分:
part1. 毫秒、秒、分和时换算
part2. 组成【时:分:秒,毫秒】格式

分析代码:

毫秒转换

毫秒t除以1000,将毫秒t转换为秒,毫秒,整数为秒,余数为毫秒。
整数和余数分别赋值给spart和mspart。

divmod()

divmod() 函数把取整和取余运算结合起来,返回一个包含商和余数的元组。
这里返回元组为:(t
//1000 , t%1000)

秒转换

秒spart除以60,将秒spart转化为分,秒,整数为分,余数为秒。
整数和余数分别赋值给mpart和spart。

时转换

分mpart除以60,将分mpart转化为时,分,整数为时,余数为分。
整数和余数分别赋值给hpart和mpart。

【时:分:秒,毫秒】格式

通过str()函数将hpart、mpart、spart、mspart转化为字符串格式,并以字符串组成【时:分:秒,毫秒】格式。

本段代码stype的结果为【0:0:0,53】,其中时、分、秒和毫秒的位数都不满足要求。
要求为:时:分:秒的位数均为两位数毫秒位数为三位数
下节课,我们将时间格式处理为标准格式——【00:00:00,053

本节课,我们学习了srt字幕概念,获取了音频中的时间数据,并做了时间换算,初步得到字幕时间。
下节课,我们将完善【时:分:秒,毫秒】格式,以满足字幕格式要求,得到标准的srt字幕文件。

【class20】

上节课,我们学习了:
srt字幕概念,获取了音频中的时间数据,并做了时间换算,初步得到字幕时间。

                        

上节课获取了音频中的时间数据,并做了时间换算,初步得到字幕时间格式为【0:0:0.53】。
但是,时、分、秒和毫秒的位数都不满足srt字幕文件格式要求。
要求为:时:分:秒的位数均为两位数毫秒位数为三位数

本节课,我们将学习这些知识点:
1. 【时:分:秒,毫秒】格式标准化                                   2. 去除标点符号

在上节课生成的时间格式基础之上:
我们实现“标准字幕文件生成”的第一步——时间格式标准化

接下来,我们通过代码实现【时:分:秒,毫秒】格式标准化:将时、分、秒和毫秒的位数调整为srt字幕文件标准【时:分:秒,毫秒】格式。

【时:分:秒,毫秒】格式标准化

代码的作用

第8行-第18行,通过返回指定长度字符串(位数不够前面补0),将【时:分:秒,毫秒】格式标准化。

第9行,mspart返回长度为3的字符串
第11行,spart返回长度为2的字符串
第13行,mpart返回长度为2的字符串
第15行,hpart返回长度为2的字符串
第18行,组成【时:分:秒,毫秒】格式

示例代码:

...

""将毫秒t转换为时,分,秒,毫秒""

spart,mspart = divmod(t,1000)

mpart,spart = divmod(spart,60)

hpart,mpart = divmod(mpart,60)

# mspart返回长度为3的字符串,位数不够前面补0

mspart=str(mspart).zfill(3)

# spart返回长度为2的字符串,位数不够前面补0

spart=str(spart).zfill(2)

# mpart返回长度为2的字符串,位数不够前面补0

mpart=str(mpart).zfill(2)

# hpart返回长度为2的字符串,位数不够前面补0

hpart=str(hpart).zfill(2)

# 组成【时:分:秒,毫秒】格式

stype = hpart+":"+mpart+":"+spart+","+mspart

分析代码:

设置毫秒格式

使用str()函数将mspart转化为字符串,再通过zfill()函数返回长度为3的字符串,位数不够前面补0。

例如:mspart为14,位数为2,通过本行代码可变为"014"。

字符串

使用str()函数将mspart转化为字符串,mspart字符串为待处理对象。

zfill()

通过zfill()函数并传入数字参数,可返回指定长度的字符串。

Zfill()函数的用法

zfill() 是字符串对象的一个方法,用于在字符串的左侧填充指定数量的零字符('0'),直到字符串达到指定的长度。如果字符串已经达到或超过指定的长度,则不会填充任何字符。

zfill() 方法的语法如下:

str.zfill(width)

其中,str 是要操作的字符串,width 是期望的字符串长度。如果 str 的长度小于 width,则在左侧填充足够数量的零字符,直到字符串达到指定的长度。

例如:

s = "42"

padded_s = s.zfill(5)

print(padded_s)  # 输出 "00042"

在这个例子中,字符串 "42" 的长度为 2,通过 zfill(5) 方法,将在字符串左侧填充 3 个零字符,使得最终字符串的长度为 5

这个方法通常用于格式化数字字符串,以确保它们具有相同的长度,方便对齐和比较。

长度

必选参数,zfill()函数传入数字参数3,设置字符串长度为3。

设置秒格式

使用str()函数将spart转化为字符串,再通过zifill()函数返回长度为2的字符串,位数不够前面补0。

设置分格式

使用str()函数将mpart转化为字符串,再通过zifill()函数返回长度为2的字符串,位数不够前面补0。

设置时格式

使用str()函数将hpart转化为字符串,再通过zifill()函数返回长度为2的字符串,位数不够前面补0。

我们已经学会了将毫秒时间转换为【时:分:秒,毫秒】标准时间格式。
基于DRY原则,我们只需要把获取标准时间格式方法写成一个函数,方便多次调用。

编写得到标准时间的函数代码如下:

# 定义函数getTime(),传入参数t

def getTime(t):

    # 将毫秒t转换为秒,毫秒

    # 毫秒t除以1000,整数为秒,余数为毫秒

    spart,mspart = divmod(t,1000)

    # 将秒spart转化为分,秒

    # 秒spart除以60,整数为分,余数为秒

    mpart,spart = divmod(spart,60)

    # 将分mpart转化为时,分

    # 分mpart除以60,整数为时,余数为分

    hpart,mpart = divmod(mpart,60)

    # mspart返回长度为3的字符串,位数不够前面补0

    mspart=str(mspart).zfill(3)

    # spart返回长度为2的字符串,位数不够前面补0

    spart=str(spart).zfill(2)

    # mpart返回长度为2的字符串,位数不够前面补0

    mpart=str(mpart).zfill(2)

    # hpart返回长度为2的字符串,位数不够前面补0

    hpart=str(hpart).zfill(2)

    # 组成【时:分:秒,毫秒】格式

    stype = hpart+":"+mpart+":"+spart+","+mspart

    # 返回标准时间格式stype

    return stype

进行检验:

学到这里,我们已经定义了标准时间格式函数,通过遍历列表可以循环调用。
我们前面得到的时间数据列表为timestamp_list,接下来,我们通过遍历和索引的方式取出二维列表中的每个元素,并将其转换为【时:分:秒,毫秒】标准时间格式。

通过定义时间格式转换函数:
我们已经将二维列表timestamp_list中的时间数据,转换为【时:分:秒,毫秒】的标准时间格式。
接下来,我们开始分析并制作srt字幕

我们再次以文本格式(如word文档)打开一个标准的srt字幕文件,可以看到每段字幕由三部分组成:
第一行:序号,从0开始
第二行:标准时间格式,格式为:开始时间 --> 结束时间
第三行:字幕的文字部分,也就是语音识别的文字

字幕文件中需要注意的:
1.开始时间和结束时间的" --> ",箭头前后各有一个空格;
2.两段字幕之间空了两行分隔开来,方便后续修改字幕。

  

字幕文件的三部分:序号、标准时间格式和文字,我们均已获得。
接下来,我们通过代码将该三部分组合起来,实现“标准字幕文件生成”的第二步——输出标准的srt字幕

学习了如何输出标准的srt字幕之后:
基于DRY原则,我们只需要把输出srt字幕方法写成一个函数,方便多次调用。

生成字幕的函数为:

# 定义函数getsrt(),传入参数sn,start_time,end_time,text

def getsrt(sn,start_time,end_time,text):

    # 序号、开始结束时间和文字组合起来得到标准字幕

    srt_text = str(sn)+"\n"+start_time+" --> "+end_time+"\n"+text+"\n"+"\n"

    # 返回标准字幕srt_text

return srt_text

输出查看srttext的结果,可以看到:
输出的字幕文字部分包括标点符号。一般来说,电影的字幕要求十分严格,不允许加标点符号

      

接下来,我们实现“标准字幕文件生成”的第三步——去除标点符号

通过代码去除字符串中的标点符号
使得输出的字幕文字更符合电影字幕的要求。

示例代码

代码的作用

第3行-第8行,将text文字中的标点符号替换成空格。
第4行,定义常用标点符号列表
第6行,for循环遍历symbol
第8行,使用replace()函数,将text文字中的标点符号替换成空格

...

# 定义常用标点符号列表,赋值给symbol

symbol = [",","。","!","?"]

# for循环遍历symbol

for j in symbol:

    # 使用replace()函数,将text文字中的标点符号替换成空格

text = text.replace(j," ")

分析代码:

标点符号列表

定义常用标点符号列表,包括逗号、句号、感叹号和问号四种。

遍历

通过for循环遍历列表symbol,j为列表symbol中的每个元素。

replace()

使用replace() 函数,把字符串text中的标点符号替换成空格。
用法:new_str = old_str.replace(a,b),将字符串old_str中变量a的值替换为变量b的值,结果赋值给new_str,原字符串old_str不变。

去除字幕文字中的标点符号之后:
我们实现“标准字幕文件生成”的第四步——写入srt字幕文件

写入srt字幕文件函数

通过定义函数writesrt(),传入参数srt,写入标准字幕文件。
使用 with...as 配合open()函数以a方式,打开路径为srtpath的srt文件(没有就新建一个),并赋值给 fp;
使用write()函数写入文件。最后,调用函数writesrt(),写入srt字幕文件,并输出提示信息:srt字幕文件写入成功!

# 定义函数writesrt(),传入参数srtpath,srt,写入标准字幕文件

def writesrt(srtpath,srt):

    # 使用 with...as 配合open函数以a方式,打开路径为srtpath的srt文件

    with open(srtpath,"a") as fp:

        # 使用write()函数写入文件

        fp.write(srt)

       

# 序号sn

sn = 0

# 开始时间start_time,结束时间end_time

start_time = "00:00:00,537"

end_time = "00:00:02,627"

# 文字部分text

text = "看来我不应该来"

# 将以上三部分组合起来,通过换行符\n实现换行

srt_text = str(sn)+"\n"+start_time+" --> "+end_time+"\n"+text+"\n"+"\n"

# 写入文件路径

srtpath = "/Users/yequ/大话西游.srt"

# 调用函数writesrt(),写入srt字幕文件

writesrt(srtpath,srt_text)

# 输出提示信息:srt字幕文件写入成功!

print("srt字幕文件写入成功!")

至此,我们要帮助阿九实现"一键生成srt字幕文件" 的功能就全部完成啦。
我们以文本格式(如word文档)打开生成的“大话西游.srt”字幕文件,可以看到最终的效果了!

使用支持外挂字幕的播放器打开“大话西游.mp4”视频文件,就可以看到视频中的字幕了!
需要注意两点
1.视频文件和字幕文件在同一个文件夹下
2.视频文件和字幕文件命名一样

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenWrt 安装Quagga 支持ospf Bgp等动态路由协议 软路由实测 系列四

1 Quagga 是一个路由软件套件, 提供 OSPFv2,OSPFv3,RIP v1 和 v2,RIPng 和 BGP-4 的实现. 2 web 登录安装 #或者ssh登录安装 opkg install quagga quagga-zebra quagga-bgpd quagga-watchquagga quagga-vtysh # reboot 3 ssh 登录 #重启服务 /etc/init.d/quagga restart #…

揭秘IDM:数字资产管理的未来之星

在当今数字化时代,数字资产管理的重要性日益凸显。随着科技的飞速发展,越来越多的企业和个人开始关注如何有效管理和保护他们的数字资产。在这个过程中,IDM(身份管理系统)逐渐成为了热门话题。IDM作为一种新兴的技术手…

一个生动的例子——通过ERC20接口访问Tether合约

生动的例子 USDT:符合ERC20标准的美元稳定币,Tether合约获得测试网上Tether合约地址通过自己写的ERC20接口访问这个合约 Tether合约地址:0xdAC17F958D2ee523a2206206994597C13D831ec7 IERC20.sol // SPDX-License-Identifier: GPL-3.0pra…

ARM-V9 RME(Realm Management Extension)系统架构之系统能力的内存隔离和保护

安全之安全(security)博客目录导读 目录 一、内存隔离和保护 1、颗粒PAS过滤Granular PAS filtering 2、Cache的一致性维护 2.1 物理别名点 Point of Physical Aliasing (PoPA) 2.2 加密点 3、内存(DRAM)保护 3.1 内存加密和完整性 3.2 DRAM scrubbing 本博客探讨 RME…

Django之rest_framework(九)

一、分页-PageNumberPagination类 REST framework提供了分页的支持 官网:Pagination - Django REST framework 1.1、全局设置 # settings.py REST_FRAMEWORK = {DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination,PAGE_SIZE: 100 # 每页数目 }提示…

【YashanDB知识库】自动选举配置错误引发的一系列问题

问题现象 问题出现的步骤/操作: ● 配置自动选举,数据库备库手动发起switch over,命令会报错 ● 主、备库变为只读状态,数据库无法进行读写操作 ● shutdown immediate 停止数据库,此时发现数据库一直没有退出&…

leetCode-hot100-数组专题之子数组+二维数组

数组专题之子数组二维数组 子数组238.除自身以外数组的乘积560.和为K的子数组 二维数组48.旋转图像 子数组 数组的子数组问题是算法中常见的一类问题,通常涉及到数组的连续元素。在解决这类问题时,常用的方法有前缀和、滑动窗口、双指针,分治…

C++模拟实现stack和queue

1 stack 1.1概念 stl栈 1.2栈概念 1.3代码 2 queue 2.1概念 stl队列 2.2队列概念 2.3代码

java中,怎样用最简单方法实现写word文档

在跨平台环境中实现写word时,如果用现成的库,就会涉及跨平台兼容性问题,比如在安卓与java中实现写word的功能。还有一个问题就是,完全用程序生成word文档,工作量较大。所以采用了模板替换的方法。 docx文档本质就是一…

Thingsboard规则链:Calculate Delta节点详解

在物联网(IoT)应用中,对设备数据的实时分析和处理是优化运营、预测维护的关键。Thingsboard作为一款功能强大的物联网平台,其规则引擎提供了丰富的节点来处理和分析数据流。其中,Calculate Delta节点是一个重要的工具,用于计算连续…

数据源不同?奥威BI软件是这么做的

面对数据源不同的情况,BI(商业智能)软件如奥威BI软件通常通过一系列技术和方法来实现数据的整理。以下以奥威BI软件为例,详细解释其如何整理不同数据源的数据: 数据收集: 爬虫技术:奥威BI软件…

六面体大米装袋机在提升大米包装效率中的作用

在当今社会,随着科技的飞速发展,各行各业都在寻求创新与突破,以提升生产效率和降低成本。而在大米包装领域,六面体大米装袋机的出现,无疑为整个行业带来了革命性的变化。这种先进的机械设备不仅提高了大米的包装效率&a…

MySQL-innodb后台线程

文章目录 一、结构图二、后台线程①Master Thread②IO Thread③Purge Thread④Page Cleaner Thread 拓展知识 一、结构图 二、后台线程 InnoDB是多线程的模型,因此其后台有多个不同的后台线程,负责处理不同的任务 后台线程有: ①Master Thr…

文件上传巩固及流量分析

1.[GXYCTF2019]BabyUpload 1)打开题目也是没有任何提示, 2)进入环境,看到下面页面猜测是文件上传漏洞,下面开始传文件 3)首先上传一句话木马 a.php,代码如下: 下面这个代码中并没有…

Mybatis多表查询

MyBatis-多表查询-一对一查询(方式一) 一个菜品对应一个分类 直接菜品记录category对象 菜品id写入Dish,后面的分类直接写入 Category类 封装,如果sql不能封装上,那么直接使用resultmap封装 使用resultType只能封装基本属性 所以要定义一个resultmap手动封装 使用标签 要…

整理三维空间内4点的209个结构

4点的209个结构按照旋转对称的关系可分成73组 如1,72,177为一组, z y x z y x 1 72 177 1 2 10 93 4 * 4 74 39 2 * 3 73 179 5 * 5 76 178 3 * 6 75 133 6 7 77 180 7 8 8 89 34 9 11 95 35 * 35 91 …

怎么藏族翻译中文在线翻译?更好地了解藏族文化

怎么藏族翻译中文在线翻译?着全球化的发展,语言交流的重要性日益凸显。藏族,作为中国的一个古老而神秘的民族,其语言对于很多人来说充满了神秘感。然而,在今天的数字化时代,我们有了更多的工具来打破语言壁…

unity中的常用属性修饰符

unity中的常用属性修饰符 一、前言二、常用修饰符三、结语 一、前言 在做unity开发编辑脚本的时候经常会用到属性修饰符,使开发调试更加便捷。初学者见过最多的莫过于[Header("标题文本")]了吧,除此之外其实还有很多,这篇文章列举说…

CI/CD(基于ESP-IDF)

主要参考资料 B站乐鑫信息科技《【乐鑫全球开发者大会】DevCon23 #15 |通过 CI/CD 进行流水线开发》 pytest-embedded乐鑫文档: https://docs.espressif.com/projects/pytest-embedded/en/latest/api.html 目录 CI/CD简介乐鑫内部CI/CD测试GitLab CI/CDGitHub Actio…

电子阅览室解决方案

一.方案概述 “电子阅览室”概念一经提出,就得到了广泛的关注,纷纷组织力量进行探讨、研究和开发,进行各种模型的试验。随着数字地球概念、技术、应用领域的发展,电子阅览室已成为数字地球家庭的成员,为信息高速公路提…