基于百度语音识别API智能语音识别和字幕推荐系统——深度学习算法应用(含全部工程源码)+测试数据集

news2024/11/29 4:43:03

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
  • 模块实现
    • 1. 数据预处理
    • 2. 翻译
    • 3. 格式转换
    • 4. 音频切割
    • 5. 语音识别
    • 6. 文本切割
    • 7. main函数
  • 系统测试
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目基于百度语音识别API,结合了语音识别、视频转换音频识别以及语句停顿分割识别等多种技术,从而实现了高效的视频字幕生成。

首先,我们采用百度语音识别API,通过对语音内容进行分析,将音频转换成文本。这个步骤使得我们能够从语音中提取出有意义的文本信息。

其次,我们运用视频转换音频识别技术,将视频中的音频部分提取出来,并进行同样的文本识别操作。这样,我们就可以对视频中的声音内容进行准确的文字化。

另外,我们还引入了语句停顿分割识别,用于识别语音中的语句边界和停顿,从而更准确地切分出每个语句的内容。

综合上述技术,我们成功地实现了视频字幕的生成。通过对视频中的语音内容进行逐帧识别、转换和分割,我们能够准确地将语音内容转化为文本,并在视频上生成相应的字幕。

本项目不仅能够为视频内容提供字幕,也为内容创作者提供了方便,使得他们能够更好地将视频内容传达给观众。同时,这也为包括听障人士在内的用户提供了更友好的观看体验。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

在Windows环境下完成Python 3所需的配置,并运行代码即可。

模块实现

本项目包括7个模块:数据预处理、翻译、格式转换、音频切割、语音识别、文本切割和main函数,下面分别给出各模块的功能介绍及相关代码。

1. 数据预处理

基于百度语音API得到所需要的APP_IDAPI_KEYSECRET_KEY。进入百度语音官网地址为http://yuyin.baidu.com,在右上角单击“控制台”按钮,登录百度账号,如图所示。

在这里插入图片描述

在控制台左端单击“产品服务”-“语音技术”进入语音识别界面,如图所示。

在这里插入图片描述

进入后,可能会提示需要实名认证,填入相关信息,完成认证即可。

单击“创建应用”,根据需求填写项目名称、类型、所需接口、语音包名、应用描述等信息后即可创建成功,如图所示。

在这里插入图片描述

按下图,查看应用详情即可得到APP_IDAPI_KEYSECRET_KEY供后续调用,在此界面也可查看调用量限制等信息,如下两图所示。

在这里插入图片描述
在这里插入图片描述

注意:如果API接口状态为待开通付费的话,需要在左边“概览”页中,选择需要开通的API接口,进行开通。如下图所示。

在这里插入图片描述

本项目使用百度语音识别API接口,采用以下两种方法调用,最终采用后者。

(1) 下载使用SDK

根据pip工具使用pip install baidu-aip下载。

调用代码为:

from aip import AipSpeech
APP_ID = 'XXXXXXX'
API_KEY = '****************'
SECRET_KEY = '*********************'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
#读取文件
def get_file_content(file_path):
    with open(file_path, 'rb') as fp:
        return fp.read()
result=client.asr(get_file_content('test2.wav'),'wav',16000,{
    'dev_pid': 1537,
})
print(type(result))
print(result)

(2)不需要下载SDK

首先,根据文档组装.url获取token;其次,处理本地音频以JSON格式POST到百度语音识别服务器,获得返回结果。

#合成请求token的URL
    url = baidu_server + "grant_type=" + grant_type + "&client_id=" + client_id + "&client_secret=" + client_secret
   #获取token
    res = urllib.request.urlopen(url).read()
    data = json.loads(res.decode('utf-8'))
    token = data["access_token"]
    print(token)

下载配置所需要的库相关操作如下:

(1)安装moviepy库

moviepy用于视频编辑Python库:切割、拼接、标题插入、视频合成、视频处理。moviepy依赖库有numpy、imageio、decorator、 tqdm。

在cmd使用命令pip install moviepy安装moviepy库。

安装时可能存在的问题:发生报错导致下载安装停止时,查看报错信息可能为依赖库的缺失。

如Anaconda中的Python未安装tqdm发生报错,使用conda list查看确认缺失该库,可通过conda install tqdm下载安装,其他库缺失问题也可依照类似方法解决。

(2)安装js2py库

爬虫时很多网站使用js加密技术,js2py可以在Python环境下运行Java代码,摆脱Java环境的瓶颈。制作中英文字幕时,涉及百度语音识别英文输出,需将其翻译为中文,因此,安装is2py库 爬虫调用百度翻译的JavaScript脚本。

(3)安装pydub库

根据音频的静默检测语句停顿,进行合理断句识别,pydub库使用pip工具安装,在cmd命令行输入pip insall pydub

使用pydub)库 from pydub import AudioSegment, 验证安装是否成功可通过例程检测,若报错没有pydub库,则安装失败。

2. 翻译

将识别的英文结果使用爬虫调用百度翻译,得到对应的中文翻译。

class baidu_Translate():
    def __init__(self):
        self.js = js2py.eval_js('''
            var i = null;
            function n(r, o) {
                for (var t = 0; t < o.length - 2; t += 3) {
                    var a = o.charAt(t + 2);
                    a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
                    a = "+" === o.charAt(t + 1) ? r >>> a: r << a,
                    r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
                }
                return r
            }
            var hash = function e(r,gtk) {
                var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
                if (null === o) {
                    var t = r.length;
                   t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t /                     2) - 5, 10) + r.substr( - 10, 10))
                } else {
                    for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C =                          0, h = e.length, f = []; h > C; C++)"" !== e[C] && f.push.a                        pply(f, a(e[C].split(""))),C !== h - 1 && f.push(o[C]);
                    var g = f.length;
                    g > 30 && (r = f.slice(0, 10).join("")+f.slice(Math.floor(g/ 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice( - 10).join(""))
                }
                var u = void 0,
                u = null !== i ? i: (i = gtk || "") || "";
                for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d                           [1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
                    var A = r.charCodeAt(v);
                    128 > A ? S[c++] = A: (2048 > A ? S[c++] = A >> 6 | 192 : (55296 ===(64512 & A) && v + 1 < r.length && 56320 ===(64512&r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)), S[c++] = A >> 18 | 240, S[c++] = A >> 12 &63 | 128) : S[c++] = A >> 12 | 224,S[c++] = A >> 6 & 63 | 128), S[c++] = 63 & A | 128)
                }
                for (
                var p = m,F = "+-a^+6", D = "+-3^+b+-f", b = 0;
                b < S.length; b++) p += S[b],p = n(p, F);
                return p = n(p, D),
                p ^= s,
                0 > p && (p = (2147483647 & p) + 2147483648),
                p %= 1e6,
                p.toString() + "." + (p ^ m)
            }
        ''')
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36', }
             self.session = requests.Session()
             self.session.get('https://fanyi.baidu.com', headers=headers)
             response = self.session.get('https://fanyi.baidu.com', headers=headers)
             self.token = re.findall("token: '(.*?)',", response.text)[0]
             self.gtk = '320305.131321201'  # re.findall("window.gtk = '(.*?)';", response.text, re.S)[0]
    def translate(self, query, from_lang='en', to_lang='zh'):
        #语言检测
        self.session.post('https://fanyi.baidu.com/langdetect', data={'query':        query})
        #单击事件
        self.session.get('https://click.fanyi.baidu.com/?src=1&locate=zh&actio        n=query&type=1&page=1')
        #翻译
        data = {
            'from': from_lang,
            'to': to_lang,
            'query': query,
            'transtype': 'realtime',
            'simple_means_flag': '3',
            'sign': self.js(query, self.gtk),
            'token': self.token
        }
        response = self.session.post('https://fanyi.baidu.com/v2transapi', data=data)
        json = response.json()
        if 'error' in json:
            pass
            #return 'error: {}'.format(json['error'])
        else:
            return response.json()['trans_result']['data'][0]['dst']

3. 格式转换

百度语音识别API有严格的参数要求,使用moviepy库完成从视频中提取音频工作。

def separate_audio(file_path, save_path):  
#视频转音频,音频编码要求:.wav格式、采样率 16000、16bit 位深、单声道
    audio_file = save_path + '\\tmp.wav'
    audio = AudioFileClip(file_path)
    audio.write_audiofile(audio_file, ffmpeg_params=['-ar', '16000', '-ac', '1'], logger=None)
    return audio_file

4. 音频切割

使用pydub库,利用停顿时的音频分贝降低作为判定断句标准,设置停顿时的分贝阈值,拆分后的小音频不短于0.5s,不长于5s。

def cut_point(path, dbfs=1.25):    #音频切割函数
    sound = AudioSegment.from_file(path, format="wav")
    tstamp_list = detect_silence(sound, 600, sound.dBFS * dbfs, 1)
    timelist = []
    for i in range(len(tstamp_list)):
        if i == 0:
            back = 0
        else:
            back = tstamp_list[i - 1][1] / 1000
        timelist.append([back, tstamp_list[i][1] / 1000])
    min_len = 0.5  #切割所得音频不短于0.5s,不长于5s
    max_len = 5
    result = []
    add = 0
    total = len(timelist)
    for x in range(total):
        if x + add < total:
            into, out = timelist[x + add]
            if out-into>min_len and out-into<max_len and x + add +1 < total:
                add += 1
                out = timelist[x + add][1]
                result.append([into, out])
            elif out - into > max_len:
                result.append([into, out])
        else:
            break
    return result

5. 语音识别

调用百度语音识别API进行操作,填写申请App所得信息,上传待识别音频,进行中文或英文识别,返回所得文本。

class baidu_SpeechRecognition():   #调用百度语音识别API进行操作
    def __init__(self, dev_pid):
        Speech_APP_ID = '19712136'
        Speech_API_KEY = 'Loo4KbNtagchc2BLdCnHEnZl'
        Speech_SECRET_KEY = 'DO4UlSnw7FzpodU2G3yXQSHLv6Q2inN8'
        self.dev_pid = dev_pid
        self.SpeechClient = AipSpeech(Speech_APP_ID, Speech_API_KEY, Speech_SECRET_KEY)
        self.TranslClient = baidu_Translate()
    def load_audio(self, audio_file):    #读取加载音频文件
        self.source = AudioSegment.from_wav(audio_file)
    def speech_recognition(self, offset, duration, fanyi):    
#语音识别,根据要求的参数进行设置
        data = self.source[offset * 1000:duration * 1000].raw_data
        result = self.SpeechClient.asr(data, 'wav', 16000, {'dev_pid': self.dev_pid, })
        fanyi_text = ''
        if fanyi:  
            try:
                fanyi_text = self.TranslClient.translate(result['result'][0])  
#调用translate()函数,将识别文本翻译或直接输出
            except:
                pass
        try:
            return [result['result'][0], fanyi_text]   #返回所得文本
        except:
            #print('错误:',result)
            return ['', '']

6. 文本切割

断句,避免同一画面内出现过多文字影响观感,将38设为阈值,小于38时正常显示,大于则切割,分段显示。

def cut_text(text, length=38):  
 #文本切割,即断句,一个画面最多单语言字数不超过38,否则将多出的加入下一画面
    newtext = ''
    if len(text) > length:
        while True:
            cutA = text[:length]
            cutB = text[length:]
            newtext += cutA + '\n'
            if len(cutB) < 4:
                newtext = cutA + cutB
                break
            elif len(cutB) > length:
                text = cutB
            else:
                newtext += cutB
                break
        return newtext
    return text

7. main函数

让模块(函数)可以自己单独执行,构造调用其他函数的入口,设置简单的交互功能,用户根据需要选择语言类型、字幕类型以及是否将字幕直接加入视频中,并可观察当前工作进度、推算所需时间、文件格式错误时报错。

if __name__ == '__main__':
    def StartHandle(timeList, save_path, srt_mode=2, result_print=False):
        index = 0
        total = len(timeList)
        a_font = r'{\fn微软雅黑\fs14}'    #中、英字幕字体设置
        b_font = r'{\fn微软雅黑\fs10}'
        fanyi = False if srt_mode == 1 else True
        file_write = open(save_path, 'a', encoding='utf-8')
        for x in range(total):
            into, out = timelist[x]
            timeStamp=format_time(into - 0.2) +'--> '+ format_time(out- 0.2)
            result=baidufanyi.speech_recognition(into+0.1,out - 0.1, fanyi)
            if result_print:
                if srt_mode == 0:
                    print(timeStamp, result[0])
                else:
                    print(timeStamp, result)
            else:
                progressbar(total, x, '识别中...&& - {0}/{1}'.format('%03d' % (total), '%03d' % (x)), 44)
            #将切割后所得的识别文本结果按顺序写入,中、英、中英双语不同
            if len(result[0]) > 1:
                index += 1
                text = str(index) + '\n' + timeStamp + '\n'
                if srt_mode == 0:  # 仅中文
                    text += a_font + cut_text(result[1])
                elif srt_mode == 1:  # 仅英文
                    text += b_font + cut_text(result[0])
                else:  #中文+英文
                    text+=a_font+cut_text(result[1])+'\n'+b_font + result[0]
                text = text.replace('\u200b', '') + '\n\n'
                file_write.write(text)
        file_write.close()
        if not result_print:
            progressbar(total,total,'识别中...&&-{0}/{1}'.format('%03d'% (total), '%03d' % (total)), 44)
    os.system('cls')
    wav_path = os.environ.get('TEMP')
    #语音模型,1536为普通话+简单英文,1537为普通话,1737为英语,1637为粤语,1837川话,1936普通话远场
    pid_list = 1536, 1537, 1737, 1637, 1837, 1936
    #设置参数
    print('[ 百度语音识别字幕生成器 - by Teri ]\n')
    __line__print__('1 模式选择')
    input_dev_pid = input('请选择识别模式:\n'
                          '\n  (1)普通话,'
                          '\n  (2)普通话+简单英语,'
                          '\n  (3)英语,'
                          '\n  (4)粤语,'
                          '\n  (5)四川话,'
                          '\n  (6)普通话-远场'
                          '\n\n请输入一个选项(默认3):')
    __line__print__('2 字幕格式')
    input_srt_mode = input('请选择字幕格式:\n'
                           '\n  (1)中文,'
                           '\n  (2)英文,'
                           '\n  (3)中文+英文,'
                           '\n\n请输入一个选项(默认3):')
    __line__print__('3 实时输出')
    input_print = input('是否实时输出结果到屏幕? (默认:否/y:输出):').upper()
    #处理参数,根据用户输入给出相应参数
    dev_pid = int(input_dev_pid) if input_dev_pid else 3
    dev_pid -= 1
    srt_mode = int(input_srt_mode) if input_srt_mode else 3
    srt_mode -= 1
    re_print = True if input_print == 'Y' else False
    #输入文件
    __line__print__('4 打开文件')
    input_file = input('请拖入一个文件或文件夹并按回车:').strip('"')
    video_file = []
    if not os.path.isdir(input_file):
        video_file = [input_file]
    else:
        file_list = file_filter(input_file)
        for a, b in file_list:
            video_file.append(a + '\\' + b)
    #执行确认
    select_dev = ['普通话', '普通话+简单英语', '英语', '粤语', '四川话', '普通话-远场']
    select_mode = ['中文', '英文', '中文+英文']
    __line__print__('5 确认执行')
    input('当前的设置:\n识别模式: {0}, 字幕格式: {1}, 输出结果: {2}\n当前待处理文件 {3} 个\n请按下回车开始处理...'.format(
        select_dev[dev_pid],
        select_mode[srt_mode],
        '是' if re_print else '否',
        len(video_file)
    ))
    #批量处理,调用所设函数进行处理工作
    total_file = len(video_file)
    total_time = time.time()
    baidufanyi = baidu_SpeechRecognition(pid_list[dev_pid])
    for i in range(total_file):       #在所给文件范围内循环运行
        item_time = time.time()       #项目时间
        file_name = video_file[i].split('\\')[-1]
        print('\n>>>>>>>> ...正在处理音频... <<<<<<<<', end='')
        audio_file = separate_audio(video_file[i], wav_path)  #视频转音频
        timelist = cut_point(audio_file, dbfs=1.15)             #音频切割
        if timelist:
            print('\r>>>>>>>> 当前:{} 预计:{} <<<<<<<<'.format(
                '%03d' % (i),
                countTime(len(timelist) * 5, now=False)
            ))
            srt_name = video_file[i][:video_file[i].rfind('.')] + '.srt' 
            #根据时间将输出循环写入字幕文件
            baidufanyi.load_audio(audio_file)                 
            StartHandle(timelist, srt_name, srt_mode, re_print)
            print('\n{} 处理完成, 本次用时{}'.format(file_name, countTime(item_time)))
        else:
            print('音频参数错误')
    #执行完成,统计所用时间
    input('全部完成, 处理了{}个文件, 全部用时{}'.format(total_file, countTime(total_time)))
#本部分包括活动类、模块的相关函数、主函数代码
from moviepy.editor import AudioFileClip
from pydub import AudioSegment
from pydub.silence import detect_silence
from aip import AipSpeech
import os
import time
import re
import requests
import js2py
class baidu_Translate():
    def __init__(self):
        self.js = js2py.eval_js('''
            var i = null;
            function n(r, o) {
                for (var t = 0; t < o.length - 2; t += 3) {
                    var a = o.charAt(t + 2);
                    a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
                    a = "+" === o.charAt(t + 1) ? r >>> a: r << a,
                    r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
                }
                return r
            }
            var hash = function e(r,gtk) {
                var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
                if (null === o) {
                    var t = r.length;
                    t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr( - 10, 10))
                } else {
                    for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)"" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                    C !== h - 1 && f.push(o[C]);
                    var g = f.length;
                    g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice( - 10).join(""))
                }
                var u = void 0,
                u = null !== i ? i: (i = gtk || "") || "";
                for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
                    var A = r.charCodeAt(v);
                    128 > A ? S[c++] = A: (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)), S[c++] = A >> 18 | 240, S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224, S[c++] = A >> 6 & 63 | 128), S[c++] = 63 & A | 128)
                }
                for (
                var p = m,F = "+-a^+6", D = "+-3^+b+-f", b = 0;
                b < S.length; b++) p += S[b],p = n(p, F);
                return p = n(p, D),
                p ^= s,
                0 > p && (p = (2147483647 & p) + 2147483648),
                p %= 1e6,
                p.toString() + "." + (p ^ m)
            }
        ''')
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36', }
        self.session = requests.Session()
        self.session.get('https://fanyi.baidu.com', headers=headers)
        response = self.session.get('https://fanyi.baidu.com', headers=headers)
        self.token = re.findall("token: '(.*?)',", response.text)[0]
        self.gtk = '320305.131321201'  # re.findall("window.gtk = '(.*?)';", response.text, re.S)[0]
    def translate(self, query, from_lang='en', to_lang='zh'):
        #语言检测
        self.session.post('https://fanyi.baidu.com/langdetect', data={'query': query})
        #单击事件        self.session.get('https://click.fanyi.baidu.com/?src=1&locate=zh&action=query&type=1&page=1')
        #翻译
        data = {
            'from': from_lang,
            'to': to_lang,
            'query': query,
            'transtype': 'realtime',
            'simple_means_flag': '3',
            'sign': self.js(query, self.gtk),
            'token': self.token
        }
        response =self.session.post('https://fanyi.baidu.com/v2transapi', data=data)
        json = response.json()
        if 'error' in json:
            pass
            #return 'error: {}'.format(json['error'])
        else:
            return response.json()['trans_result']['data'][0]['dst']
class baidu_SpeechRecognition():
    def __init__(self, dev_pid):
        #百度语音识别API
        Speech_APP_ID = '19712136'
        Speech_API_KEY = 'Loo4KbNtagchc2BLdCnHEnZl'
        Speech_SECRET_KEY = 'DO4UlSnw7FzpodU2G3yXQSHLv6Q2inN8'
        self.dev_pid = dev_pid
        self.SpeechClient = AipSpeech(Speech_APP_ID, Speech_API_KEY, Speech_SECRET_KEY)
        self.TranslClient = baidu_Translate()
    def load_audio(self, audio_file):
        self.source = AudioSegment.from_wav(audio_file)
    def speech_recognition(self, offset, duration, fanyi):
        data = self.source[offset * 1000:duration * 1000].raw_data
        result = self.SpeechClient.asr(data, 'wav', 16000, {'dev_pid': self.dev_pid, })
        fanyi_text = ''
        if fanyi:
            try:
           fanyi_text = self.TranslClient.translate(result['result'][0])
            except:
                pass
        try:
            return [result['result'][0], fanyi_text]
        except:
            #print('错误:',result)
            return ['', '']
def cut_point(path, dbfs=1.25):
    sound = AudioSegment.from_file(path, format="wav")
    tstamp_list = detect_silence(sound, 600, sound.dBFS * dbfs, 1)
    timelist = []
    for i in range(len(tstamp_list)):
        if i == 0:
            back = 0
        else:
            back = tstamp_list[i - 1][1] / 1000
        timelist.append([back, tstamp_list[i][1] / 1000])
    min_len = 0.5
    max_len = 5
    result = []
    add = 0
    total = len(timelist)
    for x in range(total):
        if x + add < total:
            into, out = timelist[x + add]
       if out-into>min_len and out - into < max_len and x + add + 1 < total:
                add += 1
                out = timelist[x + add][1]
                result.append([into, out])
            elif out - into > max_len:
                result.append([into, out])
        else:
            break
    return result
def cut_text(text, length=38):
    newtext = ''
    if len(text) > length:
        while True:
            cutA = text[:length]
            cutB = text[length:]
            newtext += cutA + '\n'
            if len(cutB) < 4:
                newtext = cutA + cutB
                break
            elif len(cutB) > length:
                text = cutB
            else:
                newtext += cutB
                break
        return newtext
    return text
def progressbar(total, temp, text='&&', lenght=40):  #定义进度栏
    content = '\r' + text.strip().replace('&&', '[{0}{1}]{2}%')
    percentage = round(temp / total * 100, 2)
    a = round(temp / total * lenght)
    b = lenght - a
    print(content.format('■' * a, '□' * b, percentage), end='')
def format_time(seconds):  #定义时间格式
    sec = int(seconds)
    m, s = divmod(sec, 60)
    h, m = divmod(m, 60)
    fm = int(str(round(seconds, 3)).split('.')[-1])
    return "%02d:%02d:%02d,%03d" % (h, m, s, fm)
def separate_audio(file_path, save_path):  #定义音频间隔
    audio_file = save_path + '\\tmp.wav'
    audio = AudioFileClip(file_path)
    audio.write_audiofile(audio_file, ffmpeg_params=['-ar', '16000', '-ac', '1'], logger=None)
    return audio_file
def file_filter(path, alldir=False):  #定义文件过滤
    key = ['mp4', 'mov']
    if alldir:
        dic_list = os.walk(path)
    else:
        dic_list = os.listdir(path)
    find_list = []
    for i in dic_list:
        if os.path.isdir(i[0]):
            header = i[0]
            file = i[2]
            for f in file:
                for k in key:
                    if f.rfind(k) != -1:
                        find_list.append([header, f])
        else:
            for k in key:
                if i.rfind(k) != -1:
                    find_list.append([path, i])
    if find_list:
        find_list.sort(key=lambda txt: re.findall(r'\d+', txt[1])[0])
    return find_list
def countTime(s_time, now=True):  #定义累计时间
    if now: s_time = (time.time() - s_time)
    m, s = divmod(int(s_time), 60)
    return '{}分{}秒'.format('%02d' % (m), '%02d' % (s))
def __line__print__(txt='-' * 10):  #定义打印
    print('\n' + '-' * 10 + ' ' + txt + ' ' + '-' * 10 + '\n')
if __name__ == '__main__':  #主函数
    def StartHandle(timeList, save_path, srt_mode=2, result_print=False):
        index = 0
        total = len(timeList)
        a_font = r'{\fn微软雅黑\fs14}'
        b_font = r'{\fn微软雅黑\fs10}'
        fanyi = False if srt_mode == 1 else True
        file_write = open(save_path, 'a', encoding='utf-8')
        for x in range(total):
            into, out = timelist[x]
            timeStamp = format_time(into - 0.2) + ' --> ' + format_time(out - 0.2)
            result = baidufanyi.speech_recognition(into + 0.1, out - 0.1, fanyi)
            if result_print:
                if srt_mode == 0:
                    print(timeStamp, result[0])
                else:
                    print(timeStamp, result)
            else:
            progressbar(total, x, '识别中...&& - {0}/{1}'.format('%03d' % (total), '%03d' % (x)), 44)
            if len(result[0]) > 1:
                index += 1
                text = str(index) + '\n' + timeStamp + '\n'
                if srt_mode == 0:  #仅中文
                    text += a_font + cut_text(result[1])
                elif srt_mode == 1:  #仅英文
                    text += b_font + cut_text(result[0])
                else:  #中文+英文
       text += a_font + cut_text(result[1]) + '\n' + b_font + result[0]
                text = text.replace('\u200b', '') + '\n\n'
                file_write.write(text)
        file_write.close()
        if not result_print:
         progressbar(total, total, '识别中...&& - {0}/{1}'.format('%03d' % (total), '%03d' % (total)), 44)
    os.system('cls')
    wav_path = os.environ.get('TEMP')
    #语音模型
    pid_list = 1536, 1537, 1737, 1637, 1837, 1936
    #设置参数
    print('[ 百度语音识别字幕生成器 - by 谷健&任家旺 ]\n')
    __line__print__('1 模式选择')
    input_dev_pid = input('请选择识别模式:\n'
                          '\n  (1)普通话,'
                          '\n  (2)普通话+简单英语,'
                          '\n  (3)英语,'
                          '\n  (4)粤语,'
                          '\n  (5)四川话,'
                          '\n  (6)普通话-远场'
                          '\n\n请输入一个选项(默认3):')
    __line__print__('2 字幕格式')
    input_srt_mode = input('请选择字幕格式:\n'
                           '\n  (1)中文,'
                           '\n  (2)英文,'
                           '\n  (3)中文+英文,'
                           '\n\n请输入一个选项(默认3):')
    __line__print__('3 实时输出')
    input_print = input('是否实时输出结果到屏幕? (默认:否/y:输出):').upper()
    #处理参数
    dev_pid = int(input_dev_pid) if input_dev_pid else 3
    dev_pid -= 1
    srt_mode = int(input_srt_mode) if input_srt_mode else 3
    srt_mode -= 1
    re_print = True if input_print == 'Y' else False
    #输入文件
    __line__print__('4 打开文件')
    input_file = input('请拖入一个文件或文件夹并按回车:').strip('"')
    video_file = []
    if not os.path.isdir(input_file):
        video_file = [input_file]
    else:
        file_list = file_filter(input_file)
        for a, b in file_list:
            video_file.append(a + '\\' + b)
    #执行确认
    select_dev = ['普通话', '普通话+简单英语', '英语', '粤语', '四川话', '普通话-远场']
    select_mode = ['中文', '英文', '中文+英文']
    __line__print__('5 确认执行')
    input('当前的设置:\n识别模式: {0}, 字幕格式: {1}, 输出结果: {2}\n当前待处理文件 {3} 个\n请按下回车开始处理...'.format(
        select_dev[dev_pid],
        select_mode[srt_mode],
        '是' if re_print else '否',
        len(video_file)
    ))
    #批量处理
    total_file = len(video_file)
    total_time = time.time()
    baidufanyi = baidu_SpeechRecognition(pid_list[dev_pid])
    for i in range(total_file):
        item_time = time.time()
        file_name = video_file[i].split('\\')[-1]
        print('\n>>>>>>>> ...正在处理音频... <<<<<<<<', end='')
        audio_file = separate_audio(video_file[i], wav_path)
        timelist = cut_point(audio_file, dbfs=1.15)
        if timelist:
            print('\r>>>>>>>> 当前:{} 预计:{} <<<<<<<<'.format(
                '%03d' % (i),
                countTime(len(timelist) * 5, now=False)
            ))
            srt_name = video_file[i][:video_file[i].rfind('.')] + '.srt'
            baidufanyi.load_audio(audio_file)
            StartHandle(timelist, srt_name, srt_mode, re_print)
            print('\n{} 处理完成, 本次用时{}'.format(file_name, countTime(item_time)))
        else:
            print('音频参数错误')
    #执行完成
    input('全部完成, 处理了{}个文件, 全部用时{}'.format(total_file, countTime(total_time)))

系统测试

运行Python代码,根据提示进行交互选择。选择待识别视频语言,如图1所示;选择需要的字幕语言,如图2所示。

在这里插入图片描述

图1 待识别视频

在这里插入图片描述

图2 字幕语言

选择是否实时输出字幕结果,选择文件路径: (需要在英文输入法下使用双引号)确认需求,如图所示。

在这里插入图片描述

本次运行的设置:

识别模式英语(3),字幕格式为中文+英文(3)是否实时输出字幕为(y) 。结果:实时查看字幕输出,如图所示。

在这里插入图片描述

生成.srt字幕文件,如图所示。

在这里插入图片描述

在播放器中选择打开或关闭字幕,当生成多个字幕文件(如英文/中文/英文+中文)时也可在播放器中设置更换字幕文件。

使用记事本打开字幕文件,如图所示。

在这里插入图片描述

查看字幕文件加入视频的效果,原无字幕视频,如图所示。

在这里插入图片描述

加入生成字幕后的视频,如图所示。

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

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

相关文章

从数据仓库到数据结构:数据架构的演变之路

在上个世纪&#xff0c;从电子商务巨头到医疗服务机构和政府部门&#xff0c;数据已成为每家组织的生命线。有效地收集和管理这些数据可以为组织提供宝贵的洞察力&#xff0c;以帮助决策&#xff0c;然而这是一项艰巨的任务。 尽管数据很重要&#xff0c;但CIOinsight声称&…

【C++】AVL树模拟实现插入功能

AVL树模拟实现插入 前言正式开始树节点树insert旋转左单旋右单旋左右双旋右左双旋 用旋转来平衡树测试 前言 本篇主要介绍AVL树的插入功能。其中就包含了最重要的旋转。 通过旋转来使得树平衡&#xff0c;是学习AVL树的一个重点&#xff0c;也是也是一个难点。 正式开始 先…

虹科方案 | 汽车总线协议转换解决方案

汽车总线&#xff1a; 汽车总线是一种用于在车辆电子系统中传输数据和控制信息的通信系统。它允许不同的电子控制单元&#xff08;ECU&#xff09;在车辆中相互通信&#xff0c;协调各个系统的操作&#xff0c;以实现功能的集成和协同工作。 在现代汽车中&#xff0c;综合通信…

提高办案效率:公检系统引入自动校对技术

引入自动校对技术到公检系统中可以有效提高办案效率。自动校对技术结合公检系统的特点&#xff0c;可以在以下方面提高办案效率&#xff1a; 1.节省时间&#xff1a;自动校对技术可以快速检测和修正法律文书中的语法、拼写和标点符号等错误。与手动校对相比&#xff0c;自动校对…

dfs+回溯做题笔记

题目链接&#xff1a;t矩阵中的路径_牛客题霸_牛客网 参考代码&#xff1a; import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** * param matrix char字符型二维数组 * param …

虹科方案 | 汽车总线协议转换解决方案(二)

上期说到&#xff0c;虹科的PCAN-LIN网关在CAN、LIN总线转换方面有显著的作用&#xff0c;尤其是为BMS电池通信的测试提供了优秀的解决方案。假如您感兴趣&#xff0c;可以点击文末相关链接进行回顾&#xff01; 而今天&#xff0c;虹科将继续给大家带来Router系列在各个领域的…

个推消息推送专项运营提升方案,基于AIGC实现推送文案智能生成

个推消息推送专项运营提升方案自今年3月份发布以来&#xff0c;已应用于游戏社交、影音资讯、电商购物等多个行业。现个推消息推送专项运营提升方案又实现了推送策略的智能化和推送流程的自动化&#xff0c;助力APP进一步提升消息推送的效率和效果。 丰富推送策略组合&#xf…

Tomcat10.1源码安装与部署

安装JDK 1、下载jdk17 [rootmysql80 ~]# wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz[rootmysql80 ~]# ll -h jdk-17_linux-x64_bin.tar.gz -rw-r--r--. 1 root root 174M Mar 18 03:53 jdk-17_linux-x64_bin.tar.gz2、安装目录[rootmysql8…

第三方电容笔怎么样?apple pencil的平替笔

在当今世界&#xff0c;高科技已经成为推动电子产品迅速发展的重要动力。无论是工作&#xff0c;还是学习&#xff0c;iPad平板都很方便。iPad平板电脑将会和我们的生活联系在一起&#xff0c;不管是现在还是未来。iPad配上一支简单的电容笔&#xff0c;不仅提高了工作效率&…

数据库管理-第九十七期 以一当十的数据库路线(20230810)

第九十七期 以一当十的数据库路线&#xff08;20230810&#xff09; 距离上一期已经过去了整整9天了&#xff0c;相较于前几个月的“生产队的驴”&#xff0c;确实慢了很多&#xff0c;归根结底有几点&#xff1a;一是19c OCM的相关内容暂时告一段落&#xff0c;少了一半内容&…

从NPM注册中心获取包

目录 1、搜索和选择要下载的包 1.1 为什么使用 1.2 工作原理 1、质量 2、维护 3、受欢迎程度 4、名气 1.1、开始搜索包 2、在本地安装下载和安装软件包 2.1 安装未限定作用域的包 2.2 安装有作用域的公共包 2.3 安装私有包 2.4 测试包安装 2.5 已安装的软件包版本…

LeetCode算法递归类—两两交换链表中的节点

目录 24. 两两交换链表中的节点 题解&#xff1a; 代码&#xff1a; 运行结果&#xff1a;​编辑 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节…

线程池工作原理深入解析

目录 1. 线程正常的生命周期 2. 为什么要用线程池&#xff1f; 3. 线程池的核心原理 4. 怎样创建线程池&#xff1f; 5.线程池的代码实现 6. ThreadPoolExecutor 源码分析 7. ThreadPoolExecutor 工作原理展示&#xff08;重点&#xff09; 1. 线程正常的生命周期 我们知…

Pyinstaller 打包 django 项目如何将命令行参数加入?

起因 Pyinstaller 打包 django 项目&#xff0c;打包成 manage.exe 后用命令行 cmd manage.exe runserver 0.0.0.0:8001 --noreload 来运行感觉很不方便。 希望能够直接把命令行参数也打包进去&#xff0c;直接运行 exe 。我走了些弯路&#xff0c;但最终实现了。 弯路 我看…

Linux —— 基础I/O

一&#xff0c;背景介绍 狭义的文件存放在磁盘上&#xff0c;广义上在Linux下一切皆文件&#xff1b;磁盘上的文件一般为永久存储的外设&#xff0c;本质上对文件的操作&#xff0c;即为对外设的输入和输出&#xff08;简称I/O&#xff09;&#xff1b;空文件并不是不占磁盘文件…

Xamarin.Android实现手写板的功能

目录 1、背景说明2、实现效果3、代码实现3.1 整体思路3.2 核心绘画类-PaintView.cs3.3 对话框类-WritePadDialog.cs3.4 前端实现类-MainActivity3.5 布局文件3.5.1 write_pad.xml3.5.2 activity_main布局文件 4、知识总结5、代码下载6、参考资料 1、背景说明 在实际使用过程中…

【动态规划刷题 6】 买卖股票的最佳时机含冷冻期 买卖股票的最佳时机含手续费

买卖股票的最佳时机含冷冻期 链接: 买卖股票的最佳时机含冷冻期 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。​ 设计一个算法计算出最大利润。在满足以下约束条件下&#xff0c;你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票…

【赠书活动|第四期《互联网广告系统:架构、算法与智能化》】

文章目录 内容简介作者简介读者对象大咖推荐抽奖方式 广告平台的建设和完善是一项长期工程。例如&#xff0c;谷歌早于2003年通过收购Applied Semantics开展Google AdSense 项目&#xff0c;而直到20年后的今天&#xff0c;谷歌展示广告平台仍在持续创新和提升。广告平台是负有…

2024软考系统架构设计师论文写作要点

一、写作注意事项 系统架构设计师的论文题目对于考生来说&#xff0c;是相对较难的题目。一方面&#xff0c;考生需要掌握论文题目中的系统架构设计的专业知识;另一方面&#xff0c;论文的撰写需要结合考生自身的项目经历。因此&#xff0c;如何将自己的项目经历和专业知识有机…

内网穿透:实现公网访问内网群晖NAS的方法

公网远程访问内网群晖NAS 7.X版 【内网穿透】 文章目录 公网远程访问内网群晖NAS 7.X版 【内网穿透】前言1. 在群晖控制面板找到“终端机和SNMP”2. 建立一条连接公网数据隧道3. 获取公网访问内网群晖NAS的数据隧道入口 前言 群晖NAS作为应用较为广泛的小型数据存储中心&#…