【人脸检测+人脸识别】-mtcnn+facenet

【人脸检测+人脸识别】-mtcnn+facenet

转载为: https://blog.csdn.net/guyuealian/article/details/84896733

利用MTCNN和facenet实现人脸检测和人脸识别

0.遇到问题

'''
1.报错:ValueError: Object arrays cannot be loaded when allow_pickle=False

问题解决:numpy不符合当前代码
!pip install numpy==1.16.2 (卸载当前版本)

pip install numpy==1.16.2 (安装1.16.2版本)
'''
import numpy as np
print(np.__vision__) #查询当前版本号

【github】项目中拷贝所需要的文件

  1. align文件
  2. facenet.py

其他文件介绍

dataset:这个文件主要存放数据,如人脸数据库

utils:这个文件是工具类文件,用于文件读写,图像相关操作的函数方法等

models:存放facenet预训练模型,百度网盘下载地址:【链接】——提取码: jf1n

预训练模型

Model nameLFW accuracyTraining datasetArchitecture
20180408-1029000.9905CASIA-WebFaceInception ResNet v1
20180402-1147590.9965VGGFace2Inception ResNet v1

2.实现流程

  1. 通过MTCNN人脸检测模型,从照片中提取人脸图像
  2. 把人脸图像输入到FaceNet,计算Embedding的特征向量
  3. 比较特征向量间的欧式距离,判断是否为同一人,例如当特征距离小于1的时候认为是同一个人,特征距离大于1的时候认为不是同一个人

3.Multi-task cnn(MTCNN)人脸检测

提供一个使用MTCNN进行人脸检测的方法

def detection_face(img):
    minsize = 20  # minimum size of face
    threshold = [0.6, 0.7, 0.7]  # three steps's threshold
    factor = 0.709  # scale factor
    print('Creating networks and loading parameters')
    with tf.Graph().as_default():
        # gpu_memory_fraction = 1.0
        # gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction)
        # sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
        sess = tf.Session()
        with sess.as_default():
            pnet, rnet, onet = detect_face.create_mtcnn(sess, None) # 加载训练好的模型
            bboxes, landmarks = detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)  # 返回bboxes和landmarks
    landmarks = np.transpose(landmarks)
    bboxes = bboxes.astype(int)
    bboxes = [b[:4] for b in bboxes]
    landmarks_list=[]
    for landmark in landmarks:
        face_landmarks = [[landmark[j], landmark[j + 5]] for j in range(5)]
        landmarks_list.append(face_landmarks)
    return bboxes,landmarks_list

在实际使用中封装成一个类

注意

'''
mtcnn人脸检测获得bboxes并不一定是一个正方形框
1.可以调用get_square_bboxes()  将参数 @ fixed 指定等宽或者等高的 bboxes
2.直接resize成指定大小
'''
class Facedetection:
    def __init__(self):
        self.minsize = 30  # minimum size of face
        self.threshold = [0.6, 0.7, 0.7]  # three steps's threshold
        self.factor = 0.709  # scale factor
        print('Creating networks and loading parameters')
        with tf.Graph().as_default():
            # gpu_memory_fraction = 1.0
            # gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction)
            # sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
            sess = tf.Session()
            with sess.as_default():
                self.pnet, self.rnet, self.onet = detect_face.create_mtcnn(sess, None)
    def detect_face(self,image,fixed=None):
        '''
        mtcnn人脸检测,
        PS:人脸检测获得bboxes并不一定是正方形的矩形框,参数fixed指定等宽或者等高的bboxes
        :param image:
        :param fixed:
        :return:
        '''
        bboxes, landmarks = detect_face.detect_face(image, self.minsize, self.pnet, self.rnet, self.onet, self.threshold, self.factor)
        landmarks_list = []
        landmarks=np.transpose(landmarks)
        bboxes=bboxes.astype(int)
        bboxes = [b[:4] for b in bboxes]
        for landmark in landmarks:
            face_landmarks = [[landmark[j], landmark[j + 5]] for j in range(5)]
            landmarks_list.append(face_landmarks)
        if fixed is not None:
            bboxes,landmarks_list=self.get_square_bboxes(bboxes, landmarks_list, fixed)
        return bboxes,landmarks_list
 
    def get_square_bboxes(self, bboxes, landmarks, fixed="height"):
        '''
        获得等宽或者等高的bboxes
        :param bboxes:
        :param landmarks:
        :param fixed: width or height
        :return:
        '''
        new_bboxes = []
        for bbox in bboxes:
            x1, y1, x2, y2 = bbox
            w = x2 - x1
            h = y2 - y1
            center_x, center_y = (int((x1 + x2) / 2), int((y1 + y2) / 2))
            if fixed == "height":
                dd = h / 2
            elif fixed == 'width':
                dd = w / 2
            x11 = int(center_x - dd)
            y11 = int(center_y - dd)
            x22 = int(center_x + dd)
            y22 = int(center_y + dd)
            new_bbox = (x11, y11, x22, y22)
            new_bboxes.append(new_bbox)
        return new_bboxes, landmarks

4.faceNet人脸识别

FaceNet 主要用于验证人脸是否为同一个人,通过人脸识别这个人是谁,FaceNet的主要思想是把人脸图像映射到一个多维度空间,通过空间距离表示人脸的相似度。这样通过人脸图像的空间映射就可以实现人脸识别,FaceNet中采用基于深度神经网络的图像映射方法和基于triplets(三联子)的loss函数训练神经网络,网络直接输出为128维度的向量空间

FaceNet的网络结构如下图所示,其中Batch表示人脸的训练数据,接下来是深度卷积神经网络,然后采用L2归一化操作,得到人脸图像的特征表示,最后为三元组(Triplet Loss)的损失函数

在这里插入图片描述

'''
其中类函数get_embedding(self,images)方法
用于facenet提取人脸特征embadding
'''
class facenetEmbedding:
    def __init__(self,model_path):
        self.sess = tf.InteractiveSession()
        self.sess.run(tf.global_variables_initializer())
        # Load the model
        facenet.load_model(model_path)
        # Get input and output tensors
        self.images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
        self.tf_embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
        self.phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
 
    def  get_embedding(self,images):
        '''用于提取facenet的人脸特征embadding'''
        feed_dict = {self.images_placeholder: images, self.phase_train_placeholder: False}
        embedding = self.sess.run(self.tf_embeddings, feed_dict=feed_dict)
        return embedding
    def free(self):
        self.sess.close()

2.triplet loss

triplet 是指三元组:Anchor、Positive、Negative
在这里插入图片描述
整个训练过程

1.首先从训练集中随机选一个样本,成Anchor-(记为x_a)
2.然后再随机选取一个和Anchor属于同一类的样本,成为Positive-(记为x_p)
3.最后再随机选取一个人和Anchor属于不同类的样本,称为Negative-(记为x_n)

三元组的三个样本最终得到的特征表达式为
f ( x i a ) f ( x i p ) f ( x i n ) f\left(x_{i}^{a}\right) f\left(x_{i}^{p}\right) f\left(x_{i}^{n}\right) f(xia)f(xip)f(xin)

5.产生数据库

1.制作人脸数据图库

将人像收集放在dataset/images文件夹下

特别说明

1.制作人脸数据库时,所使用的照片必须是单人照片

2.生成embedding数据库

使用create_dataset.py生成embedding数据库(人脸特征)

后面待检测识别的人脸,只需要与这些embedding数据库(人脸特征)进行相似性比较就可以识别人脸

"""
    @Project: faceRecognition
    @File   : create_dataset.py
    @Author : panjq
    @E-mail : pan_jinquan@163.com
    @Date   : 2018-12-07 11:31:09
"""
import numpy as np
from utils import image_processing , file_processing,debug
import face_recognition
import cv2
import os

resize_width = 160
resize_height = 160


def get_face_embedding(model_path,files_list, names_list):
    '''
    获得embedding数据
    @ files_list: 图像列表
    @ names_list: 与files_list一一的名称列表
    :return:
    '''
    # 转换颜色空间RGB or BGR
    colorSpace="RGB"
    # 初始化mtcnn人脸检测
    face_detect = face_recognition.Facedetection()
    # 初始化facenet
    face_net = face_recognition.facenetEmbedding(model_path)

    embeddings=[] # 用于保存人脸特征数据库
    label_list=[] # 保存人脸label的名称,与embeddings一一对应
    for image_path, name in zip(files_list, names_list):
        print("processing image :{}".format(image_path))
        # 读取图片
        image = image_processing.read_image_gbk(image_path, colorSpace=colorSpace)
        # 进行人脸检测,获得bounding_box
        bboxes, landmarks = face_detect.detect_face(image)
        bboxes, landmarks =face_detect.get_square_bboxes(bboxes, landmarks,fixed="height")
        # image_processing.show_image_boxes("image",image,bboxes)
        if bboxes == [] or landmarks == []:
            print("-----no face")
            continue
        if len(bboxes) >= 2 or len(landmarks) >= 2:
            print("-----image have {} faces".format(len(bboxes)))
            continue
        # 获得人脸区域
        face_images = image_processing.get_bboxes_image(image, bboxes, resize_height, resize_width)
        # 人脸预处理,归一化
        face_images = image_processing.get_prewhiten_images(face_images,normalization=True)
        # 获得人脸特征
        pred_emb = face_net.get_embedding(face_images)
        embeddings.append(pred_emb)
        # 可以选择保存image_list或者names_list作为人脸的标签
        # 测试时建议保存image_list,这样方便知道被检测人脸与哪一张图片相似
        # label_list.append(image_path)
        label_list.append(name)
    return embeddings,label_list

def create_face_embedding(model_path,dataset_path,out_emb_path,out_filename):
    '''
    @ model_path: faceNet模型路径
    @ dataset_path: 人脸数据库路径,每一类单独一个文件夹
    @ out_emb_path: 输出embeddings的路径
    @ out_filename: 输出与embeddings一一对应的标签
    @ return: None
    '''
    # 获取每个图片的路径和对应的标签
    files_list,names_list=file_processing.gen_files_labels(dataset_path,postfix=['*.jpg']) 
    # 获取embedding数据
    embeddings,label_list=get_face_embedding(model_path,files_list, names_list)
    print("label_list:{}".format(label_list))
    print("have {} label".format(len(label_list)))

    embeddings=np.asarray(embeddings)
    np.save(out_emb_path, embeddings)
    file_processing.write_list_data(out_filename, label_list, mode='w')

if __name__ == '__main__':
    model_path = 'models/20180408-102900'
    dataset_path='dataset/images'
    out_emb_path = 'dataset/emb/faceEmbedding.npy'
    out_filename = 'dataset/emb/name.txt'
    create_face_embedding(model_path, dataset_path,out_emb_path, out_filename)

6.人脸识别过程

1.加载人脸数据库

def load_dataset(dataset_path,filename):
    '''
    加载人脸数据库
    @ dataset_path: embedding.npy文件(faceEmbedding.npy)
    @ filename: labels文件路径路径(name.txt)
    '''
    compare_emb=np.load(dataset_path)
    names_list=file_processing.read_data(filename,split=False)
    return compare_emb,names_list

2.进行人脸检测

def face_recognition_image(model_path,dataset_path, filename,image_path):
    # 加载数据库的数据
    dataset_emb,names_list=load_dataset(dataset_path, filename)
    # 初始化mtcnn人脸检测
    face_detect=face_recognition.Facedetection()
    # 初始化facenet
    face_net=face_recognition.facenetEmbedding(model_path)
 
    image = image_processing.read_image_gbk(image_path)
    # 获取 判断标识 bounding_box crop_image
    bboxes, landmarks = face_detect.detect_face(image)
    bboxes, landmarks = face_detect.get_square_bboxes(bboxes, landmarks, fixed="height")
    if bboxes == [] or landmarks == []:
        print("-----no face")
        exit(0)
    print("-----image have {} faces".format(len(bboxes)))
    face_images = image_processing.get_bboxes_image(image, bboxes, resize_height, resize_width)
    face_images = image_processing.get_prewhiten_images(face_images)
    pred_emb=face_net.get_embedding(face_images)
    pred_name,pred_score=compare_embadding(pred_emb, dataset_emb, names_list)
    # 在图像上绘制人脸边框和识别的结果
    show_info=[ n+':'+str(s)[:5] for n,s in zip(pred_name,pred_score)]
    image_processing.show_image_text("face_recognition", image,bboxes,show_info)

3.人脸识别(比较相似性)

比较特征向量间的欧式距离

 
def compare_embadding(pred_emb, dataset_emb, names_list,threshold=0.65):
    # 为bounding_box 匹配标签
    pred_num = len(pred_emb)
    dataset_num = len(dataset_emb)
    pred_name = []
    pred_score=[]
    for i in range(pred_num):
        dist_list = []
        for j in range(dataset_num):
            dist = np.sqrt(np.sum(np.square(np.subtract(pred_emb[i, :], dataset_emb[j, :]))))
            dist_list.append(dist)
        min_value = min(dist_list)
        pred_score.append(min_value)
        if (min_value > threshold):
            pred_name.append('unknow')
        else:
            pred_name.append(names_list[dist_list.index(min_value)])
    return pred_name,pred_score

参考

  1. 利用MTCNN和facenet实现人脸检测和人脸识别
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值