目录
- 核心概念:人脸检测 vs. 人脸识别
- 环境准备
- 第一步:人脸检测
- 使用 Haar 级联分类器
- 使用深度学习模型 (DNN - 推荐)
- 第二步:人脸识别
- 理解原理:将人脸转换为“数字指纹”
- 使用 OpenCV 的
LBPHFaceRecognizer - 完整的人脸识别流程(从训练到识别)
- 进阶:使用更强大的模型 (FaceNet, DeepFace)
- 总结与最佳实践
核心概念:人脸检测 vs. 人脸识别
这是一个非常重要的区别,很多人会混淆它们。

-
人脸检测:任务是找到图像中人脸的位置,它只回答“哪里有人脸?”,不关心这个人是谁,它的输出通常是人脸的边界框。
- 好比:在人群中找出所有的人脸,但不知道他们的名字。
-
人脸识别:任务是在检测到人脸的基础上,识别这个人是谁,它需要将新检测到的人脸与一个已知人脸数据库进行比对,然后给出一个身份标签(如 "Alice", "Bob")。
- 好比:在人群中找出 Alice、Bob 和 Charlie,并叫出他们的名字。
流程:人脸识别通常分为两步:
- 人脸检测:从图像/视频中定位人脸区域。
- 人脸识别:将检测到的人脸区域进行特征提取和比对。
环境准备
你需要安装必要的库。

# 安装 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。

代码示例:
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 级联,速度也很快,是目前的主流方法。
我们需要两个预训练文件:
- 模型架构文件:
deploy.prototxt - 模型权重文件:
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 算法虽然简单,但精度有限,在实际应用中,我们通常使用基于深度学习的模型,如 FaceNet、DeepFace 等。
这些模型在大型数据集上训练,能够生成更具区分度的特征向量,识别率极高。
使用 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) |
| 精度 | 低,易受干扰 | 高 | 中等,依赖数据质量 | 非常高 |
| 易用性 | 简单 | 简单 | 中等 | 非常简单 |
| 适用场景 | 嵌入式设备,对速度要求极高 | 大多数通用场景 | 快速原型,小型应用 | 对精度要求高的商业应用 |
最佳实践建议:
- 检测阶段:始终优先使用 DNN 检测器 (
cv2.dnn),它在精度和速度之间取得了很好的平衡,是目前工业界和学术界的主流选择。 - 识别阶段:
- 入门/快速验证:使用 OpenCV 的
LBPH,优点是无需额外依赖,易于上手,缺点是精度有限,对数据质量要求高。 - 生产环境/高精度需求:使用
deepface库或基于 FaceNet 的自建模型,它们能提供远超传统方法的识别率,是构建可靠人脸识别系统的基石。
- 入门/快速验证:使用 OpenCV 的
- 数据质量是关键:无论使用哪种识别算法,高质量、多样化的训练数据都是最重要的,确保训练图片中的人脸清晰、光线良好、角度多样。
- 调整置信度阈值:在识别结果中,
confidence或distance是一个非常重要的指标,你需要根据实际应用场景调整这个阈值,以平衡“误识率”(把别人认成你)和“拒识率”(没认出自己)。
