0


在Visual Studio上,使用OpenCV实现人脸识别

1. 环境与说明

本文介绍了如何在

  1. Visual Studio

上,使用

  1. OpenCV

来实现人脸识别的功能

环境说明 :

  • 操作系统 : windows 10 64位
  • Visual Studio版本 : Visual Studio Community 2022 (社区版)
  • OpenCV版本 : OpenCV-4.8.0 (2023年7月最新版)

实现效果如图所示,识别到的人脸会用红框框出来 :

在这里插入图片描述

2. 配置Visual Studio环境

这部分详见我的另一篇博客 : Visual Studio 2022 cmake配置opencv开发环境

最终配置好后,能够在

  1. Visual Studio

中正常调用

  1. OpenCV

,运行

  1. CMake

项目(

  1. C++

程序)
在这里插入图片描述

3. 实现摄像头预览

这部分要用到

  1. VideoCapture

这个类,

  1. VideoCapture

既支持从视频文件读取,也支持直接从摄像机等监控器中读取,还可以读取

  1. IP

视频流,要想获取视频需要先创建一个

  1. VideoCapture

对象来打开相机,然后就可以来操作视频帧了。

我们将项目代码修改为如下内容

  1. #include"OpenCVTest.h"#include"opencv2/opencv.hpp"usingnamespace std;usingnamespace cv;intmain(){
  2. VideoCapture capture;//打开相机,这个传入的相机ID为0
  3. capture.open(0);if(!capture.isOpened()){
  4. cout <<"opencv打开摄像头失败!\n"<< endl;return-1;}//Mat矩阵,用来存一张图片
  5. Mat frame;while(true){//从capture中取数据,将画面输出到frame矩阵里面
  6. capture >> frame;if(frame.empty()){
  7. cout <<"读取摄像头数据失败\n"<< endl;}imshow("摄像头", frame);//显示图像if(waitKey(30)==27)//按下ESC键退出程序{break;}}return0;}

运行程序,效果如下所示

在这里插入图片描述

4. 转化为灰度图像

接下来我们需要将图片转化为灰度图,为什么要进行灰度化处理呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性

  • 简化图像处理:灰度化可以将彩色图像转化为黑白图像,使得处理更加简单。彩色图像包含三个通道(红、绿、蓝),而灰度图像只有一个通道,使得处理更加快速和高效。
  • 消除颜色信息:人脸识别对于颜色信息并不是非常敏感,而更关注形状和轮廓等特征。因此,通过灰度化处理,可以消除颜色信息对于后续处理的影响。
  • 提高处理性能:灰度化处理可以减少计算量,提高处理性能。在人脸识别过程中,对每个像素进行颜色计算会消耗大量计算资源,而灰度化处理只需要对每个像素的亮度进行计算,减少了计算量。
  • 突出图像特征:灰度化处理可以突出图像中的边缘和纹理等特征。这些特征对于人脸识别非常关键,可以帮助算法更好地识别人脸。

进行灰度化处理我们需要调用

  1. void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );

,这里

  1. src

是我们输入的图像,

  1. dst

是我们要输出的图像,

  1. code

需要传

  1. COLOR_BGR2GRAY

,表示将

  1. BGR

转化为灰度图。

要注意,在

  1. OpenCV

中,是

  1. BGR

排列方式,而不是

  1. RGB

排列。

具体完整代码如下

  1. #include"OpenCVTest.h"#include"opencv2/opencv.hpp"usingnamespace std;usingnamespace cv;intmain(){
  2. VideoCapture capture;
  3. capture.open(0);if(!capture.isOpened()){
  4. cout <<"opencv打开摄像头失败!\n"<< endl;return-1;}
  5. Mat frame;//摄像头彩色图像
  6. Mat grayFrame;//摄像头灰度图像while(true){//从capture中取数据,将画面输出到frame矩阵里面
  7. capture >> frame;if(frame.empty()){
  8. cout <<"读取摄像头数据失败!\n"<< endl;return-1;}imshow("摄像头", frame);//显示彩色图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY);//注意 : OpenCV中是BRGimshow("灰度化", grayFrame);//显示灰色图像if(waitKey(30)==27)//ESC键{break;}}return0;}

运行程序,效果如下所示,左边的是彩色画面,右边的是黑白画面

在这里插入图片描述

5. 直方图均衡化处理

接着,要进行直方图均衡化处理,为什么要进行这一步操作呢 ? 主要有以下几个作用,提高人脸识别的准确性和可靠性

  • 提高对比度:直方图均衡化通过重新分布图像像素的灰度级,将原始图像中的灰度级分布变得更加均匀。这样做可以增强图像的对比度,使得人脸的特征更加清晰可见。
  • 消除光照变化:人脸识别中的一个挑战是光照变化对人脸图像的影响。直方图均衡化可以消除光照变化,使得人脸图像在不同光照条件下具有一致的亮度和对比度。
  • 提高图像质量:直方图均衡化可以改善图像的质量,去除图像中的噪声和伪影。这对于后续的人脸特征提取和匹配非常重要,可以提高人脸识别的准确性和鲁棒性。
  • 增强细节信息:直方图均衡化可以增强图像的细节信息,使得人脸图像中的纹理和特征更加明显。这对于人脸识别算法的性能至关重要,可以提高人脸识别的准确率和鲁棒性。

直方图均衡化处理需要调用

  1. void equalizeHist( InputArray src, OutputArray dst);

  1. src

是输入的图像,需要是单通道的灰度图,

  1. dst

是我们输出的图像。

具体完整代码如下

  1. #include"OpenCVTest.h"#include"opencv2/opencv.hpp"usingnamespace std;usingnamespace cv;intmain(){
  2. VideoCapture capture;
  3. capture.open(0);if(!capture.isOpened()){
  4. cout <<"opencv打开摄像头失败!\n"<< endl;return-1;}
  5. Mat frame;//摄像头彩色图像
  6. Mat grayFrame;//摄像头灰度图像
  7. Mat equalizeFrame;//直方图while(true){
  8. capture >> frame;//从capture中取数据,将画面输出到frame矩阵里面if(frame.empty()){
  9. cout <<"读取摄像头数据失败!\n"<< endl;return-1;}imshow("摄像头", frame);//显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY);//注意 : OpenCV中是BRGimshow("灰度化", grayFrame);//显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);imshow("直方图", equalizeFrame);if(waitKey(30)==27)//ESC键{break;}}return0;}

运行程序,效果如下所示,最右边的是经过直方图均衡化处理后的
在这里插入图片描述

6. 加载级联分类器

级联分类器

  1. CascadeClassifier

的作用是进行目标检测。它是一种基于机器学习的分类器,通过训练多个弱分类器来识别目标物体。这些弱分类器层层级联,形成一个级联分类器,能够快速准确地检测出图像中的目标物体。

级联分类器通常用于人脸检测,可以通过训练来识别人的面部特征,如眼睛、鼻子、嘴巴等,从而识别人脸并定位人脸的位置。在

  1. OpenCV

中,

  1. CascadeClassifier

类提供了一个方便的接口,可以加载预训练的级联分类器,并进行目标检测操作。

首先我们要去加载级联分类器文件(

  1. xml

文件),这些文件位于

  1. D:\Developer\opencv4.8.0\opencv\build\etc

目录下,这里我们用的是

  1. haarcascade

这种基于梯度提升决策树的分类器 (另一种

  1. lbpcascade

是一种基于局部二值模式

  1. LBP

的分类器)

  1. haarcascade

目录下,我们可以看到

  1. haarcascade_frontalface_alt.xml

这个文件,就是我们需要的,用于人脸识别的级联分类器了。
在这里插入图片描述
所以,我们加载级联分类器的时候,去指定这个路径

  1. D:\Developer\opencv4.8.0\opencv\build\etc\haarcascades\haarcascade_frontalface_alt.xml

,需要注意的是,放到代码里,这里的要将

  1. \

改为

  1. /

(或者改为

  1. \\

也行)。如果不改,那么路径不对,级联分类器会读取出错。

具体代码如下

  1. intmain(){
  2. CascadeClassifier face_CascadeClassifier;if(!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")){
  3. cout <<"级联分类器加载失败!\n"<< endl;return-1;}//这里省略了原本其他的代码 ...}

7. 进行人脸检测

接下来我们就要进行人脸检测了,人脸检测需要调用

  1. detectMultiScale

方法,第一个参数

  1. image

需要传入我们刚才处理后的直方图,第二个参数

  1. objects

会返回所有检测出来的人脸的坐标。

  1. voiddetectMultiScale( InputArray image,
  2. CV_OUT std::vector<Rect>& objects,double scaleFactor =1.1,int minNeighbors =3,int flags =0,
  3. Size minSize =Size(),
  4. Size maxSize =Size());

还有一个

  1. rectangle

方法,用来在得到人脸坐标之后,进行画框。第一个参数

  1. img

代表要在哪个图像上画框,第二个参数

  1. rec

表示框的坐标,第三个参数

  1. color

表示画框的颜色。

  1. voidrectangle(InputOutputArray img, Rect rec,const Scalar& color,int thickness =1,int lineType = LINE_8,int shift =0);

主要代码如下所示

  1. std::vector<Rect> faces;
  2. face_CascadeClassifier.detectMultiScale(grayFrame, faces);//检测人脸for(size_t i =0; i < faces.size(); i++){rectangle(frame,faces[i],Scalar(0,0,255));//在人脸的位置画红色的框}

来看一下完整代码

  1. #include "OpenCVTest.h"
  2. #include "opencv2/opencv.hpp"
  3. using namespace std;
  4. using namespace cv;
  5. int main(){//加载级联分类器
  6. CascadeClassifier face_CascadeClassifier;if(!face_CascadeClassifier.load("D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml")){
  7. cout <<"级联分类器加载失败!\n"<< endl;return-1;}
  8. VideoCapture capture;
  9. capture.open(0);if(!capture.isOpened()){
  10. cout <<"opencv打开摄像头失败!\n"<< endl;return-1;}
  11. Mat frame;//摄像头彩色图像
  12. Mat grayFrame;//摄像头灰度图像
  13. Mat equalizeFrame;//直方图while(true){
  14. capture >> frame;//从capture中取数据,将画面输出到frame矩阵里面if(frame.empty()){
  15. cout <<"读取摄像头数据失败!\n"<< endl;}//imshow("摄像头", frame); //显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY);//注意 : OpenCV中是BRG//imshow("灰度化", grayFrame); //显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);//imshow("直方图", equalizeFrame);
  16. std::vector<Rect> faces;
  17. face_CascadeClassifier.detectMultiScale(grayFrame, faces);//检测人脸for(size_t i =0; i < faces.size(); i++){rectangle(frame,faces[i],Scalar(0,0,255));}imshow("摄像头", frame);//显示图像if(waitKey(30)==27)//ESC键{break;}}return0;}

运行程序,来看一下效果

可以看到,人脸已经检测出来了,并对人脸进行了画框。但是可以画面非常的卡顿,因为人脸检测是非常耗时的,可能需要500毫秒甚至1-2秒时间,这里每一帧都去检测人脸,导致了异常卡顿。所以这种方式只适合用来检测静态图像,并不适合用作实时的摄像头人脸跟踪检测。

8. 实现实时人脸跟踪检测

8.1 OpenCV Android Demo

那我们需要来怎么做呢 ? 其实我们可以来看一下官方的示例,我们要去下载官方的Android包,里面有Android的官方示例。

在这里插入图片描述

8.2 DetectionBasedTracker_jni.cpp

我们下载解压后,可以在

  1. OpenCV-android-sdk\samples\face-detection\jni

目录下找到

  1. DetectionBasedTracker_jni.cpp

这个文件
在这里插入图片描述
在里面的

  1. nativeCreateObject

方法里,我们可以发现其调用了这几句代码
在这里插入图片描述

8.3 CascadeDetectorAdapter

  1. CascadeDetectorAdapter

是一个适配器类,用于将

  1. CascadeClassifier

  1. Detector

接口适配起来,从而用于检测人脸。

再来看一下

  1. CascadeDetectorAdapter

这个类,里面的

  1. detect

方法就是用来检测人脸的
在这里插入图片描述

8.4 DetectorAgregator

然后来看一下第三行代码中的

  1. DetectorAgregator

,这里面有

  1. tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);

这行代码是我们需要的,用来传入

  1. mainDetector

  1. trackingDetector

,生成一个

  1. tracker

对象。
在这里插入图片描述

8.5 开始重新编写代码

这里我们将原来写的人脸检测的代码删除了,代码恢复到了刚配置好OpenCV的初始状态,然后将

  1. CascadeDetectorAdapter

这个类的代码复制到我们的项目中

  1. classCascadeDetectorAdapter:public DetectionBasedTracker::IDetector{public:CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):IDetector(),Detector(detector){CV_Assert(detector);}voiddetect(const cv::Mat &Image, std::vector<cv::Rect>&objects){
  2. Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours,0, minObjSize, maxObjSize);}virtual~CascadeDetectorAdapter(){}private:CascadeDetectorAdapter();
  3. cv::Ptr<cv::CascadeClassifier> Detector;};

声明

  1. tracker

这个对象。

  1. cv::Ptr<DetectionBasedTracker> tracker;

然后创建

  1. tracker

,并调用

  1. run()

方法,会启动一个异步线程,后面的人脸检测会在这个异步线程进行检测了。

  1. string stdFileName ="D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";//创建一个主检测适配器
  2. cv::Ptr<CascadeDetectorAdapter> mainDetector =makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建一个跟踪检测适配器
  3. cv::Ptr<CascadeDetectorAdapter> trackingDetector =makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建跟踪器
  4. DetectionBasedTracker::Parameters DetectorParams;
  5. tracker =makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
  6. tracker->run();

然后在人脸检测的使用调用

  1. tracker->process(grayFrame);

进行人脸检测,并调用

  1. tracker->getObjects(faces);

获得识别出来的人脸。

  1. tracker->process(grayFrame);
  2. tracker->getObjects(faces);

核心代码就是如上所示,接下来我们再来看一下完整的代码

  1. #include"OpenCVTest.h"#include"opencv2/opencv.hpp"usingnamespace std;usingnamespace cv;classCascadeDetectorAdapter:public DetectionBasedTracker::IDetector{public:CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):IDetector(),Detector(detector){CV_Assert(detector);}voiddetect(const cv::Mat& Image, std::vector<cv::Rect>& objects){
  2. Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours,0, minObjSize, maxObjSize);}virtual~CascadeDetectorAdapter(){}private:CascadeDetectorAdapter();
  3. cv::Ptr<cv::CascadeClassifier> Detector;};
  4. cv::Ptr<DetectionBasedTracker> tracker;intmain(){
  5. string stdFileName ="D:/Developer/opencv4.8.0/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml";//创建一个主检测适配器
  6. cv::Ptr<CascadeDetectorAdapter> mainDetector =makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建一个跟踪检测适配器
  7. cv::Ptr<CascadeDetectorAdapter> trackingDetector =makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(stdFileName));//创建跟踪器
  8. DetectionBasedTracker::Parameters DetectorParams;
  9. tracker =makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
  10. tracker->run();
  11. VideoCapture capture;
  12. capture.open(0);if(!capture.isOpened()){
  13. cout <<"opencv打开摄像头失败!\n"<< endl;return-1;}
  14. Mat frame;//摄像头彩色图像
  15. Mat grayFrame;//摄像头灰度图像
  16. Mat equalizeFrame;//直方图while(true){
  17. capture >> frame;//从capture中取数据,将画面输出到frame矩阵里面if(frame.empty()){
  18. cout <<"读取摄像头数据失败!\n"<< endl;return-1;}//imshow("摄像头", frame); //显示图像//灰度化处理cvtColor(frame, grayFrame, COLOR_BGR2GRAY);//注意 : OpenCV中是BRG//imshow("灰度化", grayFrame); //显示图像//直方图均衡化,用来增强图像对比度,从而让轮廓更加明显equalizeHist(grayFrame, equalizeFrame);//imshow("直方图", equalizeFrame);
  19. std::vector<Rect> faces;
  20. tracker->process(grayFrame);
  21. tracker->getObjects(faces);for(size_t i =0; i < faces.size(); i++){rectangle(frame, faces[i],Scalar(0,0,255));}imshow("摄像头", frame);//显示图像if(waitKey(30)==27)//ESC键{break;}}
  22. tracker->stop();return0;}

8.6 运行效果

运行程序,我们就可以看到本文开头给出的效果了

在这里插入图片描述
至此,我们就使用

  1. OpenCV

完成实时人脸跟踪识别了。

9. 本文源码下载

使用OpenCV实现人脸识别示例Demo


本文转载自: https://blog.csdn.net/EthanCo/article/details/131959456
版权归原作者 氦客 所有, 如有侵权,请联系我们删除。

“在Visual Studio上,使用OpenCV实现人脸识别”的评论:

还没有评论