目次
序文
このプロジェクトは、Baidu 音声認識 API に基づいて、音声認識、ビデオ変換音声認識、文ポーズ分割認識などのさまざまなテクノロジーを組み合わせて、効率的なビデオ字幕生成を実現します。
まず、Baidu Speech Recognition API を使用して音声の内容を分析し、音声をテキストに変換します。このステップにより、音声から意味のあるテキスト情報を抽出できるようになります。
次に、ビデオ変換音声認識技術を使用してビデオの音声部分を抽出し、同じテキスト認識操作を実行します。このようにして、ビデオ内の音声コンテンツを正確にテキスト化できます。
さらに、各文の内容をより正確にセグメント化するために、文の境界と音声のポーズを識別するために使用される文ポーズセグメンテーション認識も導入します。
以上の技術を組み合わせることで、ビデオ字幕の生成を実現することに成功しました。ビデオ内の音声コンテンツをフレームごとに認識、変換、セグメント化することで、音声コンテンツを正確にテキストに変換し、対応する字幕をビデオ上に生成できます。
このプロジェクトは、ビデオコンテンツに字幕を提供するだけでなく、コンテンツ制作者がビデオコンテンツをより視聴者に伝えることができる利便性を提供します。同時に、これにより、聴覚障害者を含むユーザーにとって、よりフレンドリーな視聴体験が提供されます。
全体的なデザイン
システムの全体構成図とシステムフローチャートを記載します。
システム全体構成図
システムの全体構成を図に示します。
システムフローチャート
システムフローを図に示します。
動作環境
Windows 環境で Python 3 に必要な構成を完了し、コードを実行します。
モジュールの実装
このプロジェクトにはデータ前処理、翻訳、フォーマット変換、音声切り取り、音声認識、テキスト切り取り、関数の7つのモジュールが含まれており、main
各モジュールの機能紹介と関連コードは以下の通りです。
1. データの前処理
Baidu Speech API に基づいて必要なAPP_ID
、API_KEY
、を取得しますSECRET_KEY
。図に示すように、Baidu Voice の公式 Web サイトhttp://yuyin.baidu.comにアクセスし、右上隅の [コンソール] ボタンをクリックして、Baidu アカウントにログインします。
図に示すように、コンソールの左端にある [Product Service] - [Speech Technology] をクリックして、音声認識インターフェイスに入ります。
入力後、実名認証が必要になる場合がありますので、必要事項を入力し、認証を完了してください。
「アプリケーションの作成」をクリックし、必要に応じてプロジェクト名、タイプ、必要なインターフェース、音声パッケージ名、アプリケーションの説明などの情報を入力すると、図のように作成が成功します。
次の図をクリックすると、後続のコールのAPP_ID
、API_KEY
、およびを取得SECRET_KEY
するためのアプリケーションの詳細が表示されます。このインターフェイスでは、次の 2 つの図に示すように、コールの制限などの情報も表示できます。
注: API インターフェースのステータスがアクティブ化保留中の場合は、左側の「概要」ページでアクティブ化する API インターフェースを選択し、アクティブ化する必要があります。以下に示すように。
このプロジェクトでは、Baidu Speech Recognition API インターフェイスを使用します。これは次の 2 つのメソッドによって呼び出され、最終的に後者が使用されます。
(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 をアセンブルしてトークンを取得し、次にローカル音声を処理し、JSON 形式で Baidu 音声認識サーバーに 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
View を使用してライブラリが見つからないことを確認し、conda install tqdm
ダウンロードしてインストールできます。他のライブラリが見つからない問題も同様の方法で解決できます。
(2) js2pyライブラリをインストールする
クロールの際、多くの Web サイトでは js 暗号化テクノロジが使用されており、js2py は Python 環境で Java コードを実行して、Java 環境のボトルネックを取り除くことができます。中国語と英語の字幕を作成する場合、Baidu 音声認識の英語出力が含まれるため、これを中国語に翻訳する必要があるため、Baidu 翻訳の JavaScript スクリプトを呼び出すための is2py ライブラリ クローラーをインストールします。
(3) pydubライブラリをインストールする
音声の無音に応じて、文の一時停止を検出し、適切な文認識を実行します。pydub ライブラリは、pip ツールを使用してインストールされ、cmd コマンド ラインに入力されますpip insall pydub
。
pydub) ライブラリを使用して、from pydub import AudioSegment
日常的な検出によってインストールが成功したかどうかを確認します。エラーが報告され、pydub ライブラリがない場合、インストールは失敗します。
2. 翻訳
クローラーを使用して Baidu Translate を呼び出し、認識された英語の結果に対して対応する中国語翻訳を取得します。
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. フォーマット変換
Baidu 音声認識 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.5 秒以上 5 秒以下でなければなりません。
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. 音声認識
Baidu Speech Recognition API を呼び出して操作し、アプリの申請で取得した情報を入力し、認識する音声をアップロードし、中国語または英語の認識を実行して、取得したテキストを返します。
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.メイン機能
モジュール(関数)を独立して実行したり、他の関数を呼び出すための入り口を構築したり、簡単なインタラクティブ関数を設定したりすることができ、ユーザーは必要に応じて言語の種類、字幕の種類、ビデオに直接字幕を追加するかどうかを選択でき、現在の作業の進捗状況を観察し、結果を計算するのに時間がかかり、ファイル形式が間違っている場合はエラーが報告されます。
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 に示すように、必要な字幕言語を選択します。
図に示すように、字幕結果をリアルタイムで出力するかどうかを選択し、ファイル パスを選択します: (英語の入力方法では二重引用符を使用する必要があります)。要件を確認します。
この実行の設定:
認識モードは英語 (3)、字幕形式は中国語 + 英語 (3) リアルタイムで字幕を出力するかどうか (y)。結果: 図に示すように、リアルタイムで字幕出力が表示されます。
図に示すように、.srt 字幕ファイルを生成します。
プレーヤーの字幕のオン/オフを選択します。複数の字幕ファイル (英語/中国語/英語+中国語など) を生成する場合、プレーヤーで字幕ファイルを設定して置き換えることもできます。
図のように、メモ帳で字幕ファイルを開きます。
図に示すように、ビデオ (字幕のない元のビデオ) に字幕ファイルを追加した効果を確認します。
図に示すように、字幕を生成した後にビデオを追加します。
プロジェクトのソースコードのダウンロード
詳細については、ブログ リソースのダウンロード ページをご覧ください。
その他の情報ダウンロード
人工知能関連の学習ルートと知識システムについて学び続けたい場合は、私の他のブログ「重い | 完全な人工知能 AI 学習 - 基本知識学習ルート、すべての資料は料金を支払わずにネットワーク ディスクから直接ダウンロードできます」を参照してください。 「ルーチンへの注意」
このブログでは、Github の有名なオープンソース プラットフォーム、AI テクノロジー プラットフォーム、および関連分野の専門家 (Datawhale、ApacheCN、AI Youdao、Huang Haiguang 博士など) について言及しています。関連資料は約 100G あります。友達全員を助けてください。