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));
}

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