12、基于OpenCV构建人脸检测与跟踪系统

基于OpenCV构建人脸检测与跟踪系统

在机器人编程领域,人脸检测与跟踪是一项非常重要的技术。本文将详细介绍如何使用OpenCV实现人脸、眼睛检测以及微笑识别功能。

1. 技术要求

在开始之前,你需要准备以下设备和文件:
- 三个LED灯
- 搭载树莓派相机模块的树莓派(RPi)机器人
- 相关代码文件可从 此处 下载

2. 基于Haar级联的人脸检测

2001年,Paul Viola和Micheal Jones在论文中提出了基于Haar特征的级联分类器,也被称为Viola - Jones算法。该分类器使用人脸图像和非人脸图像进行训练,不仅可以检测正面人脸,还能检测人的眼睛、嘴巴和鼻子。

2.1 Viola - Jones算法的基本原理

Viola - Jones算法使用Haar特征来检测人脸,Haar特征主要包括边缘特征和线条特征:
- 边缘特征 :用于检测边缘,由白色和黑色像素组成,可进一步分为水平边缘特征和垂直边缘特征。
- 线条特征 :用于检测线条,白色像素夹在两个黑色像素之间,或者黑色像素夹在两个白色像素之间。

人脸检测通常在灰度图像上进行,因为在灰度图像中,不同面部区域的亮度不同。例如,额头区域比眉毛区域亮,鼻梁区域比眼睛和脸颊区域亮,上唇区域较暗,牙齿区域较亮,下唇区域又较暗。通过利用Haar级联的边缘和线条特征,我们可以检测人脸中最相关的特征点,如眼睛、鼻子和嘴巴。

OpenCV 4.0包含不同的预训练Haar检测器,可用于检测人脸及其眼睛、鼻子、微笑等。在 Opencv - 4.0.0 文件夹的 Data 文件夹中,有一个 haarcascades 文件夹,其中包含不同的Haar级联分类器。对于正面人脸检测,我们将使用 haarcascade_frontalface_alt2.xml 检测器。

2.2 人脸检测程序

以下是编写人脸检测程序的步骤:
1. 加载预训练的Haar正面人脸XML文件

CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");
  1. 声明矩阵变量和视频捕获变量
Mat videofeed, grayfeed;
VideoCapture vid(0);
  1. 读取相机馈送,翻转图像并转换为灰度
vid.read(videofeed);
flip(videofeed, videofeed, 1);
cvtColor(videofeed, grayfeed, COLOR_BGR2GRAY);
  1. 进行直方图均衡化
equalizeHist(grayfeed, grayfeed);
  1. 使用 detectMultiScale 函数检测人脸
detectMultiScale(image, object, scalefactor, min neighbors, flags, min size, max size);

该函数的参数说明如下:
| 参数 | 说明 |
| ---- | ---- |
| image | 输入视频馈送,这里是 grayfeed |
| object | 包含检测到的人脸的矩形向量 |
| scalefactor | 图像尺寸缩小的比例,理想值在1.1到1.3之间 |
| flags | 可设置为 CASCADE_SCALE_IMAGE CASCADE_FIND_BIGGEST_OBJECT CASCADE_DO_ROUGH_SEARCH CASCADE_DO_CANNY_PRUNING |
| min neighbors | 影响检测到的人脸质量,理想值在3到5之间 |
| min size | 检测的最小人脸尺寸,理想值为30 x 30像素 |
| max size | 检测的最大人脸尺寸 |

  1. 声明矩形向量并进行人脸检测
vector<Rect> face;
faceDetector.detectMultiScale(grayfeed, faces, 1.3, 5, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
  1. 在检测到的人脸周围绘制矩形并显示文本
for (size_t f = 0; f < face.size(); f++)
{
    rectangle(videofeed, face[f], Scalar(255, 0, 0), 2);
    putText(videofeed, "Face Detected", Point(face[f].x, face[f].y), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 2.0);
}
  1. 显示视频馈送
imshow("Face Detection", videofeed);
3. 眼睛和微笑检测

接下来,我们将检测人的眼睛并识别微笑。相关程序 SmilingFace.cpp 可从上述GitHub链接下载。

3.1 眼睛检测

OpenCV 4.0有三种主要的眼睛级联分类器:
- haarcascade_eye.xml :同时检测两只眼睛
- haarcascade_lefteye_2splits.xml :仅检测左眼
- haarcascade_righteye_2splits.xml :仅检测右眼

以下是使用不同分类器进行眼睛检测的步骤:

使用 haarcascade_eye 检测眼睛
1. 加载分类器

CascadeClassifier eyeDetector("haarcascade_eye.xml");
  1. 找到人脸区域
Mat faceroi = videofeed(face[f]);
  1. 检测眼睛区域
vector<Rect> eyes;
eyeDetector.detectMultiScale(faceroi, eyes, 1.3, 5, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
  1. 在眼睛周围绘制圆圈
for (size_t e = 0; e < eyes.size(); e++)
{
    Point eyecenter(face[f].x + eyes[e].x + eyes[e].width / 2, face[f].y + eyes[e].y + eyes[e].height / 2);
    int radius = cvRound((eyes[e].width + eyes[e].height) * 0.20);
    circle(videofeed, eyecenter, radius, Scalar(0, 0, 255), 2);
}

使用 haarcascade_lefteye_2splits haarcascade_righteye_2splits 分别检测左眼和右眼
- 检测左眼

CascadeClassifier eyeDetectorleft("haarcascade_lefteye_2splits.xml");
Mat faceroi = videofeed(face[f]);
vector<Rect> lefteye;
eyeDetectorleft.detectMultiScale(faceROI, lefteye, 1.3, 25, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
for (size_t le = 0; le < lefteye.size(); le++)
{
    Point center(face[f].x + lefteye[le].x + lefteye[le].width * 0.5, face[f].y + lefteye[le].y + lefteye[le].height * 0.5);
    int radius = cvRound((lefteye[le].width + lefteye[le].height) * 0.20);
    circle(videofeed, center, radius, Scalar(0, 0, 255), 2);
}
  • 检测右眼
CascadeClassifier eyeDetectorright("haarcascade_righteye_2splits.xml");
Mat faceroi = videofeed(face[f]);
vector<Rect> righteye;
eyeDetectorright.detectMultiScale(faceROI, righteye, 1.3, 25, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
for (size_t re = 0; re < righteye.size(); re++)
{
    Point center(face[f].x + righteye[re].x + righteye[re].width * 0.5, face[f].y + righteye[re].y + righteye[re].height * 0.5);
    int radius = cvRound((righteye[re].width + righteye[re].height) * 0.20);
    circle(videofeed, center, radius, Scalar(0, 255, 0), 2);
}

通过以上步骤,我们可以实现人脸、眼睛的检测以及微笑的识别。在实际应用中,可以根据具体需求调整参数,以获得更好的检测效果。

以下是人脸检测和眼睛检测的流程图:

graph TD;
    A[开始] --> B[加载Haar分类器];
    B --> C[捕获视频馈送];
    C --> D[翻转并转换为灰度图像];
    D --> E[直方图均衡化];
    E --> F[检测人脸];
    F --> G{是否检测到人脸};
    G -- 是 --> H[绘制人脸矩形并显示文本];
    H --> I[检测眼睛];
    I --> J{是否检测到眼睛};
    J -- 是 --> K[在眼睛周围绘制圆圈];
    K --> L[显示视频馈送];
    L --> C;
    G -- 否 --> C;
    J -- 否 --> C;

通过这个流程图,我们可以清晰地看到整个检测过程的步骤和逻辑。从开始加载分类器,到捕获视频、处理图像、检测人脸和眼睛,最后显示结果,形成了一个循环的检测系统。

3.2 微笑识别

在检测到人脸和眼睛后,我们还可以进行微笑识别。当网络摄像头检测到嘴巴周围有黑白黑的线条特征时,即上唇和下唇比牙齿区域颜色深时,就会识别出微笑的人脸。

以下是实现微笑识别的编程步骤:
1. 加载微笑级联分类器

CascadeClassifier smileDetector("haarcascade_smile.xml");
  1. 找到人脸区域(感兴趣区域)
Mat faceroi = videofeed(face[f]);
  1. 声明微笑检测的矩形向量并进行检测
vector<Rect> smile;
smileDetector.detectMultiScale(faceroi, smile, 1.3, 25, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

这里将 min neighbors 设置为25,这样只有当人微笑时才会创建圆圈。你可以在25 - 35之间调整该值。
4. 在嘴巴周围绘制绿色圆圈

for (size_t s = 0; s < smile.size(); s++)
{
    Point center(face[f].x + smile[s].x + smile[s].width * 0.5, face[f].y + smile[s].y + smile[s].height * 0.5);
    int radius = cvRound((smile[s].width + smile[s].height) * 0.20);
    circle(videofeed, center, radius, Scalar(0, 255, 0), 2);
}
4. 参数调整与注意事项

在使用上述检测功能时,各个参数的设置对检测效果有重要影响,以下是一些关键参数的调整建议和注意事项:
| 参数 | 影响 | 建议值 |
| ---- | ---- | ---- |
| scalefactor | 图像尺寸缩小比例,值越大,图像缩小越快,检测速度可能加快,但可能遗漏小目标 | 1.1 - 1.3 |
| min neighbors | 影响检测到的目标质量,值越大,检测到的目标越准确,但可能漏检;值越小,可能检测到更多目标,但可能误检 | 人脸检测:3 - 5;眼睛检测:5;微笑检测:25 - 35 |
| min size | 检测的最小目标尺寸,小于该尺寸的目标将被忽略 | 30 x 30像素 |
| max size | 检测的最大目标尺寸,大于该尺寸的目标将被忽略 | 根据实际情况设置 |

同时,要确保相关的XML文件(如 haarcascade_frontalface_alt2.xml haarcascade_eye.xml 等)与代码文件在同一文件夹中,否则会导致分类器加载失败。

5. 总结

本文详细介绍了如何使用OpenCV实现人脸、眼睛检测以及微笑识别功能。通过使用Haar级联分类器,我们可以方便地在图像或视频中检测出目标。整个过程包括加载分类器、捕获视频、处理图像、检测目标以及绘制标记等步骤。

以下是完整的检测流程总结:
1. 加载所需的Haar级联分类器(人脸、眼睛、微笑)。
2. 初始化视频捕获设备。
3. 循环读取视频帧。
- 翻转并将视频帧转换为灰度图像。
- 进行直方图均衡化以提高图像质量。
- 检测人脸。
- 如果检测到人脸,在人脸周围绘制矩形并显示文本。
- 在人脸区域内检测眼睛。
- 如果检测到眼睛,在眼睛周围绘制圆圈。
- 在人脸区域内检测微笑。
- 如果检测到微笑,在嘴巴周围绘制圆圈。
4. 显示处理后的视频帧。

通过合理调整参数和优化代码,我们可以提高检测的准确性和效率,使系统在不同的场景下都能有良好的表现。希望本文能为你在人脸检测与跟踪领域的开发提供有价值的参考。

以下是包含微笑识别的完整流程图:

graph TD;
    A[开始] --> B[加载Haar分类器(人脸、眼睛、微笑)];
    B --> C[捕获视频馈送];
    C --> D[翻转并转换为灰度图像];
    D --> E[直方图均衡化];
    E --> F[检测人脸];
    F --> G{是否检测到人脸};
    G -- 是 --> H[绘制人脸矩形并显示文本];
    H --> I[检测眼睛];
    I --> J{是否检测到眼睛};
    J -- 是 --> K[在眼睛周围绘制圆圈];
    K --> L[检测微笑];
    L --> M{是否检测到微笑};
    M -- 是 --> N[在嘴巴周围绘制圆圈];
    N --> O[显示视频馈送];
    O --> C;
    G -- 否 --> C;
    J -- 否 --> L;
    M -- 否 --> O;

这个流程图展示了从开始到完成人脸、眼睛和微笑检测的完整过程,涵盖了各个检测步骤和条件判断,有助于我们更清晰地理解整个系统的工作逻辑。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值