安装环境
安装insightface ,安装命令如下。
python -m pip install Cython insightface==0.6.2 -i https://mirror.baidu.com/pypi/simple
1
安装onnxruntime-gpu,命令如下。
python -m pip install onnxruntime-gpu -i https://mirror.baidu.com/pypi/simple
1
安装cudatoolkit,命令如下。
conda install cudatoolkit=11.3 cudnn --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/
1
人脸识别和人脸注册
为了方便,写一个类完成所有的识别流程,开始编写人脸识别和人脸注册工具类,使用insightface.app.FaceAnalysis()可以获取模型对象,这里包含了三个模型,首先是人脸检测模型,然后是人脸特征提取模型,和最后的性别年龄识别模型。使用model.prepare()可以配置ctx_id指定使用哪一块GPU,如果是负数则是使用CPU执行预测,det_thresh配置的是人脸检测的阈值。load_faces()函数是加载人脸库中的人脸,用于之后的人脸识别对比。
import os
import cv2
import insightface
import numpy as np
from sklearn import preprocessing
class FaceRecognition:
def __init__(self, gpu_id=0, face_db='face_db', threshold=1.24, det_thresh=0.50, det_size=(640, 640)):
"""
人脸识别工具类
:param gpu_id: 正数为GPU的ID,负数为使用CPU
:param face_db: 人脸库文件夹
:param threshold: 人脸识别阈值
:param det_thresh: 检测阈值
:param det_size: 检测模型图片大小
"""
self.gpu_id = gpu_id
self.face_db = face_db
self.threshold = threshold
self.det_thresh = det_thresh
self.det_size = det_size
# 加载人脸识别模型,当allowed_modules=['detection', 'recognition']时,只单纯检测和识别
self.model = insightface.app.FaceAnalysis(root='./',
allowed_modules=None,
providers=['CUDAExecutionProvider'])
self.model.prepare(ctx_id=self.gpu_id, det_thresh=self.det_thresh, det_size=self.det_size)
# 人脸库的人脸特征
self.faces_embedding = list()
# 加载人脸库中的人脸
self.load_faces(self.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_name = 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_name": user_name,
"feature": embedding
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
接下来编写recognition()函数实现人脸识别,首先获取每张人脸的特征embedding,其中使用人脸识别的就是通过欧氏距离来对比人脸库中的人脸特征,默认如何它们的欧氏距离小于1.24,我们就可以认为他们是同一个人。
def recognition(self, image):
faces = self.model.get(image)
results = list()
for face in faces:
# 开始人脸识别
embedding = np.array(face.embedding).reshape((1, -1))
embedding = preprocessing.normalize(embedding)
user_name = "unknown"
for com_face in self.faces_embedding:
r = self.feature_compare(embedding, com_face["feature"], self.threshold)
if r:
user_name = com_face["user_name"]
results.append(user_name)
return results
1
2
3
4
5
6
7
8
9
10
11
12
13
14
上面使用到的欧氏距离计算方式如下。
@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
1
2
3
4
5
6
7
8
人脸注册方式如下,通过传入一张照片,首先要判断照片中的人脸只有一张,然后开始提取该人脸的特征值,再次比较要注册的人脸是否已经存在人脸库中了,否之就包人脸特征添加到人脸库中并保存图片到本地。通过命名包只包含一个人脸的图片放在face_db文件夹中也可以实现。
def register(self, image, user_name):
faces = self.model.get(image)
if len(faces) != 1:
return '图片检测不到人脸'
# 判断人脸是否存在
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.threshold)
if r:
is_exits = True
if is_exits:
return '该用户已存在'
# 符合注册条件保存图片,同时把特征添加到人脸特征库中
cv2.imencode('.png', image)[1].tofile(os.path.join(self.face_db, '%s.png' % user_name))
self.faces_embedding.append({
"user_name": user_name,
"feature": embedding
})
return "success"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这里还提供了通用的人脸检测函数,通过调用detect()函数可以获取图像中每张人脸框坐标bbox,人脸五个关键点kps,人脸3D关键点landmark_3d_68,人脸2D关键点landmark_2d_106,人脸姿态pose,性别gender,年龄age,人脸特征embedding。
def detect(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["kps"] = np.array(face.kps).astype(np.int32).tolist()
result["landmark_3d_68"] = np.array(face.landmark_3d_68).astype(np.int32).tolist()
result["landmark_2d_106"] = np.array(face.landmark_2d_106).astype(np.int32).tolist()
result["pose"] = np.array(face.pose).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["embedding"] = embedding
results.append(result)
return results
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
使用
全部功能都实现了,使用如下,首先是进行人脸注册。
if __name__ == '__main__':
img = cv2.imdecode(np.fromfile('迪丽热巴.jpg', dtype=np.uint8), -1)
face_recognitio = FaceRecognition()
# 人脸注册
result = face_recognitio.register(img, user_name='迪丽热巴')
print(result)
1
2
3
4
5
6
人脸识别,通过传入一张图片,可以输出每张人脸对应的用户名。
if __name__ == '__main__':
img = cv2.imdecode(np.fromfile('迪丽热巴.jpg', dtype=np.uint8), -1)
face_recognitio = FaceRecognition()
results = face_recognitio.recognition(img)
for result in results:
print("识别结果:{}".format(result))
1
2
3
4
5
6
人脸通用检测,可以获取每张人脸的各种属性。
if __name__ == '__main__':
img = cv2.imdecode(np.fromfile('迪丽热巴.jpg', dtype=np.uint8), -1)
face_recognitio = FaceRecognition()
results = face_recognitio.detect(img)
for result in results:
print('人脸框坐标:{}'.format(result["bbox"]))
print('人脸五个关键点:{}'.format(result["kps"]))
print('人脸3D关键点:{}'.format(result["landmark_3d_68"]))
print('人脸2D关键点:{}'.format(result["landmark_2d_106"]))
print('人脸姿态:{}'.format(result["pose"]))
print('年龄:{}'.format(result["age"]))
print('性别:{}'.format(result["gender"]))
1
2
3
4
5
6
7
8
9
10
11
12
13
全部代码
import os
import cv2
import insightface
import numpy as np
from sklearn import preprocessing
class FaceRecognition:
def __init__(self, gpu_id=0, face_db='face_db', threshold=1.24, det_thresh=0.50, det_size=(640, 640)):
"""
人脸识别工具类
:param gpu_id: 正数为GPU的ID,负数为使用CPU
:param face_db: 人脸库文件夹
:param threshold: 人脸识别阈值
:param det_thresh: 检测阈值
:param det_size: 检测模型图片大小
"""
self.gpu_id = gpu_id
self.face_db = face_db
self.threshold = threshold
self.det_thresh = det_thresh
self.det_size = det_size
# 加载人脸识别模型,当allowed_modules=['detection', 'recognition']时,只单纯检测和识别
self.model = insightface.app.FaceAnalysis(root='./',
allowed_modules=None,
providers=['CUDAExecutionProvider'])
self.model.prepare(ctx_id=self.gpu_id, det_thresh=self.det_thresh, det_size=self.det_size)
# 人脸库的人脸特征
self.faces_embedding = list()
# 加载人脸库中的人脸
self.load_faces(self.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_name = 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_name": user_name,
"feature": embedding
})
# 人脸识别
def recognition(self, image):
faces = self.model.get(image)
results = list()
for face in faces:
# 开始人脸识别
embedding = np.array(face.embedding).reshape((1, -1))
embedding = preprocessing.normalize(embedding)
user_name = "unknown"
for com_face in self.faces_embedding:
r = self.feature_compare(embedding, com_face["feature"], self.threshold)
if r:
user_name = com_face["user_name"]
results.append(user_name)
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
def register(self, image, user_name):
faces = self.model.get(image)
if len(faces) != 1:
return '图片检测不到人脸'
# 判断人脸是否存在
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.threshold)
if r:
is_exits = True
if is_exits:
return '该用户已存在'
# 符合注册条件保存图片,同时把特征添加到人脸特征库中
cv2.imencode('.png', image)[1].tofile(os.path.join(self.face_db, '%s.png' % user_name))
self.faces_embedding.append({
"user_name": user_name,
"feature": embedding
})
return "success"
# 检测人脸
def detect(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["kps"] = np.array(face.kps).astype(np.int32).tolist()
result["landmark_3d_68"] = np.array(face.landmark_3d_68).astype(np.int32).tolist()
result["landmark_2d_106"] = np.array(face.landmark_2d_106).astype(np.int32).tolist()
result["pose"] = np.array(face.pose).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["embedding"] = embedding
results.append(result)
return results
if __name__ == '__main__':
img = cv2.imdecode(np.fromfile('迪丽热巴.jpg', dtype=np.uint8), -1)
face_recognitio = FaceRecognition()
# 人脸注册
result = face_recognitio.register(img, user_name='迪丽热巴')
print(result)
# 人脸识别
results = face_recognitio.recognition(img)
for result in results:
print("识别结果:{}".format(result))
results = face_recognitio.detect(img)
for result in results:
print('人脸框坐标:{}'.format(result["bbox"]))
print('人脸五个关键点:{}'.format(result["kps"]))
print('人脸3D关键点:{}'.format(result["landmark_3d_68"]))
print('人脸2D关键点:{}'.format(result["landmark_2d_106"]))
print('人脸姿态:{}'.format(result["pose"]))
print('年龄:{}'.format(result["age"]))
print('性别:{}'.format(result["gender"]))