基于insightface实现的人脸识别和人脸注册
本教程的人脸识别是使用的是insightface库进行开发的,该库使用的框架为mxnet。
安装环境
- 安装mxnet,支持1.3~1.6版本,安装命令如下。
pip install mxnet-cu101==1.5.1
- 安装insightface,命令如下。
pip install --upgrade insightface
- 安装其他依赖库。
pip install flask flask-cors PyYAML scikit-learn opencv-python
人脸识别和人脸注册
为了方便参数的修改,使用yaml格式进行配置参数,yaml格式文件加载如下。
import os
import yaml
import numpy as np
import insightface
from random import choice
import cv2
from sklearn import preprocessing
# Deploy Configuration File Parser
class DeployConfig:
def __init__(self, conf_file):
if not os.path.exists(conf_file):
raise Exception('Config file path [%s] invalid!' % conf_file)
with open(conf_file) as fp:
configs = yaml.load(fp, Loader=yaml.FullLoader)
deploy_conf = configs["FACE"]
# 正数为GPU的ID,负数为使用CPU
self.gpu_id = deploy_conf["GPU_ID"]
self.face_db = deploy_conf["FACE_DB"]
self.threshold = deploy_conf["THRESHOLD"]
self.nms = deploy_conf["NMS"]
config.yaml
内容如下:
FACE:
GPU_ID: 0
FACE_DB: "face_db"
THRESHOLD: 1.24
NMS: 0.50
然后开始编写人脸识别和人脸注册工具类,使用insightface.app.FaceAnalysis()
可以获取模型对象,这里包含了三个模型,首先是人脸检测模型,然后是人脸特征提取模型,和最后的性别年龄识别模型。使用model.prepare()
可以配置ctx_id
指定使用哪一块GPU,如果是负数则是使用CPU执行预测,nms
配置的是人脸检测的阈值。load_faces()
函数是加载人脸库中的人脸,用于之后的人脸识别对比。
class FaceRecognition:
def __init__(self, conf_file):
self.config = DeployConfig(conf_file)
# 加载人脸识别模型
self.model = insightface.app.FaceAnalysis()
self.model.prepare(ctx_id=self.config.gpu_id, nms=self.config.nms)
# 人脸库的人脸特征
self.faces_embedding = list()
# 加载人脸库中的人脸
self.load_faces(self.config.face_db)
# 加载人脸库中的人脸
def load_faces(self, face_db_path):
if not os.path.exists(face_db_path):
os.makedirs(face_db_path)
for root, dirs, files in os.walk(face_db_path):
for file in files:
input_image = cv2.imdecode(np.fromfile(os.path.join(root, file), dtype=np.uint8), 1)
user_id = file.split(".")[0]
face = self.model.get(input_image)[0]
embedding = np.array(face.embedding).reshape((1, -1))
embedding = preprocessing.normalize(embedding)
self.faces_embedding.append({
"user_id": user_id,
"feature": embedding
})
接下来编写recognition()
函数实现人脸识别,通过调用model.get()
函数可以获取图像中每张人脸的位置bbox,人脸关键点landmark,人脸特征embedding,性别gender,年龄age。其中使用人脸识别的就是通过欧氏距离来对比人脸库中的人脸特征,默认如何它们的欧氏距离小于1.24,我们就可以认为他们是同一个人。
def recognition(self, image):
faces = self.model.get(image)
results = list()
for face in faces:
result = dict()
# 获取人脸属性
result["bbox"] = np.array(face.bbox).astype(np.int32).tolist()
result["landmark"] = np.array(face.landmark).astype(np.int32).tolist()
result["age"] = face.age
gender = '男'
if face.gender == 0:
gender = '女'
result["gender"] = gender
# 开始人脸识别
embedding = np.array(face.embedding).reshape((1, -1))
embedding = preprocessing.normalize(embedding)
result["user_id"] = "unknown"
for com_face in self.faces_embedding:
r = self.feature_compare(embedding, com_face["feature"], self.config.threshold)
if r:
result["user_id"] = com_face["user_id"]
results.append(result)
return results
上面使用到的欧氏距离计算方式如下。
@staticmethod
def feature_compare(feature1, feature2, threshold):
diff = np.subtract(feature1, feature2)
dist = np.sum(np.square(diff), 1)
if dist < threshold:
return True
else:
return False
人脸注册方式如下,通过传入一张照片,首先要判断照片中的人脸只有一张,然后开始提取该人脸的特征值,再次比较要注册的人脸是否已经存在人脸库中了,否之就包人脸特征添加到人脸库中并保存图片到本地。通过命名包只包含一个人脸的图片放在face_db
文件夹中也可以实现。
def register(self, image):
faces = self.model.get(image)
if len(faces) != 1:
return None
# 判断人脸是否存在
embedding = np.array(faces[0].embedding).reshape((1, -1))
embedding = preprocessing.normalize(embedding)
is_exits = False
for com_face in self.faces_embedding:
r = self.feature_compare(embedding, com_face["feature"], self.config.threshold)
if r:
is_exits = True
if is_exits:
return None
old_user_id = [d["user_id"] for d in self.faces_embedding]
user_id = self.get_user_id(old_user_id)
# 符合注册条件保存图片,同时把特征添加到人脸特征库中
cv2.imencode('.png', image)[1].tofile(os.path.join(self.config.face_db, '%s.png' % user_id))
self.faces_embedding.append({
"user_id": user_id,
"feature": embedding
})
return user_id
def get_user_id(self, old_user_id):
print(old_user_id)
while True:
user_id = "".join([choice("0123456789ABCDEF") for i in range(8)])
if user_id not in old_user_id:
break
return user_id
使用
全部功能都实现了,使用如下,首先是进行人脸注册,注册成功之后会获得一个用户注册ID,之后的人脸识别可以用过这个用户ID判断是不是这个人。
if __name__ == '__main__':
img = cv2.imread("test.png")
face_recognitio = FaceRecognition("config.yml")
user_id = face_recognitio.register(img)
print(user_id)
人脸识别,通过传入一张图片,可以输出每张人脸对应的用户ID、人脸位置bbox,人脸关键点landmark,性别gender,年龄age。
if __name__ == '__main__':
img = cv2.imread("test2.png")
face_recognitio = FaceRecognition("config.yml")
result = face_recognitio.recognition(img)
print(result)