效果
相关内容
人脸识别知识点
人脸识别过程:
识别原理简述:算法根据代码中设置的目标检测阈值参数(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));
}