实用系列1 —— 视频中的语音转换成文字

zz/2024/6/13 22:22:41

实用系列1 —— 视频中的语音转换成文字python版本

背景说明

疫情原因,家里的老师亲戚需要对着电脑上网课,晋升为十八线小主播~
备课的内容来源都是当地教育局的公开课,为了学习公开课的上课方法,只能自己慢速播放视频,并手动敲下所有汉字,此时我作为一个家里人眼中的‘电脑高手’,被迫上场表演,那么就来看看如何做到自动转换视频中的语音到文字呢?

技术方案设计

要实现自动转换视频中的语音到文字的功能需要两步,
第一,抽取视频中的语音流数据
第二,使用语音识别模型识别语音流数据
语言:python 3.6/3.6+
视频格式: MP4

抽取视频中的语音流数据

我是用python库moviepy (链接:https://pypi.org/project/moviepy)
安装方法:pip install moviepy
目的:从mp4视频中抽取语音流数据并转换成wav格式
使用方法:

    from moviepy.editor import *import os file_name = 'SVID_20200429_151304_1.mp4'dir_name = file_name.replace('.mp4', '')cmd1 = 'mkdir /Users/user/Documents/{}'.format(dir_name)os.system(cmd1)  # 新视频就建立个新目录存放video = VideoFileClip('/Users/user/Documents/{}.mp4'.format(dir_name))audio = video.audioaudio.write_audiofile('/Users/user/Documents/{}.wav'.format(dir_name))  # 主要转化函数

使用语音识别模型识别语音流数据

自己尝试自己训练了下语音模型,使用开源数据下效果只能说是一般;故而使用百度云的语音识别API,目前(2020.05)只要注册就可以免费调用50000次短语音识别(语音长度不超过60秒)
注册地址:https://login.bce.baidu.com/?redirect=http%3A%2F%2Fcloud.baidu.com%2Fcampaign%2FPromotionApr%2Findex.html
注册完成后记得建立应用并记录对应的API_KEY和SECRET_KEY,这是你调用API的身份凭识

具体调用脚本可以参考百度云在git上的demo,注意百度短语音识别只支持单声道,16000码率的音频,这需要我们转换下音频的格式,需要使用到ffmpeg,mac直接使用homebrew安装即可
具体转换命令:ffmpeg -y -i wavfile_name -acodec pcm_s16le -f s16le -ac 1 -ar 16000 pcmfile_name

整体示例代码

# coding=utf-8import sys
import json
import base64
import time
from scipy.io import wavfile
import subprocess
import osIS_PY3 = sys.version_info.major == 3if IS_PY3:from urllib.request import urlopenfrom urllib.request import Requestfrom urllib.error import URLErrorfrom urllib.parse import urlencodetimer = time.perf_counter
else:from urllib2 import urlopenfrom urllib2 import Requestfrom urllib2 import URLErrorfrom urllib import urlencodeif sys.platform == "win32":timer = time.clockelse:# On most other platforms the best timer is time.time()timer = time.timeAPI_KEY = '你的api key'
SECRET_KEY = '你的secret key'# 需要识别的文件
AUDIO_FILE = '/Users/user/Documents/test2.pcm'  # 只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式
# 文件格式
FORMAT = AUDIO_FILE[-3:]  # 文件后缀只支持 pcm/wav/amr 格式,极速版额外支持m4a 格式CUID = '123456PYTHON'
# 采样率
RATE = 16000  # 固定值# 普通版DEV_PID = 1537  # 1537 表示识别普通话,使用输入法模型。根据文档填写PID,选择语言及识别模型
ASR_URL = 'http://vop.baidu.com/server_api'
SCOPE = 'audio_voice_assistant_get'  # 有此scope表示有asr能力,没有请在网页里勾选,非常旧的应用可能没有#测试自训练平台需要打开以下信息, 自训练平台模型上线后,您会看见 第二步:“”获取专属模型参数pid:8001,modelid:1234”,按照这个信息获取 dev_pid=8001,lm_id=1234
# DEV_PID = 8001 ;
# LM_ID = 1234 ;# 极速版 打开注释的话请填写自己申请的appkey appSecret ,并在网页中开通极速版(开通后可能会收费)# DEV_PID = 80001
# ASR_URL = 'http://vop.baidu.com/pro_api'
# SCOPE = 'brain_enhanced_asr'  # 有此scope表示有极速版能力,没有请在网页里开通极速版# 忽略scope检查,非常旧的应用可能没有
# SCOPE = Falseclass DemoError(Exception):pass"""  TOKEN start """TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token'def fetch_token():params = {'grant_type': 'client_credentials','client_id': API_KEY,'client_secret': SECRET_KEY}post_data = urlencode(params)if (IS_PY3):post_data = post_data.encode( 'utf-8')req = Request(TOKEN_URL, post_data)try:f = urlopen(req)result_str = f.read()except URLError as err:print('token http response http code : ' + str(err.code))result_str = err.read()if (IS_PY3):result_str =  result_str.decode()print(result_str)result = json.loads(result_str)print(result)if ('access_token' in result.keys() and 'scope' in result.keys()):print(SCOPE)if SCOPE and (not SCOPE in result['scope'].split(' ')):  # SCOPE = False 忽略检查raise DemoError('scope is not correct')print('SUCCESS WITH TOKEN: %s  EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in']))return result['access_token']else:raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response')"""  TOKEN end """if __name__ == '__main__':token = fetch_token()from moviepy.editor import *import osfile_name = 'SVID_20200429_151304_1.mp4'dir_name = file_name.replace('.mp4', '')cmd1 = 'mkdir /Users/user/Documents/{}'.format(dir_name)os.system(cmd1)video = VideoFileClip('/Users/user/Documents/{}.mp4'.format(dir_name))audio = video.audioaudio.write_audiofile('/Users/user/Documents/{}.wav'.format(dir_name))speech_data = []like = wavfile.read('/Users/user/Documents/{}.wav'.format(dir_name))start_sec = 10end_sec = 1777intern = 55# start_sec: 识别起始秒数,end_sec:识别结束秒数, intern : 每次调用秒数间隔,不能超过60,保守起见选择55秒with open("/Users/user/Documents/{}/result.txt".format(dir_name), "w") as of:for i in range(start_sec, end_sec, intern):j = min(end_sec, i + intern)wavfile_name = '/Users/user/Documents/{}/test_{}_{}.wav'.format(dir_name, i, j)pcmfile_name = '/Users/user/Documents/{}/test_{}_{}.pcm'.format(dir_name, i, j)wavfile.write(wavfile_name, 44100, like[1][i * 44100:j * 44100])cmdline = "ffmpeg -y  -i {}  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {}".format(wavfile_name, pcmfile_name)ret = os.system(cmdline)print('code: ', ret)with open(pcmfile_name, 'rb') as speech_file:speech_data = speech_file.read()length = len(speech_data)if length == 0:raise DemoError('file %s length read 0 bytes' % AUDIO_FILE)speech = base64.b64encode(speech_data)if (IS_PY3):speech = str(speech, 'utf-8')params = {'dev_pid': DEV_PID,# "lm_id" : LM_ID,    #测试自训练平台开启此项'format': FORMAT,'rate': RATE,'token': token,'cuid': CUID,'channel': 1,'speech': speech,'len': length}post_data = json.dumps(params, sort_keys=False)# print post_datareq = Request(ASR_URL, post_data.encode('utf-8'))req.add_header('Content-Type', 'application/json')try:begin = timer()f = urlopen(req)result_str = f.read()print("Request time cost %f" % (timer() - begin))except URLError as err:print('asr http response http code : ' + str(err.code))result_str = err.read()if (IS_PY3):result_str = str(result_str, 'utf-8')print(result_str)dd = json.loads(result_str)of.write(dd['result'][0] + '\n')

http://www.ngui.cc/zz/2390165.html

相关文章

某优job

目标url : aHR0cHM6Ly93d3cuNTFqb2IuY29tLw 抓取相关数据 通过对源代码的查看,可以很明确的知道,这些数据是同步加载的。 抓包分析: payload不变,由此可以确定url和发送的params 确定headers需要的字段 凭经验和实际测试可得…

手写代码(笔试面试真题)

★★★ 手写代码:实现forEach map filter reduce ★★★ 手写实现一个简易的 Vue Reactive ★★★ 手写代码,监测数组变化,并返回数组长度 ★★★ 手写原生继承,并说出局限性? ★★★★ 手写一个柯里化函数 ★★★…

2021-最新Web前端经典面试试题及答案-史上最全前端面试题(含答案)---手写代码篇

★★★ 手写代码:实现forEach map filter reduce ★★★ 手写实现一个简易的 Vue Reactive ★★★ 手写代码,监测数组变化,并返回数组长度 ★★★ 手写原生继承,并说出局限性? ★★★★ 手写一个柯里化函数 ★★★…

可以设置过期时间的Java缓存Map

前言 最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式。项目前期暂时不引进redis,暂时用java内存代替。 解决方案 1. ExpiringMap 功能简介 : 1.可设置Map中的Entry在一段时间后自动过期。 2.可设置Map最大容纳值,当到达Maxim…

后端技术杂谈4:Elasticsearch与solr入门实践

阮一峰:全文搜索引擎 Elasticsearch 入门教程 阅读 1093收藏 762017-08-23原文链接:www.ruanyifeng.com9月7日-8日 北京,与 Google Twitch 等团队技术大咖面对面www.bagevent.com 全文搜索属于最常见的需求,开源的 Elasticsearch …

第25章 JDBC核心技术第4节:操作BLOB类型字段

4.1 MySQL BLOB类型 MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。 插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。 MySQL的四种BLOB类…

Java学习个人总结

声明:个人原创,转载请在文章开头明显位置注明出处:https://www.cnblogs.com/sunshine5683/p/10063960.html 学习从来都是一个阶段的学习,然后进行整理与总结,最后才能形成自己的东西,今天将最近所学习的内容…

(翻译自用)TG^2———IJDAR杂志论文

TG2: 用于恢复文档可读性和感知质量的文本引导转换器GAN 摘要 大多数侧重于数字化文本文档恢复的图像增强方法仅限于文本信息仍保留在输入图像中的情况,而这种情况可能通常不是这样。在这项工作中,我们提出了一种新的生成性文档恢复方法,该…

基于Kubernetes/K8S构建Jenkins持续集成平台(一)

目录 Kubernetes实现Master-Slave分布式构建方案 传统Jenkins的Master-Slave方案的缺陷 KubernatesDockerJenkins持续集成架构图 KubernatesDockerJenkins持续集成方案好处 NFS简介 在Kubernetes安装Jenkins-Master 创建nfs-client-rbac 创建NFS client provisioner 创建 nfs…

中国汽水制造商市场趋势报告、技术动态创新及市场预测

汽水制造商市场的企业竞争态势 该报告涉及的主要国际市场参与者有SodaStream、Bonne、Flavorstation、Hamilton Beach、Drinkmate、iSODA、Cuisinart、Delight、Fizz Giz、Frostte、Jaybrake、KitchenAid、KOBWA、Leegoal、Lourdes、Lucky Sports、New、Primo Flavorstation、S…