杰瑞科技汇

OpenCV Python人脸识别怎么实现?

目录

  1. 核心概念:人脸检测 vs. 人脸识别
  2. 环境准备
  3. 第一步:人脸检测
    • 使用 Haar 级联分类器
    • 使用深度学习模型 (DNN - 推荐)
  4. 第二步:人脸识别
    • 理解原理:将人脸转换为“数字指纹”
    • 使用 OpenCV 的 LBPHFaceRecognizer
    • 完整的人脸识别流程(从训练到识别)
  5. 进阶:使用更强大的模型 (FaceNet, DeepFace)
  6. 总结与最佳实践

核心概念:人脸检测 vs. 人脸识别

这是一个非常重要的区别,很多人会混淆它们。

OpenCV Python人脸识别怎么实现?-图1
(图片来源网络,侵删)
  • 人脸检测:任务是找到图像中人脸的位置,它只回答“哪里有人脸?”,不关心这个人是谁,它的输出通常是人脸的边界框。

    • 好比:在人群中找出所有的人脸,但不知道他们的名字。
  • 人脸识别:任务是在检测到人脸的基础上,识别这个人是谁,它需要将新检测到的人脸与一个已知人脸数据库进行比对,然后给出一个身份标签(如 "Alice", "Bob")。

    • 好比:在人群中找出 Alice、Bob 和 Charlie,并叫出他们的名字。

流程:人脸识别通常分为两步:

  1. 人脸检测:从图像/视频中定位人脸区域。
  2. 人脸识别:将检测到的人脸区域进行特征提取和比对。

环境准备

你需要安装必要的库。

OpenCV Python人脸识别怎么实现?-图2
(图片来源网络,侵删)
# 安装 OpenCV
pip install opencv-python
# 安装 OpenCV 的 contrib 包,它包含了一些高级模块,如人脸识别器
pip install opencv-contrib-python
# 安装 numpy,OpenCV 内部大量使用它
pip install numpy

第一步:人脸检测

我们将介绍两种主流的人脸检测方法。

使用 Haar 级联分类器 (经典方法)

这是 OpenCV 中最经典、最简单的方法,速度快,但精度相对较低,容易受光照、角度影响。

OpenCV 已经预训练好了很多人脸检测的模型文件(XML 格式),我们直接下载即可。 下载地址:https://github.com/opencv/opencv/tree/master/data/haarcascades

我们主要需要 haarcascade_frontalface_default.xml

OpenCV Python人脸识别怎么实现?-图3
(图片来源网络,侵删)

代码示例:

import cv2
import os
# 加载预训练的人脸检测模型
# 请确保你已下载该文件并放在与脚本相同的目录下
# 或者提供完整路径
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 读取图片
image_path = 'path/to/your/image.jpg' # 替换为你的图片路径
image = cv2.imread(image_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图,检测器只需要灰度图
# 检测人脸
# scaleFactor: 图像缩放比例,用于创建图像金字塔
# minNeighbors: 每个候选矩形应包含的邻近矩形数,值越大,检测越严格,误检率越低
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 在检测到的人脸周围画上矩形框
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 显示结果
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

使用深度学习模型 DNN (推荐)

这种方法基于深度学习(如 Single Shot Detector - SSD),精度远高于 Haar 级联,速度也很快,是目前的主流方法。

我们需要两个预训练文件:

  1. 模型架构文件deploy.prototxt
  2. 模型权重文件res10_300x300_ssd_iter_140000.caffemodel

下载地址:https://github.com/opencv/opencv_3rdparty/tree/dnn_samples_face_detector_20250830

代码示例:

import cv2
# 加载模型
model_file = "res10_300x300_ssd_iter_140000.caffemodel"
config_file = "deploy.prototxt"
net = cv2.dnn.readNetFromCaffe(config_file, model_file)
# 读取图片
image = cv2.imread('path/to/your/image.jpg') # 替换为你的图片路径
(h, w) = image.shape[:2]
# 预处理图像:创建一个 4D blob (图像的 blob 表示)
# 300x300 是输入尺寸,1.0 是缩放因子,(104.0, 177.0, 123.0) 是均值减法
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0,
    (300, 300), (104.0, 177.0, 123.0))
# 将 blob 作为输入,进行前向传播
net.setInput(blob)
detections = net.forward()
# 遍历检测结果
for i in range(detections.shape[2]):
    confidence = detections[0, 0, i, 2]
    # 过滤掉低置信度的检测结果
    if confidence > 0.7: # 0.7 是置信度阈值,可以调整
        # 计算人脸的边界框坐标
        box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
        (startX, startY, endX, endY) = box.astype("int")
        # 确保边界框在图像范围内
        (startX, startY) = (max(0, startX), max(0, startY))
        (endX, endY) = (min(w - 1, endX), min(h - 1, endY))
        # 画框
        cv2.rectangle(image, (startX, startY), (endX, endY), (0, 255, 0), 2)
# 显示结果
cv2.imshow('DNN Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

第二步:人脸识别

现在我们进入真正的“识别”阶段,我们将使用 OpenCV 内置的 LBPHFaceRecognizer

理解原理

人脸识别的核心是将一张人脸图片转换成一个固定长度的特征向量(可以理解为一串数字,也叫“嵌入向量”或“数字指纹”),当需要识别一个人时,我们提取他的人脸特征向量,然后与数据库中所有已知人脸的特征向量进行比较,找到最相似的一个(通常通过计算距离,如欧氏距离),从而确定身份。

使用 OpenCV 的 LBPHFaceRecognizer

LBPH (Local Binary Patterns Histograms) 是一种经典且有效的人脸识别算法,对光照变化不敏感,易于实现。

完整流程:从数据收集到识别

步骤 1:准备数据集

你需要为每个要识别的人创建一个文件夹,文件夹名就是他的标签(ID),在这个文件夹里,放入这个人的多张不同角度、不同表情的照片(至少一张,越多越好)。

目录结构如下:

dataset/
├── person_1/  (标签为 1)
│   ├── 1.jpg
│   ├── 2.jpg
│   └── 3.jpg
├── person_2/  (标签为 2)
│   ├── 1.jpg
│   └── 2.jpg
└── person_3/  (标签为 3)
    ├── 1.jpg
    └── 2.jpg

步骤 2:编写训练脚本 (train.py)

这个脚本的目的是读取所有图片,训练一个识别器模型,并保存模型。

import cv2
import os
import numpy as np
# 人脸数据集路径
data_path = "dataset/"
# 获取所有子文件夹(代表不同的人)
people = [person for person in os.listdir(data_path) if os.path.isdir(os.path.join(data_path, person))]
# 为每个人分配一个唯一的标签ID
labels = []
faces = []
label_id = 0
for person in people:
    person_path = os.path.join(data_path, person)
    # 使用 Haar 级联检测器
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    for image_name in os.listdir(person_path):
        image_path = os.path.join(person_path, image_name)
        image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 读取为灰度图
        if image is None:
            continue
        faces_detected = face_cascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5)
        for (x, y, w, h) in faces_detected:
            # 提取人脸区域
            face_roi = image[y:y+h, x:x+w]
            # 调整大小,因为训练器需要统一尺寸
            face_roi = cv2.resize(face_roi, (100, 100))
            faces.append(face_roi)
            labels.append(label_id)
    label_id += 1
# 将列表转换为 NumPy 数组
faces = np.array(faces)
labels = np.array(labels)
# 打印信息
print(f"总共检测到 {len(faces)} 张人脸,对应 {len(np.unique(labels))} 个不同的人。")
# 创建并训练 LBPH 人脸识别器
# recognizer = cv2.face.LBPHFaceRecognizer_create()
# 注意:在较新版本的 OpenCV 中,LBPHFaceRecognizer_create() 可能需要从 face 模块导入
from cv2 import face
recognizer = face.LBPHFaceRecognizer_create()
print("开始训练模型...")
recognizer.train(faces, labels)
print("模型训练完成!")
# 保存训练好的模型
recognizer.save("face_trainer.yml")
print("模型已保存为 face_trainer.yml")
# 可选:保存标签映射,以便后续使用
np.save("labels.npy", labels)
print("标签已保存为 labels.npy")

步骤 3:编写识别脚本 (recognize.py)

这个脚本用于加载训练好的模型,并对实时摄像头捕获到的人脸进行识别。

import cv2
import numpy as np
from cv2 import face
# 加载训练好的模型
recognizer = face.LBPHFaceRecognizer_create()
recognizer.read("face_trainer.yml")
# 加载标签映射
labels = np.load("labels.npy")
# 将标签ID映射回人名 ( 0 -> "person_1")
# 注意:这里需要与训练时的文件夹顺序一致
people = [d for d in os.listdir("dataset/") if os.path.isdir(os.path.join("dataset/", d))]
# 加载人脸检测器
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# 打开摄像头
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if not ret:
        break
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    for (x, y, w, h) in faces:
        # 提取人脸区域
        roi_gray = gray[y:y+h, x:x+w]
        roi_gray = cv2.resize(roi_gray, (100, 100)) # 必须与训练时的大小一致
        # 进行预测
        label_id, confidence = recognizer.predict(roi_gray)
        # confidence 是置信度,值越小表示越确定
        if confidence < 70: # 置信度阈值,可以调整
            name = people[label_id]
            confidence_text = f"{confidence:.2f}"
        else:
            name = "Unknown"
            confidence_text = f"{confidence:.2f}"
        # 在画面上显示结果
        cv2.putText(frame, name, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
        cv2.putText(frame, confidence_text, (x, y+h+20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
    cv2.imshow('Face Recognition', frame)
    # 按 'q' 键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

进阶:使用更强大的模型

OpenCV 自带的 LBPH 算法虽然简单,但精度有限,在实际应用中,我们通常使用基于深度学习的模型,如 FaceNetDeepFace 等。

这些模型在大型数据集上训练,能够生成更具区分度的特征向量,识别率极高。

使用 deepface 库 (最简单)

deepface 是一个基于 Python 的高级人脸识别库,它封装了 FaceNet、VGG-Face、SFace 等强大模型,使用起来非常方便。

安装:

pip install deepface

代码示例 (极其简单):

from deepface import DeepFace
import cv2
# 对比两张图片
# result = DeepFace.verify(img1_path = "img1.jpg", img2_path = "img2.jpg")
# print(result)
# 实时摄像头识别
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if not ret:
        break
    try:
        # 使用 VGG-Face 模型进行识别
        # 它会返回识别结果和置信度
        result = DeepFace.analyze(frame, actions=['emotion', 'age', 'gender', 'race'], enforce_detection=False)
        # 显示第一个检测到的人的结果
        if isinstance(result, list):
            result = result[0]
        # 在画面上显示结果
        cv2.putText(frame, f"{result['dominant_gender']}, {result['age']}", (50, 50), 
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv2.putText(frame, f"{result['dominant_race']}", (50, 100), 
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv2.putText(frame, f"{result['dominant_emotion']}", (50, 150), 
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    except Exception as e:
        # 如果没有检测到人脸,会抛出异常
        pass
    cv2.imshow('DeepFace Analysis', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

总结与最佳实践

特性 Haar 级联 DNN 检测器 LBPH 识别器 DeepFace / FaceNet
用途 人脸检测 人脸检测 人脸识别 人脸识别
原理 传统机器学习 深度学习 传统特征提取 深度学习
速度 非常快 中等 较慢 (CPU) / 快 (GPU)
精度 低,易受干扰 中等,依赖数据质量 非常高
易用性 简单 简单 中等 非常简单
适用场景 嵌入式设备,对速度要求极高 大多数通用场景 快速原型,小型应用 对精度要求高的商业应用

最佳实践建议

  1. 检测阶段始终优先使用 DNN 检测器 (cv2.dnn),它在精度和速度之间取得了很好的平衡,是目前工业界和学术界的主流选择。
  2. 识别阶段
    • 入门/快速验证:使用 OpenCV 的 LBPH,优点是无需额外依赖,易于上手,缺点是精度有限,对数据质量要求高。
    • 生产环境/高精度需求:使用 deepface 库或基于 FaceNet 的自建模型,它们能提供远超传统方法的识别率,是构建可靠人脸识别系统的基石。
  3. 数据质量是关键:无论使用哪种识别算法,高质量、多样化的训练数据都是最重要的,确保训练图片中的人脸清晰、光线良好、角度多样。
  4. 调整置信度阈值:在识别结果中,confidencedistance 是一个非常重要的指标,你需要根据实际应用场景调整这个阈值,以平衡“误识率”(把别人认成你)和“拒识率”(没认出自己)。
分享:
扫描分享到社交APP
上一篇
下一篇