Qt+OpenCV之usb摄像头视频流中的人脸识别及人脸抠图保存

效果

在这里插入图片描述

相关内容

Qt+OpenCV之图片中的人脸识别及人脸抠图

人脸识别知识点

人脸识别过程

输入图像
预处理
人脸检测
图像表示与特征提取
人脸识别

识别原理简述:算法根据代码中设置的目标检测阈值参数(Size)以方框区域对检测的图片进行从左到右从上到下的扫描,对扫描到的符合要求的目标返回变量矩阵。所以,当需要检测的图像越大时,检测时间就会越长。这里也用了检测前缩放图片的方式提高检测速度,但也带来了抠出的图像清晰度降低的问题。

识别算法存在的问题与提升:这里与上篇笔记均使用的OpenCV的haar算法进行人脸识别,开发比较简单,但也存在着较多缺陷,比如无法识别侧脸、人脸角度差时无法识别、识别准确率不够高(会识别到非人脸区域被标记为人脸)、识别速度不够快。不过可以在了解了人脸识别流程后采用更符合业务开发的算法,Dlib算法拥有更快的检测速度,OpenCV DNN算法则可满足更全面的需求,这篇文章里有对几种算法的优劣对比。

OpenCV播放视频流

视频流由一帧帧图像组成,播放视频流其实就是播放一帧帧图像,使用OpenCV的read()函数不断的读取显示图像就形成了视频流。一般网络视频是30帧/秒,cv::VideoCapture类的CV_WRAP virtual double get(int propId) const函数的参数设置为CV_CAP_PROP_FPS时可获取到当前摄像头的帧率。

cv::VideoCapture类的virtual bool open (int index)函数可以打开当前摄像头,参数为0时打开默认摄像头,多个摄像头时index递增。cv::VideoCapture类的virtual bool read (OutputArray image)函数可以从摄像头读取图像帧。

完整代码

pro文件中引入库文件

INCLUDEPATH += H:\opencv3.4.3\buildOpencv\install\include
LIBS += H:\opencv3.4.3\buildOpencv\install\x86\mingw\bin\libopencv*.dll

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;

    cv::VideoCapture cap;
    cv::Mat cvImg;

    QTimer *timer;

    int num;
    int scaleNum;
    void showVideo();

    //分类器
    cv::CascadeClassifier faceCascade;

private slots:
    void update();
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    num = 0;
    scaleNum = 4;

    //加载级联器
    int faceCascadeState = faceCascade.load("H:/opencv3.4.3/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml");
    if(!faceCascadeState)
    {
        qDebug()<<"级联器加载失败";
    }

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    showVideo();
}

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

void Widget::showVideo()
{
    cap.open(0);
    if(!cap.isOpened())
    {
        qDebug()<<"打开摄像头失败";
        return;
    }
    timer->start(5);
}

void Widget::update()
{
    //从摄像头读取图像帧
    cap.read(cvImg);

    /***在右侧QLabel上显示人脸抠图,并框出左侧QLabel视频流中的人脸***/
    std::vector<cv::Rect> faces;
    cv::Mat smallImg;
    cv::Mat grayImg;

    //缩放图像尺寸,可以极大的提高人脸识别速度
    cv::resize(cvImg, smallImg, cv::Size(), (double)1/scaleNum, (double)1/scaleNum, cv::INTER_LINEAR_EXACT);
    //图像预处理,转为灰度图
    cv::cvtColor(smallImg, grayImg, cv::COLOR_BGR2GRAY);
    //图像预处理,直方图均衡化,用来增加图像对比度
    equalizeHist(grayImg, grayImg);

    double t = (double)cv::getTickCount();
    //实测Size设置为40约可以识别到距离摄像头2m内的人脸,设置为60约可识别到1.5m
    faceCascade.detectMultiScale( grayImg, faces, 1.1, 2, 0, cv::Size(40/scaleNum, 40/scaleNum) );
    t = ((double)cv::getTickCount() - t)*1000/cv::getTickFrequency();
    qDebug()<<"检测用时 =============="<<t<<"ms";

    for(size_t i = 0; i < faces.size(); i++)
    {
        num = num + 1;

        //用矩形框出人脸
        cv::rectangle(cvImg, cv::Point(faces[i].x*scaleNum, faces[i].y*scaleNum),
                      cv::Point((faces[i].x + faces[i].width)*scaleNum, (faces[i].y + faces[i].height)*scaleNum),
                      cv::Scalar(0, 255, 0), 1, 8);
        cv::Mat mat = smallImg(faces[i]);

        cv::Mat myFace;
        cv::Mat rgbImg2;
        //调整图像大小为92*112
        cv::resize(mat, myFace, cv::Size(92, 112));

        cv::cvtColor(myFace, rgbImg2, cv::COLOR_BGR2RGB);
        QImage img1((const uchar*)rgbImg2.data,
                    rgbImg2.cols, rgbImg2.rows,
                    rgbImg2.cols * rgbImg2.channels(),
                    QImage::Format_RGB888);
        ui->label_2->setPixmap(QPixmap::fromImage(img1));

        /***采集到的人脸图片保存到本地***/
        QString fileName = "H:/test_face_img/" + QString::number(num) + ".png";
        img1.save(fileName, "png", 0);
    }

    /***在左侧QLabel上播放视频流***/
    cv::Mat rgbImg;
    //颜色空间(通道数)转换,由BGR转RGB,param1:输入图像;param2:输出图像;param:转换格式
    cv::cvtColor(cvImg, rgbImg, cv::COLOR_BGR2RGB);
    QImage img((const uchar*)rgbImg.data,
               rgbImg.cols, rgbImg.rows,
               rgbImg.cols * rgbImg.channels(),
               QImage::Format_RGB888);
//    ui->label->setMinimumSize(img.width(), img.height());
//    ui->label->setMaximumSize(img.width(), img.height());
    ui->label->setPixmap(QPixmap::fromImage(img));
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章