本文正在参加THCHS-30、Aishell、LibriSpeech等。但是很多的国家地区的开源语料库却很少,比如:巴基斯坦、巴西、重庆话等。首先对产生这种问题的原因进行简单的分析:语料库需要很大的人力成本需要专人去录制和标注,一般大点的语料库都是上千小时非常费时费力。那作为一个底层人员咱没钱又想整个稍微靠谱点的地方方言语料库咋整呢?
方法&思路
我就简单的构思了一下,这不短视频时代的到来了吗?Tiktok、抖音、B站等一系列短视频平台都有各种地方人群发布地方方言视频并且配字幕的。我就琢磨啊,一个视频里面字幕也有音频也有我是不是可以从里面把这个东西弄出来?说干就干,下面是我不成熟的思路:
1. 我的目标:获取字幕和对应音频
2. 判断音频开始和结束,一般一个视频的音频和字幕为了让观众看的顺畅,在时间上都是有对应关系。我只需要判断相同字幕开始视频帧和结束视频帧就ok了。
3. 字幕识别这个就是一个OCR(Optical Character Recognition,光学字符识别),简单来说就是在视频帧上面找字然后转录成文字。
4. 最后把得到的字幕保存在抄本(Transcript.txt)文件里面,其他的以.wav形式保存
上面这个图就是大概的思路图。
实现代码
头文件导入:给大家解释一下我用的这个ocr是啥,这个是来自github上的一个开源OCR代码,这里是链接。环境要是不会搭建的话,下期再出个环境搭建。
import os
from ocr import ocr
import time
import cv2
import tqdm
from moviepy.editor import *
视频流处理代码:这里的代码是识别每一帧的字幕,但是只保存不同文字的字幕,同时返回一帧所占时长T、字幕帧序号 time_index以及字幕data。
def video_proc(video_path):
cap = cv2.VideoCapture(video_path)
fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频帧率
data = [] # 保存字幕
time_index = [] #
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 视频帧长
print('帧长:', frame_count)
for i in tqdm.tqdm(range(frame_count)): # 遍历视频所有帧
ret, frame = cap.read() # 读取每一帧,返回ret=True;frame=帧
# 当帧为Nonetype 就是没得视频的时候就结束
if frame is None:
break
result, image_framed = ocr(frame) # 读取帧中的中英文字
if result != {}: # {}这个符号就是代表了空字典
time_index.append(i + 1)
for key in result: # 遍历字典获取结果
caption = result[key][1]
if caption not in data:
data.append(caption)
cap.release() # 释放摄像头
T = 1/fps # 获取每一帧单位时间(s)
return data, time_index, T
视频裁剪以及音频转换代码:这里的代码就是以字幕帧序号 time_index转变得到的时间戳time_Stamp、视频保存路径video_path和声音存储路径voice_dir作为输入,最后得到分离后的音频文件。
def video_clip(video_path, voice_dir, time_Stamp):
print('正在生产音频数据...')
for key in time_Stamp:
voice_name = key+'.wav' # 音频名字
video = VideoFileClip(video_path).subclip(time_Stamp[key][0], time_Stamp[key][1])
audio = video.audio
voice_path = os.path.join(voice_dir, voice_name) # 保存音频文件路径
audio.write_audiofile(voice_path) # 写入一个音频文件
抄本生成代码:这里就是生成字幕文件的地方,因为作为抄本需要音频名字和内容有一一对应关系,所以里面的内容是音频文件名1 字幕1n 音频文件名2 字幕2n…的形式。
def trans_txt_generate(caption_data, voice_dir, time_Stamp):
txt_name = 'transcript.txt'
txt_path = os.path.join(voice_dir, txt_name)
f = open(txt_path, 'a+')
i = 0
print('正在生成文本数据...')
for key in time_Stamp:
content = key + ' ' + caption_data[i] + 'n'
f.write(content)
i += 1
f.close()
最后的执行代码
if __name__ == '__main__':
t = time.time() # 开始时间
video_path = '44.mp4'
voice_dir = './test_dataset'
caption_data, wrd_time_index, T = video_proc(video_path)
print(caption_data)
print('时间序号:', wrd_time_index)
time_Stamp = {} # 保存时间戳
left = wrd_time_index[0]
for i in range(1, len(wrd_time_index)):
sub = wrd_time_index[i]-wrd_time_index[i-1]
if sub != 1:
right = wrd_time_index[i-1]
time_Stamp['time_stamp%d' % (i+1)] = (left*T, right*T)
left = wrd_time_index[i]
video_clip(video_path, voice_dir, time_Stamp) # 裁剪视频并保存音频
trans_txt_generate(caption_data, voice_dir, time_Stamp) # 获取文本数据
print('空白时间戳', time_Stamp)
# print('时间序号长度:', len(tmp_time_index))
print('总共用时:', time.time()-t) # 总共用时
总结
我这个不成熟的想法其实还有很多吐槽的地方,比如:视频获取得到应该一样的字幕的那段时间,可能他们每一帧字幕不一样。产生的原因:可能是ocr识别准确度不太行(识别错)、视频本身的视频帧有问题。以后估计还会改进吧。文章最后求过免费的赞吧🥺🥺