大家好,今天我们来学习如何使用 OpenCV 的 Haar 级联分类器实现实时人脸检测,并在检测到的人脸区域(ROI)内进一步检测眼睛。Haar 级联是一种基于机器学习的目标检测方法,特别适合实时检测人脸、眼睛等特征,广泛应用于监控、人脸识别等场景。
一、Haar 级联分类器原理简介
Haar 级联分类器通过学习目标的 Haar 特征 (如边缘、纹理等),构建多层级联的弱分类器,最终实现对目标的快速检测。其核心优势是计算量小、实时性强,适合在普通硬件上运行。
本次教程将分为两个步骤:
- 检测图像 / 视频中的人脸(获取人脸区域 ROI);
- 在人脸 ROI 内检测眼睛(避免在非人脸区域误检)。
二、准备工作
1. 预训练模型下载
OpenCV 提供了预训练的 Haar 级联模型,无需自己训练,直接下载即可:
- 人脸检测模型:
haarcascade_frontalface_default.xml - 眼睛检测模型:
haarcascade_eye.xml
官方下载地址(OpenCV GitHub 仓库):
- 人脸模型:https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml
- 眼睛模型:https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_eye.xml
下载方法:点击链接后,右键 “Raw”→“另存为”,保存到本地(建议新建一个models文件夹存放)。
2. 环境配置
确保已安装 OpenCV 和 NumPy(之前装过就忽略):
pip install opencv-python numpy
三、实时人脸检测 + 眼睛检测实现
我们将使用摄像头实时采集视频流,先检测人脸,再在人脸区域内检测眼睛。
import cv2
import numpy as np
# 1. 加载Haar级联模型(请替换为你的模型路径)
# 注意:模型路径需与代码文件位置对应,若放在models文件夹下则为"models/xxx.xml"
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml")
# 检查模型是否加载成功
if face_cascade.empty() or eye_cascade.empty():
print("模型加载失败!请检查文件路径是否正确。")
exit()
# 2. 初始化摄像头
cap = cv2.VideoCapture(0) # 0表示默认摄像头
if not cap.isOpened():
print("无法打开摄像头!")
exit()
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 关闭自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_WB, 1) # 0:关闭自动白平衡
# 3. 实时检测循环
while True:
# 读取一帧视频
ret, frame = cap.read()
if not ret:
print("无法获取视频帧,退出程序。")
break
# 转换为灰度图(Haar检测通常基于灰度图,减少计算量)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 4. 人脸检测
# 参数说明:
# - scaleFactor:缩放因子(1.1表示每次缩放10%),值越小检测越精确但速度越慢
# - minNeighbors:最小邻居数(5表示一个目标至少被检测5次才认为是有效目标)
# - minSize:目标最小尺寸(小于此尺寸的区域不检测)
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30) # 人脸最小尺寸(宽x高)
)
# 5. 遍历检测到的人脸,在人脸ROI内检测眼睛
for (x, y, w, h) in faces:
# 绘制人脸边界框(蓝色,线宽2)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 提取人脸ROI(灰度图和彩色图,分别用于检测和绘制)
face_gray = gray[y:y+h, x:x+w] # 人脸区域的灰度图
face_color = frame[y:y+h, x:x+w] # 人脸区域的彩色图
# 6. 在人脸ROI内检测眼睛
eyes = eye_cascade.detectMultiScale(
face_gray,
scaleFactor=1.1,
minNeighbors=3,
minSize=(20, 20) # 眼睛最小尺寸
)
# 绘制眼睛边界框(绿色,线宽2)
for (ex, ey, ew, eh) in eyes:
# 注意:眼睛坐标是相对于人脸ROI的,需转换为全局坐标
cv2.rectangle(face_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)
# 显示检测结果
cv2.imshow("Face and Eye Detection", frame)
# 按'q'退出程序
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
四、代码详解
1. 模型加载
python
运行
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
eye_cascade = cv2.CascadeClassifier("haarcascade_eye.xml")
CascadeClassifier:OpenCV 用于加载 Haar 级联模型的类。- 注意:模型路径必须正确,若模型文件与代码在同一文件夹,直接写文件名;否则需写绝对路径(如
C:/models/haarcascade_frontalface_default.xml)。
2. 人脸检测核心参数
python
运行
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
scaleFactor=1.1:每次检测时将图像缩小 10%,平衡检测速度与精度。minNeighbors=5:过滤噪声(值越大,误检越少,但可能漏检)。minSize=(30, 30):忽略小于 30x30 像素的区域(避免检测过小的噪声)。
3. 人脸 ROI 与眼睛检测
python
运行
# 提取人脸ROI(只在人脸区域内检测眼睛,提高效率)
face_gray = gray[y:y+h, x:x+w]
eyes = eye_cascade.detectMultiScale(face_gray, ...)
- 为什么要在人脸 ROI 内检测眼睛?
避免在背景(如窗户、灯泡)中误检为眼睛,同时减少计算量(只需处理人脸大小的区域)。
五、效果优化与常见问题
1. 检测效果不好?调整这些参数!
- 漏检严重:减小
scaleFactor(如 1.05)、减小minNeighbors(如 3)、减小minSize。 - 误检太多:增大
scaleFactor(如 1.2)、增大minNeighbors(如 7)、增大minSize。
2. 眼睛检测不稳定?
- Haar 眼睛模型对正面人脸效果好,侧脸或闭眼时可能漏检。
- 可尝试更鲁棒的模型:
haarcascade_eye_tree_eyeglasses.xml(对戴眼镜的人更友好),下载地址:https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_eye_tree_eyeglasses.xml
3. 实时性差?
- 降低摄像头分辨率:
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)、cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)。 - 增大
scaleFactor(如 1.3),减少检测迭代次数。
六、总结
Haar 级联分类器是实时人脸 / 眼睛检测的经典方案,优点是速度快、无需复杂计算资源,缺点是对姿态(如侧脸)和光照敏感。后续笛子哥会讲解yolo的方案,敬请期待。
