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

版权声明:本文为博主原创文章,转载请附上博文链接! https://blog.csdn.net/u012902367/article/details/88944352


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

1. 安装cpenCV

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

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

2. 安装CMake

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

3. 编译openCV

用管理员身份运行刚才安装CMake,选择好路径后点击左下角Configure:
在这里插入图片描述
按照如下选择:
在这里插入图片描述
在这里插入图片描述
等待配置完成,过程可能需要等待几分钟:
在配置的过程中需要下载一些文件,最好有VPN,否则会下载失败:
在这里插入图片描述
在这里插入图片描述
完成过后在列表中勾选 WITH_QT和 WITH_OPENGL(在靠后一点位置),勾选过后再点击Configure:

在这里插入图片描述
出现Configuring done提示再点击Generate:
在这里插入图片描述
完成过后即可关闭此窗口。

开始编译

使用cmd到最开始自己新建的目录下执行mingw32-make
在这里插入图片描述
在这里插入图片描述
等待编译完成,可能需要等一小会:
在这里插入图片描述
继续执行mingw32-make install,并等待结束:
在这里插入图片描述
结束后把如下路径添加到环境变量(注意看这个路径位置):
在这里插入图片描述
在这里插入图片描述

4. 新建工程调用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

在这里插入图片描述
布局文件中就有两个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 ");
}

效果如下:
在这里插入图片描述
可以看出官方提供分类训练器也有一些误检测,也许是笔者环境问题吧。

猜你喜欢

转载自blog.csdn.net/u012902367/article/details/88944352
今日推荐