本项目是世界上最简洁的人脸识别库,你可以使用Python和命令行工具提取、识别、操作人脸。
本项目的人脸识别是基于业内领先的C++开源库 dlib 中的深度学习模型,用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。
项目地址:https://github.com/ageitgey/face_recognition
截止本博文发布日,项目Star数达50.7k,可见该项目受欢迎程度很高,值得拿来学习下。
PS:该项目及其他人脸识别项目测试运行后续会不定时更新,有兴趣可以点个关注!
环境:ubuntu18 cuda11.7
带GPU版:
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build
cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1
cmake --build .
完成后安装到python中,有虚拟环境的先切换到对应的python虚拟环境:
cd ..
python setup.py install --set DLIB_USE_CUDA=1 --no DLIB_GIF_SUPPORT
pip install face_recognition
from PIL import Image
import face_recognition
import time
# 加载图片
image = face_recognition.load_image_file("unknown_pic/obama.jpg")
# 人脸定位
beginTime = time.time()
face_locations = face_recognition.face_locations(image)
# face_locations = face_recognition.face_locations(image, model="cnn") # 使用GPU加速
print(f'face_locations Done. ({time.time() - beginTime:.3f}s)') # 打印时间
print("I found {} face(s) in this photograph.".format(len(face_locations)))
for face_location in face_locations:
# 打印位置
top, right, bottom, left = face_location
print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
# 人脸图
face_image = image[top:bottom, left:right]
pil_image = Image.fromarray(face_image)
pil_image.show()
运行结果:
from PIL import Image, ImageDraw
import face_recognition
import time
# 加载图片
image = face_recognition.load_image_file("unknown_pic/obama.jpg")
beginTime = time.time()
# 找出图像中所有人脸的所有面部特征
face_landmarks_list = face_recognition.face_landmarks(image)
print(f'face_landmarks Done. ({time.time() - beginTime:.3f}s)') # 打印时间
print("I found {} face(s) in this photograph.".format(len(face_landmarks_list)))
# 创建一个PIL imagedraw对象,这样我们就可以在图片上绘图了
pil_image = Image.fromarray(image)
d = ImageDraw.Draw(pil_image)
for face_landmarks in face_landmarks_list:
# 打印该图像中每个面部特征的位置
for facial_feature in face_landmarks.keys():
print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))
# 让我们用一条线描摹出图像中的每个面部特征!
for facial_feature in face_landmarks.keys():
d.line(face_landmarks[facial_feature], width=5)
pil_image.show()
运行结果:
import face_recognition
# 加载图片
# 拜登照片
biden_image = face_recognition.load_image_file("known_people/biden.jpg")
# 奥巴马照片
obama_image = face_recognition.load_image_file("known_people/obama.jpg")
# 需要识别的照片(奥巴马)
unknown_image = face_recognition.load_image_file("unknown_pic/unknown1.jpg")
# 获取每个图像文件中每个人脸的人脸编码
# 由于每张图像中可能有不止一张脸,它返回一个编码列表。
# 但是因为我知道每张图片只有一张脸,所以我只关心每张图片的第一个编码,所以我抓取索引0。
try:
biden_face_encoding = face_recognition.face_encodings(biden_image)[0]
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]
unknown_face_encoding = face_recognition.face_encodings(unknown_image)[0]
except IndexError:
print("无法定位到人脸. Check the image files. Aborting...")
quit()
# 已知的人脸编码
known_faces = [
biden_face_encoding,
obama_face_encoding
]
# results是一个True/False数组,告诉未知面孔是否与known_faces数组中的任何人匹配
results = face_recognition.compare_faces(known_faces, unknown_face_encoding)
print("这是Biden吗? {}".format(results[0]))
print("这是Obama吗? {}".format(results[1]))
print("都不是,没见过? {}".format(not True in results))
运行结果:
这是Biden吗? False
这是Obama吗? True
都不是,没见过? False
from PIL import Image, ImageDraw
import time
import numpy as np
import face_recognition
# 加载奥巴马照片并获取其编码.
obama_image = face_recognition.load_image_file("known_people/obama.jpg")
obama_face_encoding = face_recognition.face_encodings(obama_image)[0]
# 加载拜登照片并获取其编码.
biden_image = face_recognition.load_image_file("known_people/biden.jpg")
biden_face_encoding = face_recognition.face_encodings(biden_image)[0]
# 已知的人脸编码数组
known_face_encodings = [
obama_face_encoding,
biden_face_encoding
]
# 对应的人的名称
known_face_names = [
"Barack Obama",
"Joe Biden"
]
# 加载需要识别的照片(奥巴马)
unknown_image = face_recognition.load_image_file("unknown_pic/unknown1.jpg")
# 找到其所有人脸位置并获取其编码
face_locations = face_recognition.face_locations(unknown_image)
face_encodings = face_recognition.face_encodings(unknown_image, face_locations)
# 将图像转换为pil格式的图像,以便我们可以使用Pillow库在其上绘制
pil_image = Image.fromarray(unknown_image)
# 创建一个Pillow ImageDraw Draw实例来绘制
draw = ImageDraw.Draw(pil_image)
# 循环遍历未知图像中发现的每张脸
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
# 看看这张脸是否与已知的脸匹配。
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
# 没验证
# If a match was found in known_face_encodings, just use the first one.
# if True in matches:
# first_match_index = matches.index(True)
# name = known_face_names[first_match_index]
# 给定人脸编码列表,将它们与已知的人脸编码进行比较,并得到每个比较人脸的欧氏距离。距离大小为面孔的相似程度。
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = known_face_names[best_match_index]
# 使用Pillow模块在脸部周围画一个框
draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))
# 在脸下面画一个带名字的标签
text_width, text_height = draw.textsize(name)
draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))
draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))
del draw
pil_image.show()
运行结果:
import face_recognition
import cv2
import numpy as np
import uuid
import os
# 获取视频流(这里拿了个海康相机RTSP流)
video_capture = cv2.VideoCapture("rtsp://admin:密码@192.168.*.*/h264/ch1/main/av_stream")
# 创建已知人脸编码及其名称的数组
known_face_encodings =[]
known_face_names=[]
# 已知的人脸库文件夹
known_face_dir = "known_people"
# 加载人脸库
# 遍历文件夹并获取文件夹名(对应人名)
for face_name in os.listdir(known_face_dir):
fece_name_dir = os.path.join(known_face_dir, face_name)
if os.path.isdir(fece_name_dir):
# 再获取该人名文件夹下所有图片名(人脸库图片)
for face_img in os.listdir(fece_name_dir):
face_img_filepath = os.path.join(fece_name_dir, face_img)
if face_img_filepath.endswith(".jpg"):
print(face_name)
# 加载人脸图片
face_img = face_recognition.load_image_file(face_img_filepath)
# 获取编码
face_encoding = face_recognition.face_encodings(face_img)[0]
known_face_encodings.append(face_encoding)
known_face_names.append(face_name)
# 初始化一些变量
# 人脸位置信息
face_locations = []
# 人脸编码信息
face_encodings = []
# 人脸名称
face_names = []
# 是否处理此帧
process_this_frame = True
while True:
# 抓取一帧视频
ret, frame = video_capture.read()
# 只处理每隔一帧视频以节省时间
if process_this_frame:
# 将视频帧调整为1/4大小,以便更快地进行人脸识别处理
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
# 将图像从BGR颜色(OpenCV使用)转换为RGB颜色(face_recognition使用)
# rgb_small_frame = small_frame[:, :, ::-1]
rgb_small_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)
# 找到当前视频帧中的所有人脸和人脸编码
face_locations = face_recognition.face_locations(rgb_small_frame,model="cnn")
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_names = []
for face_encoding in face_encodings:
print('detect face !')
# 看看这张脸是否与已知的脸匹配。
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
# 使用与新面孔距离最小的已知面孔
face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = known_face_names[best_match_index]
face_names.append(name)
# 显示结果
for (top, right, bottom, left), name in zip(face_locations, face_names):
# 缩放面部位置,因为我们检测到的帧被缩放到1/4大小
top *= 4
right *= 4
bottom *= 4
left *= 4
pic_name = "face_imgs/"+ name + str(uuid.uuid1()) +".jpg"
# 在脸周围画一个框
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
# 在脸下面画一个带名字的标签
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
font = cv2.FONT_HERSHEY_DUPLEX
cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)
cv2.imwrite(pic_name, frame) # 并把图片保存到路径的文件夹,注意容量
print('save face pic :',pic_name)
process_this_frame = not process_this_frame
cv2.imshow('Video', cv2.resize(frame,(1280,720)))
# Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()
其中文件夹结构:
发现的小问题:face_locations并不是每次都能准备识别人脸位置,有时候不是人脸也框了。