目录
- 核心概念:人脸检测 vs. 人脸识别
- 环境准备
- 人脸检测
- 使用 Haar 级联分类器
- 使用 DNN 模型(更推荐)
- 人脸识别
- 使用 OpenCV 的 LBPH (Local Binary Patterns Histograms) 人脸识别器
- 完整代码示例:从检测到识别
- 进阶与最佳实践
- 使用更先进的模型(如 FaceNet, DeepFace)
- 处理视频流
- 性能优化
核心概念:人脸检测 vs. 人脸识别
这是两个经常被混淆但完全不同的概念:

- 人脸检测:目标是找到图像中人脸的位置,它只回答“哪里有人脸?”,不关心这个人是谁,它的输出通常是图像中人脸的边界框坐标。
- 应用场景:人脸解锁、美颜相机、拍照时自动对焦。
- 人脸识别:目标是识别出人脸的身份,它回答“这是谁?”,这个过程通常包括人脸检测,然后提取人脸的特征,并与数据库中已知人脸的特征进行比对。
- 应用场景:手机解锁、门禁系统、身份验证。
流程总结:人脸识别 的流程通常是:图像 -> 人脸检测 -> 人脸对齐/裁剪 -> 特征提取 -> 特征比对,我们今天要实现的就是这个完整流程。
环境准备
你需要安装必要的库。
# 安装 OpenCV pip install opencv-python # 安装 NumPy (OpenCV 内部依赖) pip install numpy # 可选:用于更高级的人脸识别模型 pip install tensorflow pip install deepface
重要:获取预训练模型文件
OpenCV 自带了一些预训练模型,我们需要下载它们。

-
人脸检测模型:
- Haar 级联模型:文件名
haarcascade_frontalface_default.xml,这是一个经典但速度较快、准确率一般的模型。 - DNN 模型:文件名
opencv_face_detector_uint8.pb和opencv_face_detector.pbtxt,这是一个基于 Caffe 模型的现代 DNN,准确率更高,推荐使用。 - 下载地址:你可以从 OpenCV 的 GitHub 仓库或官方模型库下载,这里提供一个常用的下载链接:
下载后,将这两个文件(或 Haar 文件)放在你的 Python 脚本同目录下的一个
models文件夹中,以便代码可以找到它们。 - Haar 级联模型:文件名
-
人脸识别模型:
- OpenCV 提供了三种内置的人脸识别算法:
Eigenfaces,Fisherfaces, 和LBPH。 - 我们将使用
LBPH,因为它对光照变化和姿态变化不那么敏感,效果最好。 - 训练数据:这些模型需要你自己提供一组已知人物的人脸图片来进行训练,模型会学习这些人的特征。
- OpenCV 提供了三种内置的人脸识别算法:
步骤一:人脸检测
我们先来看如何检测人脸。

方法 A:使用 Haar 级联分类器 (简单)
import cv2
# 加载 Haar 级联分类器
face_cascade = cv2.CascadeClassifier('models/haarcascade_frontalface_default.xml')
# 读取图像
img = cv2.imread('test.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像,检测更快
# 检测人脸
# scaleFactor: 图像缩放比例,用于构建图像金字塔
# minNeighbors: 每个候选矩形应包含的邻近像素点数,值越大,检测越严格,越不容易误检
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)
# 在检测到的人脸周围画矩形
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 显示结果
cv2.imshow('Faces detected with Haar', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
方法 B:使用 DNN 模型 (推荐)
这种方法更准确,是现代应用的首选。
import cv2
# 加载模型
# pbtxt 是模型配置文件,pb 是模型权重文件
net = cv2.dnn.readNetFromTensorflow('models/opencv_face_detector_uint8.pb', 'models/opencv_face_detector.pbtxt')
# 读取图像
img = cv2.imread('test.jpg')
(h, w) = img.shape[:2]
# 从输入图像创建一个 "blob" (二进制大对象)
# 300x300 是 DNN 模型期望的输入尺寸
# 1.0 是缩放因子,0.0 是均值减法
blob = cv2.dnn.blobFromImage(img, scalefactor=1.0, size=(300, 300), mean=(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:
# 计算人脸边界框的坐标
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(img, (startX, startY), (endX, endY), (0, 255, 0), 2)
# 显示结果
cv2.imshow('Faces detected with DNN', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
步骤二:人脸识别 (使用 LBPH)
现在我们来整合检测和识别,我们将创建一个简单的系统,可以识别出图像中的某个人是否是预先注册的 "Alice" 或 "Bob"。
完整代码示例
这个示例需要你创建一个 dataset 文件夹,里面为每个已知人物创建一个子文件夹,并放入他们的人脸照片。
目录结构:
.
├── face_recognition.py
├── models/
│ ├── opencv_face_detector_uint8.pb
│ └── opencv_face_detector.pbtxt
└── dataset/
├── person1/
│ ├── person1_1.jpg
│ └── person1_2.jpg
└── person2/
├── person2_1.jpg
└── person2_2.jpg
face_recognition.py 代码:
import cv2
import numpy as np
import os
# --- 1. 准备数据 ---
# 创建人脸识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 准备训练数据
def prepare_training_data(data_folder_path):
dirs = os.listdir(data_folder_path)
faces = []
labels = []
label_ids = {}
current_id = 0
for person_name in dirs:
person_dir_path = os.path.join(data_folder_path, person_name)
if not os.path.isdir(person_dir_path):
continue
images = os.listdir(person_dir_path)
for image_name in images:
if image_name.endswith('.jpg') or image_name.endswith('.png'):
image_path = os.path.join(person_dir_path, image_name)
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 使用 Haar 级联检测器找到人脸
# 注意:这里假设每张图里只有一张人脸
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
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]
faces.append(face_roi)
# 为每个人分配一个唯一的 ID
if person_name not in label_ids:
label_ids[person_name] = current_id
current_id += 1
labels.append(label_ids[person_name])
return faces, labels, label_ids
# --- 2. 训练模型 ---
print("Preparing data...")
faces, labels, label_ids = prepare_training_data("dataset")
print(f"Data prepared. {len(faces)} faces and {len(labels)} labels found.")
print("Training the model...")
# 训练 LBPH 模型
recognizer.train(faces, np.array(labels))
print("Model trained successfully.")
# 保存模型和标签映射,以便下次使用
recognizer.save("trainer.yml")
# 注意:label_ids 需要单独保存,因为 LBPH 模型只保存了ID,不保存名字
np.save("label_ids.npy", label_ids)
print("Model and label IDs saved.")
# --- 3. 进行识别 ---
# 加载已训练的模型和标签
recognizer.read("trainer.yml")
label_ids = np.load("label_ids.npy", allow_pickle=True).item()
# 创建一个反向映射,从ID到名字
id_to_name = {v: k for k, v in label_ids.items()}
# 加载 DNN 人脸检测器(推荐)
net = cv2.dnn.readNetFromTensorflow('models/opencv_face_detector_uint8.pb', 'models/opencv_face_detector.pbtxt')
# 读取一张待识别的图片
test_image_path = "test.jpg"
img = cv2.imread(test_image_path)
(h, w) = img.shape[:2]
# 创建 blob 并进行人脸检测
blob = cv2.dnn.blobFromImage(img, scalefactor=1.0, size=(300, 300), mean=(104.0, 177.0, 123.0))
net.setInput(blob)
detections = net.forward()
# 遍历检测到的人脸
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > 0.7:
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
# 裁剪人脸区域
face_roi = img[startY:endY, startX:endX]
# 将人脸区域转换为灰度图
gray_roi = cv2.cvtColor(face_roi, cv2.COLOR_BGR2GRAY)
# 使用训练好的识别器进行预测
label_id, confidence = recognizer.predict(gray_roi)
# 获取预测的名字
predicted_name = id_to_name.get(label_id, "Unknown")
# 在图像上显示结果
text = f"{predicted_name} ({confidence:.2f})"
cv2.rectangle(img, (startX, startY), (endX, endY), (0, 255, 0), 2)
cv2.putText(img, text, (startX, startY - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
# 显示最终结果
cv2.imshow('Face Recognition Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
进阶与最佳实践
A. 使用更先进的模型 (FaceNet, DeepFace)
OpenCV 内置的 LBPH 模型虽然简单,但准确率有限,对于要求更高的应用,可以考虑使用深度学习模型。
-
DeepFace:这是一个基于 Python 的强大人脸识别库,封装了 FaceNet, VGG-Face, Google FaceNet, OpenFace 等多种 SOTA 模型,使用起来非常方便。
pip install deepface
from deepface import DeepFace # 验证两张图片是否为同一个人 result = DeepFace.verify(img1_path, img2_path) print(result) # 返回一个包含 'verified' (布尔值) 和 'distance' 的字典 # 识别图片中的人是谁 df = DeepFace.find(img_path = "test.jpg", db_path = "dataset") print(df) # 返回一个 DataFrame,包含匹配的图片和人物信息
DeepFace是快速原型开发和实现高精度人脸识别的最佳选择。
B. 处理视频流
识别静态图片很简单,但识别视频(如摄像头实时画面)是常见需求,核心思路是循环读取视频帧,对每一帧执行上述的检测和识别逻辑。
import cv2
# ... (加载模型、识别器等代码与上面相同) ...
# 打开摄像头
cap = cv2.VideoCapture(0) # 0 表示默认摄像头
while True:
# 读取一帧
ret, frame = cap.read()
if not ret:
break
# ... (将上面的 DNN 检测和识别逻辑放在这里,对 'frame' 进行处理) ...
#
# blob = cv2.dnn.blobFromImage(frame, ...)
# ... (检测和识别代码) ...
# cv2.imshow('Video', frame_with_labels)
# 显示处理后的帧
cv2.imshow('Video', frame)
# 按 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
C. 性能优化
- 降低分辨率:对于视频流,可以适当降低输入帧的分辨率,以加快处理速度。
- 跳帧处理:不一定需要对每一帧都进行人脸识别,可以每隔几帧处理一次。
- 多线程:可以将人脸检测和特征提取/比对放在不同的线程中,实现流水线处理,提高效率。
- 使用 GPU:如果你的 OpenCV 是支持 CUDA 的版本,可以将 DNN 模型加载到 GPU 上进行加速。
希望这份详细的指南能帮助你从零开始使用 Python 和 OpenCV 进行人脸识别!
