快速上手项目1:基于FaceNet的人脸识别项目

快速上手项目1:基于FaceNet的人脸识别项目

说明

​ 本来想自己复现一下facenet的,但是发现facenet已经被做成了python的第三方库,于是自己用了用,发现挺简单的,然后又看了看源码,感觉模型架构实现部分很简单,所以就算了。

​ 想了想,决定新开一个系列,就是快速上手项目,主要目的就是尽可能的简单使用一个项目。

GitHub项目地址

​ 想要自己研读代码的,可以把源码下载到本地:

https://github.com/timesler/facenet-pytorch/

目录结构

文章目录

    • 快速上手项目1:基于FaceNet的人脸识别项目
      • 1. 前言
      • 2. 安装
      • 3. 下载预训练权重
      • 4. 方法说明
      • 5. 人脸检测
      • 6. 人脸识别
      • 7. 总结

1. 前言

​ 经常会刷到如何学习人工智能的视频,总会有人说学习CV先跑一个项目,而这个项目大部分都人脸识别。

​ 我也是最近看了人脸识别相关的论文,才知道原来facenet已经把代码做成了一个python第三方库。难怪大家都说要实现人脸识别,因为它真的简单,并且可以在不需要你训练的情况下,直接拿过来用。

2. 安装

  • 方式一:安装包
pip install facenet-pytorch
  • 方法二:下载源码

​ 如果你只想要简单了解这个项目,直接安装facenet-pytorch即可,不过,我们这里还是把源码从GitHub上下过来:

https://github.com/timesler/facenet-pytorch/

​ 因为,想要深入了解,最好还是从源码入手,另外源码还提供了几张测试图片可以用。

​ 这里简单对下载后的GitHub项目进行简单的目录结构说明:

快速上手项目1:基于FaceNet的人脸识别项目_第1张图片

3. 下载预训练权重

​ 虽然你可以直接使用方法:

from facenet_pytorch import InceptionResnetV1

resnet = InceptionResnetV1(pretrained='vggface2')

​ 来自动下载预训练权重,不过这个下载地址其实是在GitHub上,所以注定了下载比较慢。因此我建议你可以自己下载:

  • 方法一:打开下面链接直接下载
https://github.com/timesler/facenet-pytorch/releases/download/v2.2.9/20180402-114759-vggface2.pt
  • 方法二:用百度网盘下载
链接:https://pan.baidu.com/s/1TPaz_RO4faazUUg6ljftVA 
提取码:dqqi 

​ 下载后,需要把下载的文件放入下面的路径中:

C:\Users\用户\.cache\torch\checkpoints

4. 方法说明

​ 下面对常用的方法进行一定的说明:

  • MTCNN类:创建MTCNN模型,用于人脸的检测

​ 该类的常用初始化参数:

参数 意义
image_size 输出图像大小,默认160
margin 添加到预测框的margin值,默认为0
min_face_size 最小的搜索人脸的大小,默认为20
thresholds 人脸检测阈值,默认为[0.6, 0.7, 0.7]
factor 用于创建图像金字塔的缩放因子,默认为0.709
post_process 是否进行后处理,默认为True
select_largest 如果为True,返回检测到人脸中最大的,否则返回概率最大的,默认为True
selection_method 用何种方式选择人脸,和上面的参数有点类似,默认为None
keep_all 如果为True,所有检测到的人脸都返回,默认为False
device 指定设备信息,默认为None

​ 该类的常用方法:

方法 参数 作用 举例
前向传播方法 图像、保存路径、是否返回概率值 基本的运行流程,但是返回人脸的数组 mtcnn(img.path.True)
detect 图像、是否返回人脸关键点 与前向传播类似,但是返回预测框坐标和概率值 mtcnn.detect(img,False)
  • InceptionResnetV1类,目的是获取人脸的嵌入向量,用于衡量不同人脸之间的相似性,用于人脸识别
# 常见的用法
# 1. 创建对象
resnet = InceptionResnetV1(pretrained='vggface2').eval().to('cuda')
'''
pretrained,即是否启用预训练模型
'''
# 2. 识别人脸
face_embedding = resnet(img)

5. 人脸检测

​ 其实,如果你下载了GitHub上的源码,你也许已经发现了,作者自己提供了测试代码和如何使用这些代码。(下面的代码参考作者提供的测试代码,我只是稍微修改了一些)

​ 这里,我根据作者的提示简单粗暴的来实现一下人脸检测:

# 导入包
from facenet_pytorch import MTCNN
import cv2
import torch

# 指定设备
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 创建对象:这个是作者提供的方法
mtcnn = MTCNN(
    image_size=160, margin=0, min_face_size=20,
    thresholds=[0.6, 0.7, 0.7], factor=0.709, post_process=True,
    device=device
)
# 人脸检测
# 给定一张图片路径
img_path = '../data/test.jpg'
image = cv2.imread(img_path)
# 为了防止图片太大,把它缩放一下,如果图片不大,可以把它注释掉
# image = cv2.resize(image,(500,500))
# 预测
box,prob = mtcnn.detect(image)
# 把结果可视化
cv2.namedWindow('draw')
cv2.rectangle(image,(int(box[0][0]),int(box[0][1])),(int(box[0][2]),int(box[0][3])),(0,0,255))
cv2.imshow('draw',image)
cv2.waitKey(0)

​ 看看预测结果:

快速上手项目1:基于FaceNet的人脸识别项目_第2张图片

6. 人脸识别

​ 同样的,作者也提供了人脸识别的脚本,注意:人脸检测只需要检测到人脸即可,人脸识别不仅需要检测人脸,还需要识别这个人是谁

​ 那么可以简单的实现一下:

from facenet_pytorch import MTCNN,InceptionResnetV1
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
import numpy as np
import pandas as pd
import os
from PIL import Image, ImageDraw, ImageFont

# 定义加载图像的线程数
workers = 0 if os.name=="nt" else 4
# 定义设备
device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
# 创建mtcnn
mtcnn = MTCNN(image_size=160,margin=0,min_face_size=20,thresholds=[0.6,0.7,0.7],
              factor=0.709,post_process=True,device=device
              )
# 创建resnet
resnet = InceptionResnetV1(pretrained='vggface2').eval().to(device)
# 定义数据加载器的函数
def collate_fn(x):
    return x[0]
#将所有的单人照图片放在各自的文件夹中,文件夹名字就是人的名字,存放格式如下::
dataset = datasets.ImageFolder("../data/test_images") #加载数据库
dataset.idx_to_class = {i:c for c,i in dataset.class_to_idx.items()}
loader = DataLoader(dataset,collate_fn=collate_fn,num_workers=workers)
aligned = [] #aligned就是从图像上抠出的人脸,大小是之前定义的image_size=160
names = []

# 将获取的人脸图片保存下来,注意路径
i = 1
for x, y in loader:
    path = '../data/test_images_aligned/{}/'.format(dataset.idx_to_class[y])  # 这个是要保存的人脸路径
    # 如果要保存识别到的人脸,在save_path参数指明保存路径即可,不保存可以用None
    x_aligned, prob = mtcnn(x, return_prob=True,save_path= path+ '/{}.jpg'.format(i))
    i = i+1
    # 如果有预测的值,放入结果列表中
    if x_aligned is not None:
        print('Face detected with probability: {:8f}'.format(prob))
        aligned.append(x_aligned)
        names.append(dataset.idx_to_class[y])

# 把获取的值保存下来
aligned = torch.stack(aligned).to(device)
embeddings = resnet(aligned).detach().cpu() #提取所有人脸的特征向量,每个向量的长度是512
#两两之间计算混淆矩阵
dists = [[(e1 - e2).norm().item() for e2 in embeddings] for e1 in embeddings]
print(names)
print(pd.DataFrame(dists, columns=names, index=names))
torch.save(embeddings,'database.pt')  # 当然也可以保存在一个文件
torch.save(names,'names.pt')

#对新的照片进行人脸识别
# mtcnn网络负责检测人脸
mtcnn = MTCNN(keep_all=True, device=device)
resnet = InceptionResnetV1(pretrained='vggface2').eval().to('cuda')
# 加载上面学习到的数据
names = torch.load("./names.pt")
embeddings = torch.load("./database.pt").to('cuda')
def detect_frame(img):
    fontStyle = ImageFont.truetype("arial.ttf", 100,encoding="utf-8")
    faces = mtcnn(img)  # 直接infer所有的faces
    #但是这里相当于两次infer,会浪费时间
    boxes, _ = mtcnn.detect(img)  # 检测出人脸框 返回的是位置
    # frame_draw = img.copy()
    draw = ImageDraw.Draw(img)
    print("检测人脸数目:",len(boxes))
    for i,box in enumerate(boxes):
        print(box)
        draw.rectangle(box.tolist(),outline='white',width=5)  # 绘制框
        face_embedding = resnet(faces[i].unsqueeze(0).to('cuda'))
        #print(face_embedding.size(),'大小')
        # 计算距离
        probs = [(face_embedding - embeddings[i]).norm().item() for i in range(embeddings.size()[0])]
        #print(probs)
        # 我们可以认为距离最近的那个就是最有可能的人,但也有可能出问题,数据库中可以存放一个人的多视角多姿态数据,对比的时候可以采用其他方法,如投票机制决定最后的识别人脸
        index = probs.index(min(probs))   # 对应的索引就是判断的人脸
        name = names[index] # 对应的人脸
        draw.text( (int(box[0]),int(box[1])), str(name), fill=(255,0,0),font=fontStyle)
    return img

if __name__ == '__main__':
    from matplotlib import pyplot as plt
    # 人脸检测
    img_path = '../data/test.jpg'
    img = Image.open(img_path)
    frame = detect_frame(img)
    plt.imshow(frame)
    plt.show()

​ 结果如下:
快速上手项目1:基于FaceNet的人脸识别项目_第3张图片

7. 总结

​ 这个项目主要的特点是简单,容易扩展。

​ 不过,在源码中,项目架构容易实现,但是具体的细节阅读起来仍需一定的基础。如果感兴趣或者想要提高自己阅读代码能力的朋友,可以去看看项目中的model文件夹。

你可能感兴趣的:(快速上手项目,python,深度学习,开发语言)