效果
相關內容
人臉識別知識點
人臉識別過程:
識別原理簡述:算法根據代碼中設置的目標檢測閾值參數(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));
}