人脸识别+检索项目记录

趁空闲时间,记录一下做过的一个实验室项目,主要分为4个部分:1)语音转文字;2)人脸识别;3)行人识别;4)检索。本人负责人脸识别和检索模块及整体项目的融合,在此介绍一下自己所做的两个模块。

背景

对于现今摄像录影众多的情况,想了解一个人是否在某个时间段内出现过以及出现的时间等信息,以往需要大量的人力去查找。针对于这个问题,我们开发了一个人脸检索系统,可以快速的定位到此人是否出现,出现在什么时候等信息,以此来解决需要耗费大量人力的问题。

大体流程

  1. 使用opencv读取视频,每隔25帧进行一次人脸特征提取(视频帧数为25,如果每帧都处理不是很合理,1是会出现很多重复的人脸,2是人脸识别算法fps速度不够,会产生卡顿)
  2. 使用人脸检测算法对视频帧进行检测及提取人脸特征
  3. 使用Faiss索引库构对提取到的人脸特征加入索引构建特征数据库
  4. 使用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

  1. 图像金字塔:

输入一张图片,将图片resize到500,然后按照factor = 0.709依次缩小裁剪至图片大小为12,将所有图片保存

  1. PNet:

针对每一张图片,依次输入PNet,输出很多个粗略的候选框(每个框有位置信息还有置信分数),将每个图片的候选框合并,然后进行NMS算法,得到一些粗略的proposal

  1. RNet:

将PNet得到的proposal裁剪并resize成24x24大小,输入Rnet,然后进行NMS,得到较准确的rois(位置和分数)【RNet的NMS阈值设置为0.3,只剩下少了的rois了】

  1. 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索引库对提取到的人脸特征加入索引构建数据库

  1. 代码实现(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)
  1. faiss构建数据库的优点(参考
  • faiss专门提供向量存储搜索等相关服务,支持索引的动态增删
  • 良好的搜索效率和内存占用:128/100万/0.024ms/1.552GB;128/500万/0.047ms/5.504GB
  • 支持多种相似度索引方式
3. Flask

使用Flask进行前后端的交互功能

  1. 代码实现(入门教程很多,就不贴了…)
#服务器端
"""
传输模块
"""
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)

另,有对这个项目感兴趣的或者想要代码的小伙伴可以留下邮箱~

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值