概述
趁空闲时间,记录一下做过的一个实验室项目,主要分为4个部分:1)语音转文字;2)人脸识别;3)行人识别;4)检索。本人负责人脸识别和检索模块及整体项目的融合,在此介绍一下自己所做的两个模块。
背景
对于现今摄像录影众多的情况,想了解一个人是否在某个时间段内出现过以及出现的时间等信息,以往需要大量的人力去查找。针对于这个问题,我们开发了一个人脸检索系统,可以快速的定位到此人是否出现,出现在什么时候等信息,以此来解决需要耗费大量人力的问题。
大体流程
- 使用opencv读取视频,每隔25帧进行一次人脸特征提取(视频帧数为25,如果每帧都处理不是很合理,1是会出现很多重复的人脸,2是人脸识别算法fps速度不够,会产生卡顿)
- 使用人脸检测算法对视频帧进行检测及提取人脸特征
- 使用Faiss索引库构对提取到的人脸特征加入索引构建特征数据库
- 使用Flask框架实现前后端的交互传输
相关技术
1. 人脸识别算法
项目中尝试了Opencv、Dlib、Mtcnn+FaceNet的算法,最后选定了Mtcnn+FaceNet算法,优势是在小脸和侧脸方面检测更优。
Mtcnn【输入:图片帧;输出:检测到的人脸框、置信分数、5个关键点位置】
FaceNet【输入:160x160大小的人脸图片(按Mtcnn检测到的人脸框裁剪,根据关键点进行人脸对齐,再resize成160x160大小);
输出:人脸特征(128维)】
1.1 Mtcnn算法
参考:Mtcnn详解
mtcnn网络主要分为4个阶段:图像金字塔、PNet、RNet、ONet
- 图像金字塔:
输入一张图片,将图片resize到500,然后按照factor = 0.709依次缩小裁剪至图片大小为12,将所有图片保存
- PNet:
针对每一张图片,依次输入PNet,输出很多个粗略的候选框(每个框有位置信息还有置信分数),将每个图片的候选框合并,然后进行NMS算法,得到一些粗略的proposal
- RNet:
将PNet得到的proposal裁剪并resize成24x24大小,输入Rnet,然后进行NMS,得到较准确的rois(位置和分数)【RNet的NMS阈值设置为0.3,只剩下少了的rois了】
- ONet:
将RNet得到的较准Rois裁剪并resize成48x48大小,输入ONet,然后进行NMS,得到最终的rois,即rectangles。
【len(rectangles) 的个数为检测到的人脸数,len(rectangles[0])为15,4:框的位置坐标,1:置信分数,10:5个关键点的坐标】
1.2 FaceNet算法
根据Mtcnn的输出结果,在原图片上进行裁剪人脸,并进行人脸对齐矫正,随后使用FaceNet算法的backbone对裁剪后的人脸进行特征提取(128维),其网络模型就是InceptionResNetV1,比较容易,这里就不详细讲了
FaceNet的triple loss:Facenet介绍
【注,常见的对齐方法:通过双眼坐标进行旋正、通过矩阵运算求解仿射矩阵进行旋正】
2. Faiss
使用faiss索引库对提取到的人脸特征加入索引构建数据库
- 代码实现(faiss快速入门)
def index_build(self, indexfilename):
"""
将特征构建索引库
:param indedxfilename: 索引所保存的位置
:return:
"""
if self.featureType == "face": d = 128
if self.featureType == "person": d = 256
file = open(self.featurePath)
json_data = json.load(file)
features = []
if d == 128:
# 表示读入的为人脸特征
for i in range(len(json_data)):
features.append(json_data[i]['feature'])
index = faiss.IndexFlatL2(d)
if d == 256:
# 表示读入的为行人特征,保存格式与人脸不同,遂用两段代码分别处理
for person in json_data[0].keys():
features.append(json_data[0][person]['feature'])
index = faiss.IndexFlatIP(d)
features = np.asarray(features).astype(np.float32)
index.add(features)
faiss.write_index(index, indexfilename)
- faiss构建数据库的优点(参考)
- faiss专门提供向量存储搜索等相关服务,支持索引的动态增删
- 良好的搜索效率和内存占用:128/100万/0.024ms/1.552GB;128/500万/0.047ms/5.504GB
- 支持多种相似度索引方式
3. Flask
使用Flask进行前后端的交互功能
- 代码实现(入门教程很多,就不贴了…)
#服务器端
"""
传输模块
"""
app = Flask(__name__)
@app.route('/register', methods=['POST'])
def register():
all_video_inf = []
res = json.loads(request.data)
if ('key words' in res.keys()) and (res['key words'] != ''):
print('输入关键字成功')
wordInformation = Information("word", res['key words'])
video_time_words = wordInformation.word_search()
#检索关键字
all_video_inf.append(video_time_words['result'])
if ('face' in res.keys()) and (res['face'] != ''):
print('输入人脸图片成功')
faceInformation = Information("face", res['face'])
video_time_face = faceInformation.face_search_in_many_videos(faceFeature2IndexPath, faceFeature2TimeListPath)
#检索人脸
all_video_inf.append(video_time_face['result'])
if ('person' in res.keys()) and (res['person'] != ''):
print('输入人体图片成功')
personInformation = Information("person", res['person'])
video_time_person = personInformation.person_search_in_many_videos(personFeature2IndexPath, personFeature2TimeListPath)
#检索行人
all_video_inf.append(video_time_person['result'])
else:
return str('status:Error')
#合并重复的检索结果
allOfTime = Time(all_video_inf)
result = allOfTime.merge()
return str(result)
#客户端
import requests
import cv2
import json
import numpy as np
#输入查询数据(文本、人脸、行人)
face_name = 'face1.jpg'
person_name = 'person2.jpg'
test_data = [1,2,3,4,5]
inquire_data = {'key words':'word3',
'face':(cv2.imread('./save_img/'+face_name)).tolist(),
'person':(cv2.imread('./save_img/'+person_name)).tolist()
}
# requests发送数据给服务器端并接收返回数据
response = requests.post("http://127.0.0.1:9000/register", data=json.dumps(inquire_data))
output = eval(response.text)
print(output)
另,有对这个项目感兴趣的或者想要代码的小伙伴可以留下邮箱~
最后
以上就是可耐唇彩为你收集整理的人脸识别+检索项目记录的全部内容,希望文章能够帮你解决人脸识别+检索项目记录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复