本文将从、核心原理、代码实现、功能优化四个维度,手把手教你实现基于 OpenCV+LBPH 的实时人脸检测,并解决中文标注显示的痛点,最终实现摄像头实时识别人脸并显示中文姓名的效果。
一、前置准备
-
人脸样本图片:准备待识别人员的人脸照片,建议为灰度图 / 彩色图均可(代码会自动转灰度)、正面人脸、光照均匀,每个人员准备多张(2-5 张)不同角度 / 轻微表情的样本,命名如 1.jpg、2.jpg(人员 A),1.png、2.png(人员 B),放在代码同目录下;
-
Haar 级联分类器配置文件:下载
haarcascade_frontalface_default.xml(OpenCV 官方人脸检测分类器),放在代码同目录下,可从OpenCV 官方仓库获取; -
中文字体文件:Windows 系统可直接使用系统自带字体,如黑体(simhei.ttf),路径默认为
C:/Windows/Fonts/simhei.ttf;Linux/Mac 系统需自行指定中文字体路径(如思源黑体)。
二、核心原理详解
- 人脸检测:Haar 级联分类器
Haar 级联分类器是基于Adaboost 算法的特征分类器,通过提取人脸的灰度特征(如眼睛比脸颊暗、鼻梁比两侧亮),构建多层级的分类器,快速从图像中筛选出人脸区域。
-
优势:检测速度快、轻量,无需 GPU,适合实时视频流处理;
-
核心参数:
scaleFactor(图像缩放比例)、minNeighbors(候选矩形的邻域阈值)、minSize(最小检测人脸尺寸),参数调优直接影响检测精度与速度。
- 人脸识别:LBPH 局部二值模式直方图
LBPH 是 OpenCV 内置的三大人脸识别算法(EigenFace、FisherFace、LBPH)中最实用的一种,专为灰度图设计,无需对人脸进行对齐 / 归一化预处理,对光照、轻微姿态变化鲁棒性强。
-
核心原理:对人脸灰度图的每个像素,与周围 8 个像素比较生成二值码,统计局部区域的二值模式直方图,通过对比待识别人脸与训练样本的直方图相似度,判断身份;
-
关键参数:
threshold(识别阈值),置信度(匹配值)越小表示匹配度越高,超过阈值则判定为 "无法识别",本文设置阈值为 120(可根据样本情况调整); -
训练逻辑:将每个人员的多张人脸样本标注统一标签(如 0、1),通过
train方法训练模型,模型会学习每个标签对应的人脸特征。
- OpenCV 中文绘制解决方案
OpenCV 的cv2.putText函数仅支持英文字符,无法直接绘制中文,核心解决思路是格式转换 + PIL 绘制:
-
将 OpenCV 的 BGR 格式图像转换为 PIL 的 RGB 格式(两者色彩通道顺序相反);
-
通过 PIL 的
ImageFont加载中文字体,ImageDraw绘制中文文本; -
将绘制完成的 PIL 图像转换回 OpenCV 的 BGR 格式,完成中文标注。
三、完整代码实现
1. 库导入
python
import cv2 # 计算机视觉核心:检测、识别、视频采集、绘图
import numpy as np # 图像数组处理、格式转换
from PIL import Image, ImageDraw, ImageFont # 解决中文绘制问题
2. 全局参数配置
将易修改的参数集中配置,便于后续调试与扩展,包括人脸样本、标签映射、分类器路径、字体路径等。
python
# 1. 加载人脸训练样本(灰度图模式,cv2.IMREAD_GRAYSCALE)
images = []
images.append(cv2.imread('1.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('2.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('1.png', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('2.png', cv2.IMREAD_GRAYSCALE))
# 2. 加载Haar人脸检测分类器
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 3. 样本标签:相同人员标注相同标签(0/1),与样本列表一一对应
labels = [0, 0, 1, 1]
# 4. 标签-姓名映射字典:-1为无法识别(超过阈值)
dic = {0: '林园昕', 1: '赵丽颖', -1: '无法识别'}
# 5. 中文字体路径(Windows黑体,根据系统调整)
FONT_PATH = "C:/Windows/Fonts/simhei.ttf"
注意 :样本列表images与标签列表labels的索引必须一一对应,否则训练模型会出现身份错乱
3.OpenCV 中文绘制函数
单独封装中文绘制函数,提高代码复用性,函数包含完整的参数说明,支持自定义字体大小、颜色、绘制位置。
python
def cv2_draw_chinese(img, text, pos, font_path, font_size=20, color=(0, 0, 255)):
# 步骤1:OpenCV BGR → PIL RGB(色彩通道转换)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
pil_img = Image.fromarray(img_rgb)
# 步骤2:创建PIL绘图对象,加载中文字体(必须指定大小,否则报错)
draw = ImageDraw.Draw(pil_img)
font = ImageFont.truetype(font_path, font_size, encoding="utf-8")
# 步骤3:绘制中文(Pillow颜色为RGB,需转换OpenCV的BGR)
draw.text(pos, text, fill=(color[2], color[1], color[0]), font=font)
# 步骤4:PIL RGB → OpenCV BGR(转换回原格式)
img_bgr = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
return img_bgr
注意:PIL 的颜色通道是 RGB,而 OpenCV 是 BGR,绘制时必须进行通道转换,否则颜色会出现错乱(如红色变成蓝色)。
4. 模型初始化与训练:LBPH 人脸识别模型
初始化 OpenCV 的 LBPH 人脸识别模型,设置识别阈值,并用准备好的人脸样本与标签训练模型,训练完成后即可用于实时识别。
python
# 初始化LBPH人脸识别模型,设置识别阈值为120
recognizer = cv2.face.LBPHFaceRecognizer_create(threshold=120)
recognizer.train(images, np.array(labels))
5. 摄像头实时人脸检测与识别
实现视频帧采集、人脸检测、身份识别、绘图标注、快捷键退出的完整逻辑。
python
cap=cv2.VideoCapture(0)
while True:
ret,img=cap.read()#读取每一帧的画面
if ret is None:
break
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=8, minSize=(7, 7))
for (x, y, w, h) in faces:
# 截取人脸区域(灰度图,用于识别)
face_roi = gray[y:y + h, x:x + w]
# 人脸识别:返回标签(label)和置信度(confidence)
# 置信度越小,匹配度越高;超过阈值则返回标签-1
label, confidence = recognizer.predict(face_roi)
# 在彩色帧上绘制人脸矩形框(红色,线宽2)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
# 在人脸上方绘制识别结果(红色,字体大小0.9,线宽2)
# cv2.putText(img, dic[label], (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
img = cv2_draw_chinese(
img=img,
text=dic[label], # 你的中文字符(直接传字典值即可)
pos=(x, y-20), # 原绘制坐标
font_path=FONT_PATH,
font_size=22, # 视觉效果匹配原cv2.putText的0.9
color=(0, 0, 255) # 原红色,保持一致
)
cv2.imshow('',img)
key = cv2.waitKey(10)
if key == 27:
break