Qt+openCV 打开摄像头并进行人脸检测

opencv 打开摄像头并进行人脸检测

开发环境:Qt5.12.4, MSVC2017, win10

首先,梳理一下流程

  1. 在Qt内配置opencv库
  2. 开启一个子线程来持续从摄像头获取图像帧
  3. 用获取到的图像帧传入opencv 人脸识别算法,并画出矩形框
  4. 将带有人脸矩形框的图像帧传入主界面进行展示

创建一个widget工程( 最好是QQuick工程,这里只为了展示人脸检测效果方便,所以创建widget工程 )

创建好工程后,取消勾选shadow build
在这里插入图片描述然后再工程.pro文件的同级目录创建四个文件夹, debug, release,lib, resources。
在这里插入图片描述
然后在lib文件夹里面创建两个文件夹, opencvInclude, opencvlib
在这里插入图片描述

Qt配置openCV库

我使用的opencv版本是3.4.1 ,64位,点击翻页寻找opencv3.4.1

在这里插入图片描述
下载完成后,安装:
在这里插入图片描述
安装完成后,在安装路径找到 build文件夹,
在这里2222图片描述
在build文件夹里面有一个X64文件夹,进去选择相应的编译器版本,
在这里插入图片描述
这里我使用的是MSVC2017,也就是VC15, 然后在下一层路径找到lib文件夹里面的两个库, 一个是opencv_world341.lib( release 使用的库 ),另一个是opencv_world341d.lib( debug使用的库 )。
在这里插入图片描述
将这两个库复制进工程目录 lib/opencvlib 里面
在这里插入图片描述

然后再将opencv3.4.1安装路径下的 build/include下的两个文件夹:opencv, opencv2复制进工程目录下的 lib/opencvinclude
在这里插入图片描述
然后,再将opencv3.4.1安装路径下 build/x64/vc15/bin 路径下的两个动态库:opencv_world314.dll -> 复制进工程路径下的debug文件夹,opencv_world314d.dll ->复制进工程路径下的release文件夹,

添加人脸模型xml文件

找到opencv3.4.1安装路径下 build/etc/haarcascades/ 下的haarcascade_frontalface_alt2.xml 文件,然后再工程路径下创建文件夹resources , 将haarcascade_frontalface_alt2.xml 复制到resources文件夹里面

###至此,所需要的文件添加完毕!

配置.pro文件

在工程 .pro文件中添加配置信息如下:

INCLUDEPATH	+= $$PWD/lib/opencvInclude

CONFIG( debug, debug | release ){
			DESTDIR = $$PWD/debug
			LIBS += -L$$PWD/lib/opencvlib -lopencv_world341d
}

CONFIG( release , debug | release ){
			DESTDIR = $$PWD/release 
			LIBS += -L$$PWD/lib/opencvlib -lopencv_world341
}

#####至此,opencv库配置完毕

接下来开始使用opencv


第一步: 打开摄像头并获取图像

在写这篇博客之前,我最开始使用的是Quick自带的Camera类来打开摄像头并获取图像(参考这篇文章,虽然是安卓平台,但是和windows上的开发几乎一样)
,后来因为公司采购的电脑性能太低了,用Quick自带的Camera类画面比较卡顿,所以采用opencv的方法打开摄像头。

首先,新建一个人脸检测的类
FaceRecognition.h

#ifndef FACERECOGNITION_H
#define FACERECOGNITION_H

#include <QObject>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <vector>
#include <QDateTime>
#include <iostream>
#include <QTimer>

#include "opencv2/opencv.hpp"
#include "opencv2/core.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;
using namespace std;

class FaceRecognition : public QObject
{
    Q_OBJECT
public:
    explicit FaceRecognition(QObject *parent = nullptr);

    //初始化人脸识别
    void initFaceRecog();

    //初始化定时器
    void initTimer();

    //设置opencv人脸识别库的xml文件
    bool setXmlFilePath( QString path );

    //获取opencv人脸识别库文件的路径
    QString getXmlFilePath();

    //设置成员变量m_objFrame的值
    void setFrame( Mat frame );

    // 将人脸在图像中使用矩形框出来
    Mat paintRect( Mat frame );

    //获取人脸的数量
    int getFaces();

    //http标志位,用于等待返回结果
    void setHttpAvalable( bool state );

    //获取http的标志位结果
    bool getHttpAvailable();

signals:

public slots:
    void onTimerTimeout();

private:
    //人脸分类器
    CascadeClassifier    m_objFace_cascade;
    //opencv的Mat
    Mat                  m_objFrame;
    //人脸识别库的xml文件路径
    QString              m_qsXmlFilePath;
    //存储人脸框
    vector< Rect >       m_veFaces;
    //是否识别标志位
    bool                 m_bRecognition;
    //人脸数量
    int                  m_iFaces;
    //定时器
    QTimer               m_timer;
    // 等待http返回结果的标志位
    bool                 m_bHttpAvalable;
};

#endif // FACERECOGNITION_H

FaceRecognition.cpp

#include "FaceRecognition.h"

FaceRecognition::FaceRecognition(QObject *parent) : QObject(parent)
{
    initFaceRecog();
    initTimer();
}

void FaceRecognition::initFaceRecog()
{
    m_bRecognition = true;
    bool ok = setXmlFilePath( "../../resources/haarcascade_frontalface_alt2.xml" );
    if( !ok )
    {
        qDebug() << " xml file not existed";
        return;
    }

    //加载人物训练模型
    if( !m_objFace_cascade.load( m_qsXmlFilePath.toLocal8Bit().toStdString() ) )
    {
        qDebug() << " load xml file failed ";
        return;
    }
    qDebug() << " load xml file success ";
}

void FaceRecognition::initTimer()
{
    m_timer.setInterval( 300 );
    connect( &m_timer, &QTimer::timeout, this, &FaceRecognition::onTimerTimeout );
    m_timer.start();
}

bool FaceRecognition::setXmlFilePath( QString path )
{
    QFile file( path );
    QFileInfo fileInfo( file );
    if( !fileInfo.exists() )
    {
        return false;
    }
    m_qsXmlFilePath = fileInfo.absoluteFilePath();
    qDebug() << "xml path = " << m_qsXmlFilePath;
    return true;
}

QString FaceRecognition::getXmlFilePath()
{
    return m_qsXmlFilePath;
}

void FaceRecognition::setFrame( Mat frame )
{
    if( frame.empty() )
    {
        qDebug() << " empty frame ";
        return;
    }
    m_objFrame = frame;
}

Mat FaceRecognition::paintRect( Mat frame )
{
    if( !m_bRecognition )
    {
        return frame;
    }
    setFrame( frame );
    m_veFaces.clear();
    Mat grayImg;
    Mat outPutGrayImg;
    Mat smallImg;

    //转为灰度图
    cvtColor( m_objFrame, grayImg, cv::COLOR_BGR2GRAY );

//    resize( grayImg, smallImg, Size(), 0.9, 0.9, INTER_LINEAR );

    //直方图均衡化,提升图像质量
    equalizeHist( grayImg, outPutGrayImg );

//    cout<< " size = " <<outPutGrayImg.size() << endl;

//    qint64 time1 = QDateTime::currentMSecsSinceEpoch();

    //开始检测人脸, Size 的大小会影响人脸检测的性能, 建议将最小Size稍微设大一点
    m_objFace_cascade.detectMultiScale( outPutGrayImg, m_veFaces, 1.1, 3, 0, Size( 100, 100 ), Size( 300, 300 ) );

    //存储图像中人脸的数量, 以此判断是否将该张图在DevCamera.cpp的run()函数中,通过http发送至服务器
    m_iFaces = m_veFaces.size();
//    qDebug() << " there are " << m_veFaces.size() << " faces ";

//    qDebug() << QString( " coast %1 " ).arg( QDateTime::currentMSecsSinceEpoch() - time1 );

    for( size_t i = 0; i < m_veFaces.size(); i++ )
    {
        Rect tmpFace = m_veFaces[ i ];
        Point point1( tmpFace.x, tmpFace.y );
        Point point2( tmpFace.x + tmpFace.width, tmpFace.y + tmpFace.height );
        rectangle( m_objFrame, point1, point2, Scalar( 255, 0, 0 ) );
    }

    return m_objFrame;
}

int FaceRecognition::getFaces()
{
    return m_iFaces;
}

void FaceRecognition::setHttpAvalable( bool state )
{
    m_bHttpAvalable = state;
}

bool FaceRecognition::getHttpAvailable()
{
    return m_bHttpAvalable;
}

void FaceRecognition::onTimerTimeout()
{
    m_bRecognition = !m_bRecognition;
}

然后,在新建一个摄像机设备类,用于获取摄像头的图像,此处需要开启一个新的线程,用于不断的获取摄像头的图像。并传入人脸识别类进行人脸识别,输入带人脸框的图像.

DevCamera.h

#ifndef DEVCAMERA_H
#define DEVCAMERA_H

#include <QObject>
#include <iostream>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QImage>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include "FaceRecognition.h"

class DevCamera : public QThread
{
    Q_OBJECT
public:
    DevCamera();

    //将opencv的Mat类型转换为QImage
    QImage matToQimage( Mat frame );

    //QThread 实际所在的线程
    void run();

    //关闭摄像头
    void closeCamera();

signals:
    void signalNewQimageAvailable( QImage image );

    void signalQimageToServer( QImage image );
private:
    //摄像机对象
    VideoCapture       *m_pCamera;
    //摄像机运行标志位
    bool                m_bCameraRunning;   
    //线程锁
    QMutex              m_objMutex;    
    //opencv人脸识别库文件的路径
    QString             m_objXmlPath;
    //
    QImage              m_objQimg;
    // opencv的 Mat类型
    Mat                 m_objFrame;
    //人脸识别类
    FaceRecognition     m_objFaceRecog;
};

#endif // DEVCAMERA_H

DevCamera.cpp

#include "DevCamera.h"

DevCamera::DevCamera()
{
    m_pCamera = new VideoCapture();
}

void DevCamera::run()
{
    if( !m_pCamera->isOpened() )
    {
        m_pCamera->open( 0 );
    }
    m_bCameraRunning = true;
    while( true )
    {
        m_objMutex.lock();
        if( !m_bCameraRunning )
        {
            m_objMutex.unlock();
            break;
        }
        m_objMutex.unlock();
        *m_pCamera >> m_objFrame;

        //检测人脸
        m_objFrame = m_objFaceRecog.paintRect( m_objFrame );

        QImage img = matToQimage( m_objFrame );
        if( m_objFaceRecog.getFaces() > 0 )
        {
            emit signalQimageToServer( img );
        }
        emit signalNewQimageAvailable( img );
        QThread::msleep( 20 );
    }
    m_pCamera->release();
    m_bCameraRunning = false;
    qDebug() << " break while ";
}

void DevCamera::closeCamera()
{
    m_objMutex.lock();
    m_bCameraRunning = false;
    m_objMutex.unlock();
}

QImage DevCamera::matToQimage( Mat frame )
{
    QImage img;

    if (frame.channels()==3)
    {
        cvtColor(frame, frame, CV_BGR2RGB);
        img = QImage((const unsigned char *)(frame.data), frame.cols, frame.rows,
                frame.cols*frame.channels(), QImage::Format_RGB888);
    }
    else if (frame.channels()==1)
    {
        img = QImage((const unsigned char *)(frame.data), frame.cols, frame.rows,
                frame.cols*frame.channels(), QImage::Format_ARGB32);
    }
    else
    {
        img = QImage((const unsigned char *)(frame.data), frame.cols, frame.rows,
                frame.cols*frame.channels(), QImage::Format_RGB888);
    }

    return img;
}

注意!!!:要显示出图像,只需响应DevCamera对象的 signalNewQimageAvailable( img ) 信号!。 还有,opencv 的人脸检测性能比较低,在识别的人脸的时候最好设置一个检测范围:m_objFace_cascade.detectMultiScale( outPutGrayImg, m_veFaces, 1.1, 3, 0, Size( 100, 100 ), Size( 300, 300 ) ); 最小识别尺寸最好不低于100,最大最好不高于400,不然性能会很低,我在此处还加了一个定时器,设定为0.5秒检测一次,以此辅助提升一些性能。

显示效果如下图所示:
在这里插入图片描述
。关键代码到此已经结束,由于我是用QML的Image控件来显示图像的,但我的工程为QWidget工程,所以其余代码都是用来将QML嵌入QWidget的代码,对识别部分无影响。

完整的工程已经上传个人主页,(点击下载)有需要的可以下载,没积分的私我发给你

  • 17
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 38
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值