如何做人脸识别

Database and Ruby, Python, History


下载arcface_onnx.py,然后执行下面的代码就可以算出两个照片的相似度,进而判断两者是不是同一个人。

加载模型

import os
import os.path as osp
import argparse
import cv2
import numpy as np
import onnxruntime
from scrfd import SCRFD
from arcface_onnx import ArcFaceONNX

onnxruntime.set_default_logger_severity(3)

assets_dir = osp.expanduser('~/.insightface/models/buffalo_l')

detector = SCRFD(os.path.join(assets_dir, 'det_10g.onnx'))
detector.prepare(0)
model_path = os.path.join(assets_dir, 'w600k_r50.onnx')
rec = ArcFaceONNX(model_path)
rec.prepare(0)

加载图片

image1 = cv2.imread('img1.jpg')
image2 = cv2.imread('img2.jpg')

人脸检测

和前面的文章一样,detector返回的人脸框和五个关键点。

bboxes1, kpss1 = detector.autodetect(image1, max_num=1)
if bboxes1.shape[0]==0:
    return -1.0, "Face not found in Image-1"
bboxes2, kpss2 = detector.autodetect(image2, max_num=1)
if bboxes2.shape[0]==0:
    return -1.0, "Face not found in Image-2"

获取图片里面人脸照片的特征

kps1 = kpss1[0]
kps2 = kpss2[0]
feat1 = rec.get(image1, kps1)
feat2 = rec.get(image2, kps2)

get 方法做了两件事:

  1. norm_crop根据人脸的 5 个关键点位进行对齐和拉伸,返回的是(112, 112, 3)的数组
  2. get_feat就是根据新的图片进行推断,获取到一个(512,)的特征数组。在进行推断之前,需要对知道模型对于输入的规范,再将图片按照该规范进行处理cv2.dnn.blobFromImages
def get(self, img, kps):
    aimg = face_align.norm_crop(img, landmark=kps, image_size=self.input_size[0])
    embedding = self.get_feat(aimg).flatten()
    return embedding

def norm_crop(img, landmark, image_size=112, mode='arcface'):
    M, pose_index = estimate_norm(landmark, image_size, mode)
    warped = cv2.warpAffine(img, M, (image_size, image_size), borderValue=0.0)
    return warped

def get_feat(self, imgs):
    if not isinstance(imgs, list):
        imgs = [imgs]
    input_size = self.input_size

    blob = cv2.dnn.blobFromImages(imgs, 1.0 / self.input_std, input_size,
                                  (self.input_mean, self.input_mean, self.input_mean), swapRB=True)
    net_out = self.session.run(self.output_names, {self.input_name: blob})[0]
    return net_out

计算相似度

sim = rec.compute_sim(feat1, feat2)
if sim<0.2:
    conclu = 'They are NOT the same person'
elif sim>=0.2 and sim<0.28:
    conclu = 'They are LIKELY TO be the same person'
else:
    conclu = 'They ARE the same person'

print(f"sim: {sim}")

compute_sim是计算两个特征的余弦相似度,feat1.dot(feat2)计算两者的点积,np.linalg.norm是用来计算特征的范数。

def compute_sim(self, feat1, feat2):
    sim = feat1.dot(feat2) / (np.linalg.norm(feat1) * np.linalg.norm(feat2))
    return sim