007 Dlib人脸识别
Dlib人脸识别基本流程(多线程)¶
主线程
graph TD
A[主程序开始] --> B[加载已知人脸数据]
B --> C[启动处理线程]
C --> D[初始化视频捕获]
D --> E{读取下一帧}
E -->|成功| F[缩小帧尺寸]
F --> G{输入队列是否已满?}
G -->|否| H[放入输入队列]
H --> I[尝试从输出队列获取处理结果]
I --> J{输出队列有数据?}
J -->|是| K[显示处理后的帧]
K --> L[控制播放速度]
L --> M{用户按Q键?}
M -->|否| E
M -->|是| N[设置停止信号]
G -->|是| E
J -->|否| E
E -->|失败| N
N --> O[释放资源并结束程序]
处理线程
flowchart TD
P[线程启动] --> Q{停止信号已设置且队列空?}
Q -->|是| R[线程结束]
Q -->|否| S[尝试从输入队列取帧]
S --> T{获取成功?}
T -->|是| U[人脸检测与识别]
U --> V[绘制识别结果]
V --> W[放入输出队列]
W --> Q
T -->|否| Q
代码:¶
多线程
import glob
import dlib
import cv2
import numpy as np
import os
import threading
import queue
import time
video_path = '935167194_nb3-1-30080.mp4'
known_faces_path = './known_faces'
# 全局变量
input_queue = queue.Queue(maxsize=10)
output_queue = queue.Queue(maxsize=10)
stop_signal = threading.Event()
def load_known_faces():
"""加载已知人脸"""
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
facerec = dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat')
known_descriptions = []
known_names = ['DYGG', 'GiaoGe']
for f in glob.glob(os.path.join(known_faces_path, "*.png")):
img = dlib.load_rgb_image(f)
faces = detector(img, 1)
for i, d in enumerate(faces):
shape = predictor(img, d)
face_descriptor = facerec.compute_face_descriptor(img, shape)
v = np.array(face_descriptor)
known_descriptions.append(v)
return known_descriptions, known_names, detector, predictor, facerec
def process_frames(known_descriptions, known_names, detector, predictor, facerec):
"""处理帧的线程函数"""
tolerance = 0.6
while not stop_signal.is_set() or not input_queue.empty():
try:
# 从队列获取帧,设置超时避免无限等待
frame_data = input_queue.get(timeout=1)
frame_id, frame = frame_data
except queue.Empty:
continue
# 处理帧
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
faces = detector(frame_rgb, 1)
for i, d in enumerate(faces):
shape = predictor(frame_rgb, d)
face_descriptor = facerec.compute_face_descriptor(frame_rgb, shape)
np_face_descriptor = np.array(face_descriptor)
name = 'unknown'
for idx, desc in enumerate(known_descriptions):
dis = np.linalg.norm(desc - np_face_descriptor)
if dis < tolerance:
name = known_names[idx]
break
# 绘制识别结果
font = cv2.FONT_HERSHEY_PLAIN
cv2.putText(frame, name, (d.left() + 5, d.bottom() + 10), font, 1, (255, 255, 255), 1)
cv2.rectangle(frame, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 2)
# 将处理结果放入输出队列
output_queue.put((frame_id, frame))
input_queue.task_done()
def main():
# 加载已知人脸
known_descriptions, known_names, detector, predictor, facerec = load_known_faces()
# 启动处理线程
processing_thread = threading.Thread(
target=process_frames,
args=(known_descriptions, known_names, detector, predictor, facerec)
)
processing_thread.daemon = True
processing_thread.start()
# 读取视频
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print('open_file false')
stop_signal.set()
return
# 获取视频信息
fps = cap.get(cv2.CAP_PROP_FPS)
frame_delay = 1 / fps if fps > 0 else 0.03
frame_count = 0
last_display_time = time.time()
# 主循环:读取视频帧并显示处理结果
while cap.isOpened() and not stop_signal.is_set():
ret, frame = cap.read()
if not ret:
break
# 缩小帧以加快处理速度
frame = cv2.resize(frame, (
int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) / 4),
int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) / 4)
))
# 将帧放入处理队列
try:
input_queue.put((frame_count, frame), timeout=0.1)
frame_count += 1
except queue.Full:
# 队列已满,跳过此帧
continue
# 尝试从输出队列获取处理后的帧
try:
processed_frame_id, processed_frame = output_queue.get_nowait()
cv2.imshow("FACE_REC", processed_frame)
output_queue.task_done()
# 计算实际延迟,保持视频播放速度
elapsed = time.time() - last_display_time
if elapsed < frame_delay:
time.sleep(frame_delay - elapsed)
last_display_time = time.time()
except queue.Empty:
# 没有处理完成的帧,继续
pass
# 检查用户是否按下退出键
if cv2.waitKey(1) & 0xFF == ord('q'):
stop_signal.set()
break
# 清理资源
stop_signal.set()
cap.release()
cv2.destroyAllWindows()
# 等待处理线程结束
processing_thread.join(timeout=2.0)
if __name__ == '__main__':
main()
Dlib人脸识别基本流程(单线程)¶
flowchart TD
A[程序开始] --> B[加载人脸检测器、特征点检测器和识别模型]
B --> C[加载已知人脸数据]
C --> D[遍历已知人脸图片文件夹]
D --> E[读取并处理每张图片]
E --> F[检测人脸并提取特征向量]
F --> G[保存到已知人脸描述符列表]
G --> H{是否还有图片?}
H -->|是| E
H -->|否| I[打开视频文件]
I --> J{视频是否成功打开?}
J -->|否| K[输出错误信息并退出]
J -->|是| L[读取视频帧]
L --> M{是否成功读取帧?}
M -->|否| N[释放资源并退出]
M -->|是| O[调整帧大小并转换颜色空间]
O --> P[检测当前帧中的人脸]
P --> Q{是否检测到人脸?}
Q -->|否| R[显示帧]
Q -->|是| S[对每个人脸进行识别]
S --> T[提取人脸特征点]
T --> U[计算人脸描述符]
U --> V[与已知人脸比较计算距离]
V --> W[确定身份]
W --> X[在帧上绘制识别结果和边界框]
X --> R
R --> Y{用户是否按键退出?}
Y -->|是| N
Y -->|否| L
单线程
代码¶
import glob
import dlib
import cv2
import numpy as np
import os
video_path = '935167194_nb3-1-30080.mp4'
known_faces_path = './known_faces'
def main():
detector = dlib.get_frontal_face_detector() #加载人脸探测器
predictor = dlib.shape_predictor('shape_predictor_5_face_landmarks.dat') #加载特征点检测器
facerec = dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat') #加载人脸识别模型
known_descriptions = [] # 已知人脸描述符
known_names = [
'DYGG',
'GiaoGe'
]
# 识别已知人脸并保存
for f in glob.glob(os.path.join(known_faces_path, "*.png")):
img = dlib.load_rgb_image(f)
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
faces = detector(img,1) # 人脸检测
for i ,d in enumerate(faces):
shape = predictor(img,d) #识别人脸特征点
face_descriptor = facerec.compute_face_descriptor(img,shape) #计算特征向量
v = np.array(face_descriptor) #将特征向量转化成 numpy array类型
known_descriptions.append(v) #保存人脸特征向量(描述符)
# 读取视频
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print('open_file false')
exit()
while cap.isOpened():
ret,frame = cap.read()
if not ret:
print('no frame output')
cap.release()
cv2.destroyAllWindows()
exit()
frame = cv2.resize(frame,
(int((cap.get(cv2.CAP_PROP_FRAME_WIDTH) / 4)),
int((cap.get(cv2.CAP_PROP_FRAME_HEIGHT) / 4))))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 将图片转化为RGB格式
frame_gray = cv2.cvtColor(frame,cv2.COLOR_RGB2GRAY)
faces = detector(frame,1)
for i,d in enumerate(faces):
shape = predictor(frame,d)
face_descriptor = facerec.compute_face_descriptor(frame,shape)
np_face_descriptor = np.array(face_descriptor)
tolerance = 0.6
name = 'unknown'
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
for desc in range(len(known_descriptions)):
dis = np.linalg.norm(known_descriptions[desc] - np_face_descriptor) #计算欧氏距
if dis < tolerance:
name = known_names[desc]
break
else:
name = 'unknown'
font = cv2.FONT_HERSHEY_PLAIN
cv2.putText(frame, name, (d.left() + 5, d.bottom() + 10), font, 1, (255, 255, 255), 1)
cv2.rectangle(frame, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 2)
cv2.imshow("FACE_REC",frame)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()