Skip to content

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()