资源下载

如果想快速开始使用,可以直接使用编译好的,可跳过本文的前3步,由于CSDN上传文件大小限制就分卷压缩上传了(解压保存的路径最好是英文,代码中会用到):

  • 不包含opencv_contrib编译的库:
    卷一:https://download.csdn.net/download/u012902367/11079135
    卷二:https://download.csdn.net/download/u012902367/11079147
    卷三:https://download.csdn.net/download/u012902367/11079153
    第四小节的demo工程:https://download.csdn.net/download/u012902367/11079205
  • 包含opencv_contrib编译的库:
    https://download.csdn.net/download/u012902367/11103882
  • 解决报错的文件(本文最后有提到)
    https://download.csdn.net/download/sunny_lc/9474246
    https://download.csdn.net/download/u012902367/11099517

环境信息

由于版本众多,各个版本之间编译过程可能有所区别,本文选择了一个历史版本(提醒一下不同版本使用方法会存在差异,如果读者想要按照下面的方式尝试,第一次建议选择和笔者同样的版本,成功以后再尝试新版本,还有就是本文所选择的路径在代码中会用到,如果读者怕麻烦修改,甚至可以把盘符和安装路径设置成与本文一致),如下是本文所用的环境参数:

  • 操作系统:win10
    在这里插入图片描述

  • mingw32-make
    在这里插入图片描述

  • CMake-3.14.1-win64-x64
    在这里插入图片描述

  • opencv_contrib-3.2.0
    在这里插入图片描述

  • opencv-3.2.0

1. 下载cpenCV和opencv_contrib源码

  • 官网获取到安装程序:
    • 在这里插入图片描述在这里插入图片描述
      如果官网下载太慢可以选择再CSDN里面搜索下载:
      在这里插入图片描述

    下载下来过后运行安装,请选择纯英文路径:
    在这里插入图片描述
    等待安装完成:
    在这里插入图片描述

  • 也可以在git上获取,同时把opencv_contrib下载下来,注意:opencv和opencv_contrib两个版本一定要一致

在这里插入图片描述
把两个都下载下来,下面那一个包含了一些其它模块功能,比如常用的人脸识别在这里插入图片描述
保存在纯英文路径,路径中最好也不要有特殊符号。

2. 安装CMake

官方下载CMake:https://cmake.org/download/
在这里插入图片描述
下载完后双击安装,安装到纯英文路径,安装完后把bin目录加入环境变量:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

环境变量配置:
在这里插入图片描述
顺便也将Qt的环境变量配置一下
在这里插入图片描述

3. 编译openCV

本文就具体描述包含opencv_contrib的编译,不想包含他只需要不添加他的路径就好了,其它的步骤完全一样。
为了cmake正常通过,先下载几个文件放到opencv_contrib的\modules\xfeatures2d\src目录,在CMake过程中也会下载,但是笔者尝试了很多遍都下载失败了,所以就事先把这几个文件都下载下来放到指定目录下就安全多了,当然如果不包含opencv_contrib就可以不要做这一步。需要添加的文件如下:

在这里插入图片描述
运行安装的CMake。选择路径:
在这里插入图片描述
注意: 若果是选择的使用exe安装的openCV,路径是选择的source。如果是通过git获取的会发现解压出来和exe安装的source下文件一样,选择到对应的目录即可:
在这里插入图片描述

在这里插入图片描述

如果是选择git下载解压下来的会发下解压出来的文件目录和exe安装的source文件加下目录几乎一样。

选择好后点击左下角Configure出现如下对话框,照图选择选择:
在这里插入图片描述

在这里插入图片描述
等待配置完成,过程可能需要等待几分钟,在配置的过程中需要下载一些文件,最好有vpn:
在这里插入图片描述

完成过后在列表中勾选 WITH_QT和 WITH_OPENGL(在靠后一点位置),并选择opencv_contrib的路径:
在这里插入图片描述
在这里插入图片描述

勾选过后再点击Configure等待运行完成,出现Configuring done,如果还有红色就再点一次Configure,直到界面没有红色框:
在这里插入图片描述
再点击Generate:
在这里插入图片描述

完成过后即可关闭此窗口。

开始编译

使用cmd到最开始自己新建的目录下执行mingw32-make
在这里插入图片描述

也可以目录下在按住shift点击鼠标右键:
在这里插入图片描述
在这个目录下执行mingw32-make
在这里插入图片描述
等待编译完成,根据电脑配置,过程可能需要15~30分钟:
在这里插入图片描述

继续执行mingw32-make install,并等待结束:
在这里插入图片描述
结束后把如下路径添加到环境变量(注意看这个路径位置):
在这里插入图片描述
在这里插入图片描述

4. 新建工程调用openCV

如果不想敲可以直接下载这个应用的工程源码
新建一个应用:

在这里插入图片描述
在这里插入图片描述
.pro文件下添加如下代码,注意里面的路径需要换成读者自己安装的路径

INCLUDEPATH+=D:/openCV3_2/build/install/include/opencv \
             D:/openCV3_2/build/install/include/opencv2 \
             D:/openCV3_2/build/install/include
LIBS += -L D:/openCV3_2/build/install/x86/mingw/lib/libopencv_*.a

在这里插入图片描述
布局文件中就有两个QLabel,3个QPushButton,为了让读者看得清楚点把两个QLabel背景设置成了绿色,这个对使用没有一点影响,读者可以不用管这个颜色,其中对象的名字也写在图里面了:(camera,photo,open,take,close)
在这里插入图片描述

mainwindow.h代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QTimer>
#include <QImage>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QImage  Mat2QImage(Mat cvImg);
private slots:
    void openCamara();      // 打开摄像头
    void readFarme();       // 读取当前帧信息
    void closeCamara();     // 关闭摄像头。
    void takingPictures();  // 拍照

private:
    Ui::MainWindow *ui;

    QTimer          *timer;
    QImage          imag;
    Mat             cap,cap_gray,cap_tmp; //定义一个Mat变量,用于存储每一帧的图像
    VideoCapture    capture; //声明视频读入类
};

#endif // MAINWINDOW_H

mainwindow.cpp代码

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    timer   = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(readFarme()));  // 时间到,读取当前摄像头信息
    connect(ui->open, SIGNAL(clicked()), this, SLOT(openCamara()));
    connect(ui->take, SIGNAL(clicked()), this, SLOT(takingPictures()));
    connect(ui->close, SIGNAL(clicked()), this, SLOT(closeCamara()));
}


//打开摄像头
void MainWindow::openCamara()
{
    capture.open(0);    //从摄像头读入视频如果设备只有一个摄像头就传入参数0
    qDebug("open");
    if (!capture.isOpened()) //先判断是否打开摄像头
    {
         qDebug("err");
    }
    timer->start(20);              // 开始计时,20ms获取一帧
}

//读取摄像头信息
void MainWindow::readFarme()
{
    capture>>cap; //读取当前帧
    if (!cap.empty()) //判断当前帧是否捕捉成功 **这步很重要
    {
        imag = Mat2QImage(cap);
        imag = imag.scaled(ui->camera->width(), ui->camera->height(),
                                            Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//设置图片大小和label的长宽一致
        //imshow(name, cap); //若当前帧捕捉成功,显示
        ui->camera->setPixmap(QPixmap::fromImage(imag));  // 将图片显示到label上
    }
    else
        qDebug("can not ");

}


// 拍照
void MainWindow::takingPictures()
{
    capture>>cap; //读取当前帧
    if (!cap.empty()) //判断当前帧是否捕捉成功 **这步很重要
    {
        imag = Mat2QImage(cap);
        imag = imag.scaled(ui->photo->width(), ui->photo->height(),
                                            Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//设置图片大小和label的长宽一致

        //imshow(name, cap); //若当前帧捕捉成功,显示
        ui->photo->setPixmap(QPixmap::fromImage(imag));  // 将图片显示到label上
    }
    else
        qDebug("can not ");
}


//关闭摄像头,释放资源,必须释放***
void MainWindow::closeCamara()
{
    timer->stop();         // 停止读取数据。
}


// 图片转换(网上抄的)
QImage  MainWindow::Mat2QImage(Mat cvImg)
{
    QImage qImg;
    if(cvImg.channels()==3)     //3 channels color image
    {

        cv::cvtColor(cvImg,cvImg,CV_BGR2RGB);
        qImg =QImage((const unsigned char*)(cvImg.data),
                    cvImg.cols, cvImg.rows,
                    cvImg.cols*cvImg.channels(),
                    QImage::Format_RGB888);
    }
    else if(cvImg.channels()==1)                    //grayscale image
    {
        qImg =QImage((const unsigned char*)(cvImg.data),
                    cvImg.cols,cvImg.rows,
                    cvImg.cols*cvImg.channels(),
                    QImage::Format_Indexed8);
    }
    else
    {
        qImg =QImage((const unsigned char*)(cvImg.data),
                    cvImg.cols,cvImg.rows,
                    cvImg.cols*cvImg.channels(),
                    QImage::Format_RGB888);
    }
    return qImg;
}

MainWindow::~MainWindow()
{
    delete ui;
}

需要把如下的文件全部拷贝到应用编译生成的.exe文件同级目录下,否则会编译出错:
在这里插入图片描述

在这里插入图片描述
到此就可以编译成功运行了,左边的是摄像头实时图像,右边是点击拍照后保存的图片:
在这里插入图片描述

5. openCV中的基础人脸检测调用

openCV资源里面有一些现成的.xml文件,就是用来检测人脸的,这些文件在本文最开始openCV的安装路径下就可以找到:
在这里插入图片描述

本文就测试两个就一个是眼睛检测,一个是人脸检测并用方框圈出来,是在上面的工程中修改的,只修改了如下两处:

  • 将如下代码放入到mainwindow.h中:
        CascadeClassifier eye_Classifier;  //载入分类器
        CascadeClassifier face_cascade;    //载入分类器
        //vector 是个类模板 需要提供明确的模板实参 vector<Rect>则是个确定的类 模板的实例化  需要指点std域名才可以用:using namespace std;
        vector<Rect> eyeRect;
        vector<Rect> faceRect;
        vector<Rect> faces;
    

在这里插入图片描述

  • 修改mainwindow.cppreadFarme()方法的内容为如下:
    void MainWindow::readFarme()
    {
        capture>>cap; //读取当前帧
        if (!cap.empty()) //判断当前帧是否捕捉成功 **这步很重要
        {
            cvtColor(cap, cap_gray, CV_BGR2GRAY);//转为灰度图
            equalizeHist(cap_gray, cap_gray);//直方图均衡化,增加对比度方便处理
    
            //加载分类训练器,OpenCv官方文档提供的xml文档,可以直接调用
            //xml文档路径,  opencv\sources\data\haarcascades
            if (!eye_Classifier.load("D:\\opencvSet\\opencv\\sources\\data\\haarcascades\\haarcascade_eye.xml"))  //需要将xml文档放在自己指定的路径下
            {
                qDebug("Load haarcascade_eye.xml failed!");
                return;
            }
            if (!face_cascade.load("D:\\opencvSet\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml"))
            {
                qDebug("Load haarcascade_frontalface_alt failed!");
                return;
            }
    
            //检测关于眼睛部位位置
            eye_Classifier.detectMultiScale(cap_gray, eyeRect, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));//检测
            for (size_t eyeIdx = 0; eyeIdx < eyeRect.size(); eyeIdx++)
            {
                rectangle(cap, eyeRect[eyeIdx], Scalar(0, 0, 255));   //用红色矩形画出检测到的位置
            }
            //检测关于脸部位置
            face_cascade.detectMultiScale(cap_gray, faceRect, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));//检测
            for (size_t i = 0; i < faceRect.size(); i++)
            {
                rectangle(cap, faceRect[i], Scalar(0, 255, 0));      //用绿色矩形画出检测到的位置
            }
            imag = Mat2QImage(cap);     // 将Mat转换成QImage对象来显示
            imag = imag.scaled(ui->camera->width(), ui->camera->height(),
                                                Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//设置图片大小和label的长宽一致
            //imshow(name, cap); //若当前帧捕捉成功,显示
            ui->camera->setPixmap(QPixmap::fromImage(imag));  // 将图片显示到label上
        }
        else
            qDebug("can not ");
    }
    

效果如下:
在这里插入图片描述
可以看出官方提供分类训练器也有一些误检测。

6. 人脸识别

分清两个概念:

  • 人脸检测:检测出画面中是否存在人脸。
  • 人脸识别:根据人脸特征识别出这个人具体是谁。

上一小节已经利用opencv现成的人脸模型实现了检测人脸,这一小节就描写一下如何利用opencv提供的平台实现人脸识别,这里得所谓的人脸识别实际就是从摄像头视频或者照片里面查找人脸,然后把查找到的人脸处理成指定大小,再与人脸库对比,获取到对比结果。

人脸库创建

为了提高识别率最好准备各个角度的面部照片(测试过jpg和pgm两种格式均可),就像下面一样,同一个人有10张不同角度的照片:
在这里插入图片描述

可以直接下载Database of Faces下来作为自己的参考人脸库:
在这里插入图片描述
下载完解压出来有如下目录:
在这里插入图片描述

共40个文件夹,每一个文件夹里面为同一个人的不同角度10张图片,是pgm格式的,windows的图片查看软件打不开,不过可以是使用opencv提供的方法来查看,代码的路径就是刚才下载下来的文件第一个人脸:

Mat img;
img = imread("C:/Users/XF/Desktop/orl_faces/s1/1.pgm", CV_LOAD_IMAGE_GRAYSCALE);
imshow("img", img);

在这里插入图片描述
准备我们自己需要的人脸照片处理跟下载下来为图片参数一致,人脸图为灰度图,大小为92*112,保存为第41个文件夹,如果自己需要添加几个人的面部信息就按照如此规律往后添加即可:
在这里插入图片描述
网上看的文章很多都会有一个类似如下的文本文件:
在这里插入图片描述

这个文件主要是给代码快速获取图片路径的,所说的标签也仅仅只是表示这张图片代表的是库里面的第几个人,所以这个文件不是必要的,本文就不用这个文件直接手动来获取,我想这样读者会更容易理解,
如下代码就是用来生成人脸库的, 当然这里只选了几个人的脸部照片,要把每一个都添加进去靠动手输入是很麻烦,这也就是为什么会有上面那个文本文档来保存路径和标签信息,通过读取文档里面的路径和标签信息可以快速准简单的实现如下功能,也是一劳永逸:

void MainWindow::on_pushButton_clicked()
{
    vector<Mat> images;
    Mat img;
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/1.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/2.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/3.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/4.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/5.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/6.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/7.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/8.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/9.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s1/10.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中

    img = imread("C:/Users/XF/Desktop/orl_faces/s2/1.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/2.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/3.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/4.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/5.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/6.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/7.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/8.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/9.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s2/10.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中

    img = imread("C:/Users/XF/Desktop/orl_faces/s3/1.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/2.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/3.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/4.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/5.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/6.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/7.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/8.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/9.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/orl_faces/s3/10.pgm", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中


    img = imread("C:/Users/XF/Desktop/face_jpg/1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/3.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/4.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/5.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/6.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/7.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/8.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/9.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中
    img = imread("C:/Users/XF/Desktop/face_jpg/10.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    images.push_back(img); // 将图片 添加到images中


    vector<int> labels;
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);
    labels.push_back(0);

    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);
    labels.push_back(1);

    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);
    labels.push_back(2);

    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);
    labels.push_back(3);

    Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
    model->train(images, labels);
    model->save("MyFacePCAModel.xml");
}

可以看得出上面是通过一个按钮来实现开始训练自己的人脸库,运行过后会在exe的上一级目录下多一个MyFacePCAModel.xml文件:
在这里插入图片描述

人脸识别

有了它就可以开始进行识别了,也就不再新建工程了,其它代码和上一小节的工程中代码一致,只是修改了readFarme()方法如下,里面有些路径需要修改成自己电脑中文件所在路径

//读取摄像头信息
void MainWindow::readFarme()
{
    capture>>cap; //读取当前帧
    if (!cap.empty()) //判断当前帧是否捕捉成功 **这步很重要
    {
        cvtColor(cap, cap_gray, CV_BGR2GRAY);   //转为灰度图
        equalizeHist(cap_gray, cap_gray);       //直方图均衡化,增加对比度方便处理

        if (!face_cascade.load("D:\\openCV3_2\\opencv-3.2.0\\data\\haarcascades\\haarcascade_frontalface_alt.xml"))
        {
            qDebug("Load haarcascade_frontalface_alt failed!");
            return;
        }

        Ptr<FaceRecognizer> modelPCA = createEigenFaceRecognizer();
        modelPCA->load("E:\\workspace\\Qt_workspace\\build-face-Desktop_Qt_5_11_1_MinGW_32bit-Debug\\MyFacePCAModel.xml");//加载分类器

        if (!eye_Classifier.load("D:\\openCV3_2\\opencv-3.2.0\\data\\haarcascades\\haarcascade_eye.xml"))  //需要将xml文档放在自己指定的路径下
        {
            qDebug("Load haarcascade_eye.xml failed!");
            return;
        }

        //检测关于脸部位置
        face_cascade.detectMultiScale(cap_gray, faceRect, 1.1, 3, 0 | CV_HAAR_DO_ROUGH_SEARCH, Size(50, 50));//检测
        for (size_t i = 0; i < faceRect.size(); i++)
        {
            rectangle(cap, faceRect[i], Scalar(0, 255, 0));      //用绿色矩形画出检测到的位置
            Mat faceROI = cap_gray(faceRect[i]);


            int predictPCA = 0;
            Mat face_test;
            Point text_lb;
			// 不加前面的cv::的话resize()方法会和MainWindow中的resize()冲突。
            cv::resize(faceROI,face_test,Size(92, 112));
            imshow("frame", face_test);
            //测试图像应该是灰度图
            predictPCA = modelPCA->predict(face_test);
            qDebug("%d",predictPCA);
            if(predictPCA==3)  // 这个3也就是上面labels.push_back(3);和图片是一一对应的
            {
                string name = "xufan";  // 文本提示
                text_lb = Point(faceRect[i].x, faceRect[i].y);
                putText(cap, name, text_lb, FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));
            }
            
            //imshow("frame", faceROI);
            //检测关于眼睛部位位置
            int eye_num=0;
            eye_Classifier.detectMultiScale(faceROI, eyeRect, 1.1, 1, 0 | CV_HAAR_DO_ROUGH_SEARCH, Size(30, 30));//检测
            for (size_t j = 0; j < eyeRect.size(); j++)
            {
                Rect rect(faceRect[i].x + eyeRect[j].x, faceRect[i].y + eyeRect[j].y, eyeRect[j].width, eyeRect[j].height);
                rectangle(cap, rect, Scalar(255, 0, 0));   //用蓝色矩形画出检测到的位置
                eye_num++;
                if(eye_num==2)
                    break;
            }
        }
        imag = Mat2QImage(cap);     // 将Mat转换成QImage对象来显示
        imag = imag.scaled(ui->camera->width(), ui->camera->height(),
                                            Qt::IgnoreAspectRatio, Qt::SmoothTransformation);//设置图片大小和label的长宽一致
        ui->camera->setPixmap(QPixmap::fromImage(imag));  // 将图片显示到label上
    }
    else
        qDebug("can not ");
}

运行过后就会出现就可以识别到视频中的人脸:
在这里插入图片描述

CMake过程可能会有的问题

CMake时会下载几个文件,下载失败会导致提示工程不可用,可直接手动从网上下载然后按照如下操作,添加到源文件中即可,如下所用到资源在本文最上面可以找到连接,添加文件如下:

  1. 将 opencv_ffmpeg.dll和opencv_ffmpeg_64.dll 复制到openCv资源的3rdparty\ffmpeg目录下
    在这里插入图片描述
  2. 将 ippicv_windows_20151201.zip 解压到:\3rdparty\ippicv\unpack 如果没有unpack文件夹,新建一个。形成这样的目录树: \3rdparty\ippicv\unpack\ippicv_win…,请仔细对比路径:
    在这里插入图片描述
  3. opencv_contrib里面的添加如下文件。
    在这里插入图片描述