Qt 使用摄像头通过openCV进行人脸识别


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

1. 安装cpenCV

  • 官网获取到安装程序:
    Qt 使用摄像头通过openCV进行人脸识别
    本文选择了一个历史版本(提醒一下不同版本使用方法会存在差异,如果读者想要按照下面的方式尝试,第一次建议选择和笔者同样的版本,成功以后再尝试新版本,还有就是本文所选择的路径在代码中会用到,如果读者怕麻烦修改,甚至可以把盘符和安装路径设置成与本文一致)
    Qt 使用摄像头通过openCV进行人脸识别
    如果官网下载太慢可以选择再****里面搜索下载:
    Qt 使用摄像头通过openCV进行人脸识别

下载下来过后运行安装,请选择纯英文路径:
Qt 使用摄像头通过openCV进行人脸识别
等待安装完成:
Qt 使用摄像头通过openCV进行人脸识别

  • git上获取
    Qt 使用摄像头通过openCV进行人脸识别
    把两个都下载下来,下面哪一个包含了一些其它模块功能,比如常用的人脸识别。
    下载下来后解压(英文路径),我把后面-mastre去掉了,然后创建了一个build目录,后面编译的时候会用:
    Qt 使用摄像头通过openCV进行人脸识别

2. 安装CMake

官方下载CMake:https://cmake.org/download/
Qt 使用摄像头通过openCV进行人脸识别
下载完后双击安装,安装到纯英文路径,安装完后把bin目录加入环境变量:
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
环境变量配置:
Qt 使用摄像头通过openCV进行人脸识别
顺便也将Qt的环境变量配置一下
Qt 使用摄像头通过openCV进行人脸识别

3. 编译openCV

用管理员身份运行刚才安装CMake,

**注意:**若果是选择的使用exe安装的openCV,路径是选择的source:
Qt 使用摄像头通过openCV进行人脸识别
**注意:**如果是选择git下载解压下来的会发下解压出来的文件目录和exe安装的source文件加下目录几乎一样:
Qt 使用摄像头通过openCV进行人脸识别
选择好后点击左下角Configure出现如下对话框,照图选择选择:
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
等待配置完成,过程可能需要等待几分钟,在配置的过程中需要下载一些文件:
Qt 使用摄像头通过openCV进行人脸识别
完成过后在列表中勾选 WITH_QT和 WITH_OPENGL(在靠后一点位置),还要选择,勾选过后再点击Configure:

在这里插入图片描述
出现Configuring done提示再点击Generate:
Qt 使用摄像头通过openCV进行人脸识别
完成过后即可关闭此窗口。

开始编译

使用cmd到最开始自己新建的目录下执行mingw32-make
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
等待编译完成,可能需要等一小会:
Qt 使用摄像头通过openCV进行人脸识别
继续执行mingw32-make install,并等待结束:
Qt 使用摄像头通过openCV进行人脸识别
结束后把如下路径添加到环境变量(注意看这个路径位置):
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别

4. 新建工程调用openCV

如果不想敲可以直接下载这个应用的工程源码
新建一个应用:
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
.pro文件下添加如下代码,注意里面的路径需要换成读者自己安装的路径

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

Qt 使用摄像头通过openCV进行人脸识别
布局文件中就有两个QLabel,3个QPushButton,为了让读者看得清楚点把两个QLabel背景设置成了绿色,这个对使用没有一点影响,读者可以不用管这个颜色,其中对象的名字也写在图里面了:(camera,photo,open,take,close)
Qt 使用摄像头通过openCV进行人脸识别
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文件同级目录下一起打包:
Qt 使用摄像头通过openCV进行人脸识别
Qt 使用摄像头通过openCV进行人脸识别
到此就可以编译成功运行了,左边的是摄像头实时图像,右边是点击拍照后保存的图片:
Qt 使用摄像头通过openCV进行人脸识别

5. openCV中的基础人脸识别调用

openCV资源里面有一些现成的.xml文件,就是用来识别人脸的,这些文件在本文最开始openCV的安装路径下就可以找到:
Qt 使用摄像头通过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;

Qt 使用摄像头通过openCV进行人脸识别

  • 修改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 ");
}

效果如下:
Qt 使用摄像头通过openCV进行人脸识别
可以看出官方提供分类训练器也有一些误检测,也许是笔者环境问题吧。