Yolov5+Resnet+Flask实现唇语识别系统
分享源码
https://github.com/wjwzy/lip_reading
部分内容参考https://blog.csdn.net/weixin_42907473/article/details/103470208
目录
- 分享源码
- 1.摘要
- 2.项目流程
- 3.部分代码展示
- 3.1.代码结构
- 3.2.demo主程序
- 3.3.视频切帧
- 3.4.目标检测模块处理
- 3.5.图片裁剪
- 3.6.唇读推理模块预处理
- 3.7.模型预测
- 4.核心技术分析
- 4.1.数据分析
- 4.2.目标检测算法
- 4.3.分类网络
- 5.预处理trick
- 5.1.数据增广
- 5.2.帧数填充
- 6.效果展示
- 6.1.训练效果
- 6.2.页面展示效果
- 7.弱点分析
- 8.总结
1.摘要
项目主要针对基于视频的计算机唇读系统中唇部检测、唇读特征提取和唇语识别等关键技术进行了研究。具体来说,首先对数据进行预处理,包括对视频进行切帧和增广处理;然后采用Yolov5算法对唇部检测并截取有效区域进行后续处理;接着设计了一个新型网络用于唇部特征的提取和识别。该网络融合了3DResNet和GRU网络,能够同时利用视频数据的空间和时间信息,进而提取高效的特征获得较好的识别结果。最后,为了体现可视化和实用性,本文使用Flask框架实现了唇读系统的各个功能,可以在web端体验唇读系统的识别效果。
2.项目流程
研究的主要内容是对中文唇语词语的识别功能,研究的问题涉及到唇部定位、数据特征提取、网络对特征的预测结果以及web端实现前后端数据交互四个方面。而最为关键的,就在于特征提取以及预测结果两个方面,重点设计可行的深度学习方案,对比各种方法来研究出本文的最佳实现手段。对于模型的鲁棒性和泛化能力,项目需要大量而又无误的数据集支持,以及采用合适该数据集的网络模型,才能保证网络拥有强有力的表现能力。
在系统功能上,用户需要登录成功才能使用唇语识别功能,项目流程如图所示。
在技术路线上,第一个模块是目标检测,该模块需要准确的找到人脸的唇部位置,并且通过预测的坐标对图像进行切割,保证唇部位于图像的最中间位置,项目实现算法为Yolov5算法,采用最小的预训练模型进行训练。在目标检测数据集的制作中,需要保证数据的完整性,并且标注的嘴唇应该位于图像的最中间位置,达到唇部定位的效果,这样可以大程度加快后续分类网络的拟合速度。
第二模块采用的是3DResNet与GRU复合式网络,通过Yolov5算法处理过的数据传入该网络中,残差结构提取特征,GRU保证时序信息的传递与保存,再通过softmax得到预测的结果。在该模块中,训练数据的数量尤为关键,所以在预处理中,使用数据增广让网络有充足的数据训练。其次,网络的结构也非常重要,残差网络ResNet是由多层网络堆叠而成,解决网络深度造成的梯度消失问题,让网络更深,提取到的图像信息特征越多越有效。而循环神经网络RNN的变种体GRU则是通过了门的控制机制,使时序信息得到很好的保留,让神经网络更加关注的是时间序列的唇部动态变化信息。
预测结果最终传入web模块,依靠html和js完成前后端的交互,实现的系统的识别功能。在web模块中,所使用的框架是Flask框架,该框架优点就是轻巧灵活,在登录功能中html直接往后端提交表单,后端只要通过数据库对表单进行校验,就可以完成登录功能。在识别功能中,通过js配合html读取本地视频,再提交到后台进行处理,处理过程首先是经过视频切帧,然后Yolov5模型对帧数图像进行唇部坐标预测,再切割图像并保存,最后通过分类网络得到预测的结果,识别的词语展示到前端页面即可完成整个功能的流程,处理的流程如图所示。
项目采用的技术为当今最主流的one-stage目标检测算法Yolo,用来辅助残差网络ResNet对视频进行唇语翻译,该目标检测算法首次应用于唇语识别中,使系统达到端到端的识别效果。其次数据集是由多帧数图像组成单一样本,存在缺帧等问题,给项目带来了一定的难度。项目还采用了python轻量级web框架Flask,通过前端html和js的配合使用来操作深度学习算法,达到视觉上的展示效果,让用户可以使用网页端操作唇语识别系统。
3.部分代码展示
3.1.代码结构
项目由三部分构成,唇读模块、目标检测模块和web端demo模块,由于目标检测的模型路径问题,将demo和yolov5整合到了一个目录下。
3.2.demo主程序
post请求将前端读取的视频先保存至本地相应目录,再做后续相关操作。
@app.route('/predict', methods=['GET', 'POST'])
def predict():if request.method == 'POST':try:# 读取video文件f = request.files['file']# 保存前端读取的视频到uploadsbasepath = args.save_videofile_path = os.path.join(basepath, secure_filename(f.filename))f.save(file_path)img_list = video_to_frames(file_path)cut_img_list = cut_img(img_list)del img_listvocab_path = 'lip_models/vocab100.txt'# 载入网络进行预测result = model_predict(model, cut_img_list, vocab_path, args.device)result = str(result[0])print("识别结果:" + result)return resultexcept Exception as e:return "错误,无法正确识别"return None
3.3.视频切帧
切帧直接存入list返回
def video_to_frames(path):"""输入:path(视频文件的路径)"""# VideoCapture视频读取类# 抽取帧数videoCapture = cv2.VideoCapture()videoCapture.open(path)# 总帧数frames = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)img_list = []for i in range(int(frames)):ret, frame = videoCapture.read()if i % 4 == 0:img_list.append(frame)print("视频切帧完成!")return img_list
3.4.目标检测模块处理
重新构建一个类,将加载模型初始化,由于只有一个类别,因此classes为0,定义detect方法,传入参数为图像的list,返回结果为对应坐标的list。
class yolov5(object):def __init__(self,img_size = 416,weights = 'runs/train/exp/weights/best.pt',iou_thres = 0.45,conf_thres = 0.25,device = '0',classes = 0,agnostic_nms = False,augment = False):self.imgsz = img_sizeself.iou_thres = iou_thresself.conf_thres = conf_thresself.device = select_device(device)self.classes = classesself.agnostic_nms = agnostic_nmsself.augment = augment# Initializeset_logging()self.half = self.device.type != 'cpu' # half precision only supported on CUDA# Load modelself.model = attempt_load(weights, map_location=self.device) # load FP32 modeldef detect(self, source):stride = int(self.model.stride.max()) # model strideimgsz = check_img_size(self.imgsz, s=stride) # 检查图片的大小if self.half:self.model.half() # to FP16cudnn.benchmark = True # 设置True可以加速恒定图像大小的处理速度# Run inferenceif self.device.type != 'cpu':self.model(torch.zeros(1, 3, imgsz, imgsz).to(self.device).type_as(next(self.model.parameters()))) # run onceresult = []for img0 in source:imgsz = check_img_size(imgsz) # check img_sizeimg = letterbox(img0, imgsz, stride=32)[0]# Convertimg = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416img = np.ascontiguousarray(img)img = torch.from_numpy(img).to(self.device)img = img.half() if self.half else img.float() # uint8 to fp16/32img /= 255.0 # 0 - 255 to 0.0 - 1.0if img.ndimension() == 3:img = img.unsqueeze(0)# 获取模型预测pred = self.model(img, augment=self.augment)[0]# 使用NMS进行预测pred = non_max_suppression(pred, self.conf_thres, self.iou_thres, classes=self.classes,agnostic=self.agnostic_nms)# 过程检测for i, det in enumerate(pred): # 遍历预测框# 还原图像坐标值大小det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()result.append(det[0][:4].tolist())return result
3.5.图片裁剪
目标检测模块得到唇部坐标,然后裁剪保存至新的list中返回。
# 根据预测得到的坐标进行裁剪
def cut_img(img_list):# 进行目标检测得到坐标点result = yolov5_det.detect(img_list)cut_img_list = []for idx, image in enumerate(img_list):labels = result[idx]cropped = image[int(labels[1]): int(labels[3]), int(labels[0]):int(labels[2])]cut_img_list.append(cropped)print("嘴型检测并裁剪完成!")return cut_img_list
3.6.唇读推理模块预处理
def _sample(cut_img_list, bilater = True):data = []for img in cut_img_list:img = img_clip(img) # 缩放并填充至112大小if bilater and random.random() < 0.6:# 引入双边滤波去噪img = cv2.bilateralFilter(src=img, d=0, sigmaColor=random.randint(15, 30), sigmaSpace=15)# 归一化,转换数据类型 并限定上下界限的大小必须为fixed_sideimg = img.astype(np.float32)# 标准化处理img -= np.mean(img) # 减去均值img /= np.std(img) # 除以标准差data.append(img)return np.array(data)
3.7.模型预测
网络输出后获取最大值的下标,结合词表得到预测的唇读词语类别
def model_predict(model, cut_img_list, vocab_path, device):model.to(device)id2label = []with open(vocab_path, 'r', encoding='utf-8') as f:for word in f:id2label.append(word.split(',')[0])# 预处理test_data = process(cut_img_list)test_data = torch.tensor(padding_batch(test_data))print("数据预处理完成!")############################### 预测##############################pre_result = []with torch.no_grad():batch_inputs = test_data.to(device)logist = model(batch_inputs)pred = torch.argmax(logist, dim=-1).tolist()pre_result.append(id2label[pred[0]])return pre_result
4.核心技术分析
4.1.数据分析
在数据方面,项目使用的数据集是2019年“创青春·交子杯”新网银行高校金融科技挑战赛-AI算法赛道的唇语数据集,该数据集是只有图片帧的数据集,整份数据集是由9996份带标签训练样本和2504份无标签预测样本构成,标签文件为txt格式文件,一个样本文件名对应一个中文词语,存储量8GB左右。数据包含的唇语是两个字或者四个字的中文词语,它们的比例为6816:3180,总共有313个类别,除了其中的“落地生根”和“卓有成效”两个类是只有22个样本,其他类别均有32个样本。每个数据样本的帧数由2到24不等,平均帧数在8帧左右,分布比较均匀,图片内容基本都是人脸部的下半部分,如图所示。
图像色度和饱和度都没有太大差异,这样一定程度削减的干扰因素,方便网络能够学习更多的有效特征。
数据可以分为有用信息和无用信息,在这份数据里,开口状态即为有用信息,闭口则是无用信息。因此在数据处理过程,神经网络应该着重注意开口状态的特征,但唇语数据中唇形差异并不大,使得低层数的网络提取不到更多有效的特征,所以在主干网络的选取上为多层数的深度3D神经网络,以便提取更多维度的特征提供网络学习记忆。此外,时间序列的特征信息也尤为重要,仅靠3D网络往往不会有太好的效果,因此项目在分类网络结构中需要引入循环神经网络RNN,它能将最大限度的保留时序特征,非常符合网络对特征的需求。
4.2.目标检测算法
项目对比不同的目标检测算法进行唇部检测,yolov5s、Faster-RCNN、SSD300以及Yolov3-spp这些主流目标检测算法。不同算法与不同模型对同一份数据集的效果肯定都是不一样的,通过试验不同算法在数据集中都进行了不同程度的训练以及测试,整理出了每一个算法在AP-50精度、GPU推理速度、置信度以及模型存储空间四个方面上的性能分析,如表所示。
在项目设计中,目标检测模块需要的仅仅是推理速度上的高相应需求。在参考多份资料以及通过实验结果分析,最终将算法的选择上采取Yolov5算法。
切割目标后:
4.3.分类网络
项目经过几轮测试对比,网络最终修改为ResNet内嵌一层的GRU,同样形成CNN与RNN的复合式网络,但网络并不会单纯使用3D的卷积与池化的结构,因为在特征提取的过程中,更趋向于CNN来提取像素特征,让GRU来提取时间动态变化的特征。因此在残差模块中,卷积和池化将替换成2D操作,这一定程度上能避免时间维度带来的干扰。流程如图所示。
残差模块如下图所示。
由于网络处理的数据是由多帧图像构成的动态变化多维数据,如果仅仅采用3D卷积和池化等操作,会因为下采样过程中使得时间维度数据丢失。从数据集来说,每一个样本的帧数并不恒定,而且是从2帧到24帧不等,数据帧数平均在8帧左右,由于帧数过低,时间维度上的信息本身就存在过少状态。因此当采用3D的卷积与池化后,会进一步缩减该维度上的特征数据,所以网络最终会过分依赖图像的像素两个维度来进行强行拟合,这显然是不合理的。
当残差网络从3D的残差模块更换成2D之后,此时数据中的时间维度并不会进行下采样,所以该维度特征会得到一个很好的保留。所以,为了提取时间维度的特征信息,在网络经过线性全连接之后引入一层门控循环单元GRU,让GRU通过更新门和重置门来控制时间维度特征信息的关联性。在全连接层中,通过输出的特征向量与隐藏层形成线性全连接,使网络融合了残差模块的特征信息来自适应感受向量的临界点,以此来提高网络的自适应表现能力。具体来说就是在线性全连接层中的引入自适应词语边界,不让GRU输出的隐藏层向量直接连接分类层,而是将GRU的每个时间维度的输出连接到全连接层中,在做sotfmax之后再将时间维度相加,最后使得每个时间维度的输出都能为最后的分类层做出贡献,最大化的实现了网络多维度的特征融合。
5.预处理trick
项目选择了100个词语进行研究,也就是100个类别,每个类别32份样本,一份样本平均帧数8帧左右,因此总体数据量有100×32×8=25600张图片左右。
根据标签与文件名生成词表,根据词表的下标对应各个类别。
5.1.数据增广
在图片的预处理中,首先是将图片进行缩放填充至112的像素,并对所有图像进行镜像翻转的数据增强,并对所有图像进行60%概率的双边滤波去噪。如下图所示,a为原图,b是经过缩放、填充、双边滤波后的图像,可以发现相邻的像素变得更加平滑,唇部棱角变得比较立体,图像的阴影更少了,这样很大程度减少了噪声的干扰。c图是镜像翻转的增强图像,可以使数据得到扩充,将3200份样本扩充到6400份。
5.2.帧数填充
由于网络一直过拟合,通过观察数据集,发现这是由于数据集帧数不恒定而产生的。所以在分批次的时候,会产生同一批次帧数不一的情况,这种情况有可能使网络会被帧数的干扰而影响特征提取的效果。因此在预处理阶段,程序划分批次的时候,就需要对每个批次进行0填充再训练,也就是将批次中每个样本的帧数固定到样本最大值,批次中样本统一帧数的形式输入到网络中训练。
6.效果展示
6.1.训练效果
纯3DResnet18+预处理trick训练效果:
3DDensenet+LSTM+GRU+预处理trick训练效果:
3D+2D残差模块+GRU+预处理trick训练效果:
不同预处理手段对比:
6.2.页面展示效果
项目最终成品是页面测试离线视频,从切帧、目标定位切割、网络分类、页面展示结果。
点击Choose按钮选择本地离线视频,选择后出现Predict按钮,点击后进行视频处理,待网络处理完响应请求,并将结果展示至页面,如下图。
7.弱点分析
唇语识别功能的测试中,会存在一个低泛化问题,这是由于数据集产生的。首先数据集中的样本是制作方采样而成,当训练出一个损失低正确率高,并且整体测试集效果比较好的模型时,对自己录制的视频进行切帧并送入网络进行分类,会出现准确率低的情况,这很明显模型对于非数据集的测试样例预测的效果并不是特别好。而模型的泛化能力想要提升,就需要对训练的数据集进行调整,例如增加一些自己的图像,增大每个类别的样本数据,以此提高模型的各项综合能力。
除了泛化问题,还存在相似词语识别混淆问题。例如样本中“技术”和“基础”两个词语,它们之间存在高度相似的动态唇形,测试结果和预想的一样,模型有时会对类似词语无法正确地分类。如下图为系统对录制的“技术”、“基础”两个词语视频识别结果。
在上图中,a图为“技术”词语,b图为“基础”词语,但是网络识别结果却张冠李戴,将两词识别相互混淆。如下图为二词唇部定位切割后的帧数图,首先从唇形上来说二者差异并不大,唯一不同的仅仅是“术”字和“础”字发音时的嚼舌情况不同。然而网络目前仅仅是针对图像的技术处理,并未涉及高层次的语义分析,因此在遇到唇形相似的词语这种情况下,根本无法正确地分辨类别。
混淆词语唇形切割:
在所使用的数据集中,类别的样本数不够很大程度上导致了这种情况产生,不仅如此,唇语识别原本是一个句子输入的过程,前一个字与后一个字的关联性也取决了识别的准确率高低。因此,在现有的基础上要想提高识别效果,首先需要从数据集出发,将过低帧数的样本进行重新采样,抽取高帧数的数据集样本,提高数据集的质量与科学性。同时还需要对网络深度进行修改,增加网络计算参数,让特征在网络中更加细化。其次,应该在网络中引入注意力机制,让网络充分提取开口的像素特征,以及时间维度上帧与帧之间的联系。最后需要设计语义分析模块,将图像转化成语义再对其特征向量做分析处理,细化字与字之间的关联特征,并将数据映射到更高的维度上做到数据再分。
8.总结
针对web端操作下的唇语识别系统,本文主要是使用了两大主流深度学习算法部署到Flask框架的集成思想,对如下内容进行了研究应用:
(1)Yolov5算法对人脸进行唇部定位,采用预测的坐标对数据集进行处理,整理得到图像内容仅包含有效信息的数据集;
(2)在本文所使用的数据集中,对比了不同的目标检测算法与分类网络结构,通过实验数据分析来最终确定选用的算法和网络结构;
(3)设计3DResNet和GRU复合网络,利用2D的残差模块组成深度网进行提取特征,最后利用GRU将每个帧数映射到特征维度中,形成由批次、时序和图像像素的高维度特征信息,再经过全连接层和softmax层处理;
(4)整合两个算法到Flask框架中,这是唇语识别首次应用到web框架中,通过设计路由和URL地址,再配合视图函数对预测算法进行方法调用,让系统达到可视化效果;
(5)对视频流进行预测,充分利用3D模型的优点对唇语视频进行识别,从视频的读取到切帧,最后传入网络中对图像包含的唇语信息进行相关的解码,达到端到端的识别效果。
项目一直存在一些不足的地方,针对这些问题,能从以下方面进行优化:第一是泛化能力,项目后续应该从数据集从发,需要进行一次所有类别的数据采集,以此来扩充样本数目。同时,在网络层数上,可以适当进行加深,以此来增强网络的表现能力,让数据更加细分,模型能学习到更高维度的特征信息。第二是类别数目上,可以扩充至原数据集的313类,让项目能够识别更多的中文词语,让系统不受限于翻译的类别,让更多中文词语甚至短语能够正确的被识别。第三是响应时间里,模型有可能受电脑的硬件设备影响,也有可能是双网络的原因,导致处理时间过长,这应该是项目未来工作的重点研究对象,优化项目的各个细节,提升算法的执行能力。
此外,当前识别的仅仅是词语,真正的唇语识别应该是以句子的形式被翻译的,这就需要对视频进行语句判断,例如开口到闭口的停顿时长,是否可以利用这一点来做句子识别的突破口。在识别功能上,目前仅仅是读取离线视频识别,未来的优化方向也可以向实时视频识别进军,让整个项目更加的智能,更加人性化,攻克唇语识别的这个难题,为将来的唇语工作做出积极的贡献。
Yolov5+Resnet+Flask实现唇语识别系统相关推荐
- 唇语识别技术的开源教程,听不见声音我也能知道你说什么!
作者 | Amirsina Torfi.Seyed Mehdi Iranmanesh.Nasser M. Nasrabadi 译者 | 清爹 整理 | Jane 出品 | AI科技大本营 [导读]唇语 ...
- AI如何练就读唇术?唇语识别数据功不可没
所谓的"唇语识别",其实并不神秘. 早在古代,就有专门的唇语师存在.通过长期的训练,他们具备了"观察别人的嘴型,解读其表达语句"的能力.随着科技的发展,人工智能 ...
- 唇语识别真会是语言交互的终极战场?
文 | 夏汀 来源 | 智能相对论(aixdlun) 在今年的乌镇世界互联网大会上,搜狗展出了一项黑科技--唇语识别,12月14号搜狗在北京又公开演示了这项技术.作为行业领先的唇语识别系统,搜狗在非特 ...
- 从人脸识别到唇语识别,图像识别技术发展现状
"唇语识别研究的起源有一个故事.2006年世界杯上,马特拉齐好像说了一句话把齐达内惹怒了,然后齐达内就用头撞了马特拉齐.事后,大家都在猜他到底说了什么." 山世光 中 ...
- 史上最详细唇语识别数据集综述
更新:VIPL官网网页格式更改,导致旧的LRW1000链接无法访问,现已更新LRW1000数据集链接,内部包含申请需要的文件 推荐一个大佬的综述,关于实现唇语识别的多种途径. 说明:本文包括经常用语唇 ...
- 今日新出 CV 论文汇总(含医学图像、目标检测、唇语识别、SLAM等)
点击我爱计算机视觉标星,更快获取CVML新技术 最近,52CV分享了多篇CVPR 2019 的论文,有位群友问难道除了CVPR 就没有值得读的论文了吗?当然不是,其实很多优秀的工作并不一定出自CVPR ...
- 「唇语识别技术」看不透TA的心,但可以听懂TA的话
导读 唇语识别有着极长的历史.古代的唇语师通过长期的训练,具备了"观察别人的嘴型,解读其表达语句"的能力.在现代社会里,一些听力障碍者们也会使用这种技巧与他人交谈,补充听力器官的不 ...
- 清华大学团队研发出新颖唇语解读系统
文章目录 人说话时嘴唇动作跟语音同步,可以通过识别唇动来进行语言交流.对于声带.喉舌损伤的失声人群,唇语是一种不占用双手的.日常无障碍交流的有效方式.但唇语对讲话者友好,对解读唇语的听众来说却并不轻松 ...
- 唇语识别!AI 领域的下一个万亿市场?
英国查尔斯王子迎娶卡米拉时,读唇者成功破解了伊丽莎白二世与儿子的低语,让女王糟糕的婆媳关系浮现在大众眼前 -- 这可能是"唇语识别"第一次大面积走进大众的视野. 什么是唇语识别 所 ...
- 史上最详细唇语识别最新研究进展记录
本文是唇语识别近2年来最新的方法的记录,主要集中在中英文词级数据集如LRW,LRW-1000,英文句子级数据集如LRS2,英文短语级数据集如OuluVS2,以及其他一些数据集. 记录方法为1.简要翻译 ...
最新文章
- maven私服的配置使用
- TikTok英国市场你不能不知道的10大数据
- Elasticsearch技术解析与实战(四)shardreplica机制
- python自动化测试脚本可以测php吗_自动化测试,用Python还是Java?
- python查看关键字列表的命令是_Python 41 完整查询语句 和 一堆关键字
- 记录一些js面试题以及解法
- Robocode:下载安装及迁移至IntelliJ
- 细谈等级保护与ISO27000系列的区别与联系
- 【产品】 产品设计:ID工业设计、MD结构设计、HW硬件设计和SW软件设计详解
- sql删除元组_SQL笔记
- 查询加日期oracle,Oracle查询优化日期运算实例详解
- pandas批量处理体育成绩
- 狼行千里吃肉,马行千里吃草(我读了5遍,震撼了!)
- MySQL中show命令用法大全
- ATM自动取款机程序设计
- mysql 多表 left join_MySql left join 多表连接查询优化语句
- Eureka集群启动报错It seems to be a socket read timeout exception
- 如何快速有效的学习 Python ?阿里高级开发工程师给出建议
- Hibernate学习总结(5)——一对多的级联操作
- 推荐一位川大零基础转行 Python 的人生勇士
热门文章
- idea 打包不出现target的原因
- 计算机考研复试面试常问问题 数据结构篇(下)
- 解决 Oracle 密码过期 the password has expired
- java mockserver搭建_使用Moco搭建Mock Server教程
- golang微信小程序爬虫教程offer秀
- 操作系统概念之OSAL
- Django下载文件——三种方法和大文件下载
- java完成crm系统ppt,客户关系管理系统答辩稿.ppt
- cad批量打印快捷键_CAD布局批量打印必备工具之一
- 数字图像处理边缘检测算子matlab,使用roberts算子对图像进行边缘检测,并二值化的matlab代码实现...