1> 该项目所用环境:qt-opensource-windows-x86-mingw491_opengl-5.4.0
2> 配置opencv库路径:
1、在D盘下创建一个opencv的文件夹,用于存放所需材料
2、在opencv的文件夹下创建一个名为:opencv3.4-qt-intall 文件夹
3、将资料中的opencv_library的install文件,复制到opencv3.4-qt-intall 文件夹中
4、将路径:D:\opencv\opencv3.4-qt-intall\install\x86\mingw\bin 放入电脑的系统路径中
3> 测试是否配置好
创建一个新的qt工程,将对应配置文件和头文件放入后,不报错就说明配置成功
- Mat imread( const String& filename, int flags = IMREAD_COLOR );
- //功能:读取出图像
- //参数:图像路径
- //返回值:读取的图像
- void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);
- 功能:命名一个图像窗口
- 参数1:窗口名称
- 参数2:窗体尺寸,默认为自适应大小
- 返回值:无
- void imshow(const String& winname, const ogl::Texture2D& tex);
- //功能:展示图像
- //参数1:要展示图像的窗口名称
- //参数2:要展示的二维图像
- //返回值:无
- #include "widget.h"
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
-
- //1、定义一个图像容器
- Mat src;
-
- //2、将图像加载进来
- //函数原型:Mat imread( const String& filename, int flags = IMREAD_COLOR );
- //参数:图像的路径
- //返回值:图像容器
- src = imread("D:/opencv/resource/age.jpg");
-
- //4、命名一个展示图像的窗口
- //namedWindow("Test");
-
- //5、展示图像
- //函数原型:void imshow(const String& winname, const ogl::Texture2D& tex);
- //参数1:要展示图像的窗口名称
- //参数2:要展示的图像
- //返回值:无
- imshow("Test", src);
-
- return a.exec();
- }
- virtual bool open(const String& filename);
- //参数:要打开视频的路径
- //返回值:成功返回true失败返回false
- virtual bool read(OutputArray image);
- 功能:读取视频流中的图像
- 参数:图像容器
- 返回值:成功读取返回true,失败或者视频结束返回false
- void flip(InputArray src, OutputArray dst, int flipCode);
- //将图像进行旋转
- //参数1:要处理的图像
- //参数2:处理后的图像容器
- //参数3:处理规则:0:表示沿x翻转,1表示沿y轴翻转,-1表示沿xy轴翻转
- int waitKey(int delay = 0);
- 功能:阻塞等待用户输入数据,如果delay=0,则一直等待
- 参数:毫秒数
- 返回值:在等待过程中用户按下键的值
- #include "widget.h"
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
-
- //1、定义视频流对象
- VideoCapture v(0); //表明使用摄像头构造一个视频流对象
-
- //2、读取摄像头中的图像
- Mat src; //用于存放读取出来的图像
-
- //函数原型:virtual bool read(OutputArray image);
- //功能:从视频流中读取一张图像放入参数中
- //参数:图像容器
- //返回值:成功返回真,失败或者读取视频结束返回假
- while(v.read(src))
- {
- //将图像进行翻转
- //函数原型:void flip(InputArray src, OutputArray dst, int flipCode);
- //参数1:要翻转的图像
- //参数2:翻转后的图像容器
- //参数3:翻转规则:正数表示按y轴翻转,0表示按x轴翻转,负数表示按xy轴翻转
- flip(src, src, 1);
-
- //展示图像
- imshow("Test1", src);
-
- //加延时函数
- //函数原型:int waitKey(int delay = 0);
- //参数:等待时间
- //返回值:在等待期间用户按下的键盘的ascii值 ESC键对应的值为27
- if(waitKey(20)==27)
- {
- break;
- }
- }
-
- return a.exec();
- }
- void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
- 功能:转换图像色彩空间
- //参数1:要转换的图像
- //参数2:转变后图像容器
- //参数3:转换规则:BGR to gray
- 返回值:无
- void equalizeHist( InputArray src, OutputArray dst );
- 参数1:输入的灰度图像,必须是8-bit的单通道图像
- 参数2:输出的图像
- 图像直方图:对整个图像在灰度范围内的像素值(0-255)统计出现的频率,据此生成直方图,直 方图反应了图像的灰度分布情况。
- #include "widget.h"
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
-
- //1、定义视频流对象
- VideoCapture v(0); //表明使用摄像头构造一个视频流对象
-
- //2、读取摄像头中的图像
- Mat src; //用于存放读取出来的图像
- Mat gray; //用于存储灰度图的图像容器
- Mat dst; //用于存储均衡化处理后的图像容器
-
- //函数原型:virtual bool read(OutputArray image);
- //功能:从视频流中读取一张图像放入参数中
- //参数:图像容器
- //返回值:成功返回真,失败或者读取视频结束返回假
- while(v.read(src))
- {
- //将图像进行翻转
- //函数原型:void flip(InputArray src, OutputArray dst, int flipCode);
- //参数1:要翻转的图像
- //参数2:翻转后的图像容器
- //参数3:翻转规则:正数表示按y轴翻转,0表示按x轴翻转,负数表示按xy轴翻转
- flip(src, src, 1);
-
- //3、将图像灰度处理
- //函数原型:void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
- //参数1:要转换的图像
- //参数2:转换后的图像容器
- //参数3:转换规则 CV_BGR2GRAY表示将bgr彩色图转换为gray灰度图
- //返回值:无
- cvtColor(src, gray, CV_BGR2GRAY);
-
- //4、对图像进行均衡化处理
- //函数原型:void equalizeHist( InputArray src, OutputArray dst );
- //参数1:要进行均衡化处理的图像,必须是单通道灰度图
- //参数2:均衡化处理后的图像容器
- //返回值:无
- equalizeHist(gray, dst);
-
- //展示彩色图像
- imshow("Test1", src);
-
- //展示灰度图像
- imshow("Test2", gray);
-
- //展示均衡化处理后的图像
- imshow("Test3", dst);
-
- //加延时函数
- //函数原型:int waitKey(int delay = 0);
- //参数:等待时间
- //返回值:在等待期间用户按下的键盘的ascii值 ESC键对应的值为27
- if(waitKey(20)==27)
- {
- break;
- }
- }
-
- return a.exec();
- }
- void detectMultiScale(
- const Mat& image,
- CV_OUT vector& objects, //int arr[4];
- double scaleFactor = 1.1,
- int minNeighbors = 3,
- int flags = 0,
- Size ize = Size(24,24))
- 参数1:待检测灰度图像(数据少处理起来简单)
- 参数2:被检测物体的矩形框向量( 人脸Rect矩形区域,其中objects.size()是人脸个数 )
- 参数3:前后两次相继的扫描中搜索窗口的比例系数,默认为1.1 即每次搜索窗口扩大10%
- 参数4:构成检测目标的相邻矩形的最小个数 如果组成检测目标的小矩形的个数和小于 minneighbors - 1 都会被除
- 参数5:若设置为CV_HAAR_DO_CANNY_PRUNING 函数将会使用Canny边缘检测来排除边缘过多 或过少的区域,,一般采用默认值0
- 参数6:用来限制得到的目标区域的范围,一般检测人脸使用Size(24, 24)
- void rectangle(CV_IN_OUT Mat& img, Rect rec,
- const Scalar& color, int thickness = 1,
- int lineType = LINE_8, int shift = 0);
- img:图像。
- rec:表征矩形的位置和长宽。
- color:线条颜色 (RGB) 。
- thickness:组成矩形的线条的粗细程度。
- line_type:线条的类型。
- shift:坐标点的小数点位数,0表示没有小数点。
- #include "widget.h"
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- Widget w;
- w.show();
-
- //1、定义视频流对象
- VideoCapture v(0); //表明使用摄像头构造一个视频流对象
-
- //2、读取摄像头中的图像
- Mat src; //用于存放读取出来的图像
- Mat gray; //用于存储灰度图的图像容器
- Mat dst; //用于存储均衡化处理后的图像容器
-
- //5、实例化一个级联分类器的对象,用于找到图像中的人脸矩形区域
- CascadeClassifier c;
- //给类对象装载人脸识别模型
- //函数原型:bool load( const String& filename );
- //功能:给级联分类器对象,下载一个识别模型
- //参数:人脸识别模型的文件路径
- //返回值:成功下载返回真,失败返回假
- if(!c.load("D:/opencv/resource/haarcascade_frontalface_alt2.xml"))
- {
- QMessageBox::information(NULL,"失败", "人脸识别模型装载失败");
- return -1;
- }
-
- //定义容器存放人脸分类后的矩形框
- vector
faces; -
- //函数原型:virtual bool read(OutputArray image);
- //功能:从视频流中读取一张图像放入参数中
- //参数:图像容器
- //返回值:成功返回真,失败或者读取视频结束返回假
- while(v.read(src))
- {
- //将图像进行翻转
- //函数原型:void flip(InputArray src, OutputArray dst, int flipCode);
- //参数1:要翻转的图像
- //参数2:翻转后的图像容器
- //参数3:翻转规则:正数表示按y轴翻转,0表示按x轴翻转,负数表示按xy轴翻转
- flip(src, src, 1);
-
- //3、将图像灰度处理
- //函数原型:void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
- //参数1:要转换的图像
- //参数2:转换后的图像容器
- //参数3:转换规则 CV_BGR2GRAY表示将bgr彩色图转换为gray灰度图
- //返回值:无
- cvtColor(src, gray, CV_BGR2GRAY);
-
- //4、对图像进行均衡化处理
- //函数原型:void equalizeHist( InputArray src, OutputArray dst );
- //参数1:要进行均衡化处理的图像,必须是单通道灰度图
- //参数2:均衡化处理后的图像容器
- //返回值:无
- equalizeHist(gray, dst);
-
- //6、使用级联分类器对象,获取人脸矩形区域
- //函数原型:void detectMultiScale( InputArray image,CV_OUT std::vector
& objects) - //参数1:要进行识别的图像
- //参数2:对该图像识别后,的矩形框存放的数组容器
- c.detectMultiScale(dst, faces);
-
- //7、将上述得到的矩形框,全部都绘制到图像上
- for(int i=0; i
size(); i++) - {
- //将任意一个矩形框,全部都绘制到图像上
- //函数原型:void rectangle(CV_IN_OUT Mat& img, Rect rec,const Scalar& color, int thickness = 1)
- //参数1:要被绘制的图像
- //参数2:要绘制的矩形框
- //参数3:矩形框的颜色
- //参数4:矩形框的粗细
- //返回值:无
- rectangle(src, faces[i], Scalar(0,0,255), 2);
- }
-
- //8、像素反差
- for(int i=0; i
//外层循环控制行数 - {
- for(int j=0; j
//内层循环控制列数 - {
- //找到任意一个像素:src.at
(i,j) - //找到任意一个像素中的通道中的值src.at
(i,j)[k] - for(int k=0; k<3; k++)
- {
- src.at
(i,j)[k] = 255 - src.at(i,j)[k]; //对像素进行反差 - }
-
- }
- }
-
- //展示彩色图像
- imshow("Test1", src);
-
- //展示灰度图像
- imshow("Test2", gray);
-
- //展示均衡化处理后的图像
- imshow("Test3", dst);
-
- //加延时函数
- //函数原型:int waitKey(int delay = 0);
- //参数:等待时间
- //返回值:在等待期间用户按下的键盘的ascii值 ESC键对应的值为27
- if(waitKey(20)==27)
- {
- break;
- }
- }
-
- return a.exec();
- }
机器学习的作用:根据提供的图片模型通过算法生成数据模型,从而在其它图片中查找相关的目 标。
级联分类器:是用来人脸识别。 在判断之前,我们要先进行学习,生成人脸的模型以便后续识别使用。
人脸识别器:判断是谁的面部。 FaceRecognizer类是opencv提供的人脸识别器基类,LBPHFaceRecognizer是根据LBPH算法实 现的识别器类,其中LBPHFaceRecognizer识别器支持在原有模型基础上继续学习(模型数据可以累 计)。
- 所需的头文件:#include 、using namespace cv::face;
- 创建空的人脸识别器对象:Ptr
recognizer = - LBPHFaceRecognizer::create();
-
- 根据已有的模型创建人脸识别器对象,在创建人脸识别器的时候,需要一个已经学习好的模型文件:
- Ptr
recognizer = FaceRecognizer::load("模型文 - 件.xml");
- 容器:容器中装了n张人脸Mat对象,先采集脸,装到容器中,存储标签,人的身份证,每一张脸
- 给一个编号:1 张三脸 2 李四脸 3 王五脸。
- 功能函数1:void update(InputArrayOfArray src,InputArray labels)//机器学习并更新模型
- 功能函数2:void train(InputArrayOfArrays src,InputArray labels);//只是学习,不更新
- //参数1src:图片模型数组 vector
- //参数2labels:标签数组,每个模型识别后的标签vector
- 功能函数:void save(const String& filename);//参数1:模型文件的名字
- 例如:
- recognizer->update(study_faces,study_label);//学习
- recognizer->save("face.xml");//将学习的成果,保存到face.xml模型文件中,生成模型:
- study_faces.clear();、study_labels.clear();
- 判断这个人脸到底是谁。
- 功能函数:
- void predict(InputArray src, int &label, double &confidence)
- //参数1:预测图形 Mat src
- //参数2::预测后的标签,学习时对应的标签
- //参数3:预测出结果的可信度,数值越小可信度越高
- 例如:
- int label = -1;//预测后的标签,学习时对应的标签
- double confidence = 0;//可信度
- Mat face = frame(faces[0]);//人脸区域
- cvtColor(face,face,CV_BGR2GRAY);//更改色彩空间
- cv::resize(face,face,Size(90,90));//设置人脸的大小
- recognizer->predict(face,label,confidence); //预测,相当于识别人脸,预测出人脸是谁的
- 面部,label的值就那张脸对应的标签,如果预测不到,label的值是-1。
- 功能函数:void setThreshold(double val);
- //参数1:预测可信度极值,预测可信度超出极值则预测失败。
- #-------------------------------------------------
- #
- # Project created by QtCreator 2023-09-04T19:10:16
- #
- #-------------------------------------------------
-
- QT += core gui
-
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
- TARGET = 01_demo
- TEMPLATE = app
-
-
- SOURCES += main.cpp\
- widget.cpp
-
- HEADERS += widget.h
-
- FORMS += widget.ui
-
- INCLUDEPATH += C:/opencv/opencv3.4-qt-install/install/include
- INCLUDEPATH += C:/opencv/opencv3.4-qt-install/install/include/opencv
- INCLUDEPATH += C:/opencv/opencv3.4-qt-install/install/include/opencv2
- LIBS += C:/opencv/opencv3.4-qt-install/install/x86/mingw/lib/libopencv_*.a
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace cv;
- using namespace cv::face;
- using namespace std;
-
- namespace Ui {
- class Widget;
- }
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- explicit Widget(QWidget *parent = 0);
- ~Widget();
-
- private slots:
- void on_openCameraBtn_clicked();
-
- void on_closeCameraBtn_clicked();
-
- void on_inputFaceBtn_clicked();
-
- private:
- Ui::Widget *ui;
- /***************************第一模块:关于摄像头的相关组件*****************************/
- VideoCapture v; //视频流对象
-
- Mat src; //原图像
- Mat rgb; //存放rgb图像,因为qt能识别的图像色彩空间为rgb
- Mat gray; //灰度图
- Mat dst; //均衡化图像
-
- CascadeClassifier c; //级联分类器
- vector
faces; //存储人脸举行的容器 - int cameraId; //摄像头的定时器
- void timerEvent(QTimerEvent *event); //定时器事件处理函数
- /***************************第二模块:录入人脸的相关组件*****************************/
- Ptr
recognizer; //人脸识别器 - vector
study_face; //要录入的人脸容器 - vector<int> study_lab; //要录入的人脸的标签
- int studyId; //人脸录入的定时器
- int flag; //表示是否正在录入人脸
- int count; //记录学习的次数
- /***************************第三模块:人脸检测的相关组件*****************************/
- int checkId; //人脸检测的定时器
- };
-
- #endif // WIDGET_H
- #include "widget.h"
- #include "ui_widget.h"
-
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- //将登录按钮设置成不可用
- ui->loginBtn->setEnabled(false);
- //启动摄像头
- if(!v.open(0))
- {
- QMessageBox::information(this,"错误","打开摄像头失败");
- return;
- }
-
- //将级联分类器加载进来
- if(!c.load("C:/opencv/resource/haarcascade_frontalface_alt.xml"))
- {
- QMessageBox::information(this,"失败","人脸识别模型装载失败");
- return;
- }
-
- //配置人脸识别器
- QFile file("C:/opencv/resource/myFace.xml");
- //判断文件是否存在,如果存在,则直接下载,如果不存在,则创建一个人脸识别器
- if(file.exists())
- {
- //人脸模型存在,直接下载即可
- recognizer = FaceRecognizer::load
("C:/opencv/resource/myFace.xml"); - }
- else
- {
- //人脸模型不存在,则需要创建
- recognizer = LBPHFaceRecognizer::create();
- }
-
- //启动人脸检测到的定时器
- checkId = this->startTimer(3000);
-
- //设置人脸识别的可信度
- recognizer->setThreshold(100);
- flag = 0; //表明开始时就处于检测
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- //打开摄像头按钮对应的槽函数
- void Widget::on_openCameraBtn_clicked()
- {
- //启动定时器
- cameraId = this->startTimer(20);
- ui->cameraLab->show();
- }
-
- //关闭摄像头按钮对应的槽函数
- void Widget::on_closeCameraBtn_clicked()
- {
- //关闭定时器
- this->killTimer(cameraId);
- ui->cameraLab->hide();
- }
-
- //定时器事件处理函数
- void Widget::timerEvent(QTimerEvent *event)
- {
- //判断是哪个定时器到位
- if(event->timerId() == cameraId)
- {
- //1.从摄像头中读取一张图像
- v.read(src); //得到原图
-
- //2.将图像翻转
- flip(src,src,1);
-
- //3.将src的bgr图像转换为rgb图像
- cvtColor(src,rgb,CV_BGR2RGB);
-
- //4.重新设置大小
- cv::resize(rgb,rgb,Size(300,300));
-
- //5.灰度处理
- cvtColor(rgb,gray,CV_RGB2GRAY);
-
- //6.均衡化处理
- equalizeHist(gray,dst);
-
- //7.使用级联分类器获取人脸矩形区域
- c.detectMultiScale(dst,faces);
-
- //8.将矩形框绘制到rgb图像上
- for(int i=0; i
size(); i++) - {
- rectangle(rgb,faces[i],Scalar(255,0,0),2);
- }
-
- //9.使用rgb图像,将Mat图,构造出一个qt能识别的图像
- QImage img(rgb.data,rgb.cols,rgb.rows,rgb.cols*rgb.channels(),QImage::Format_RGB888);
- //功能:通过其他图像构造出一个QImage图像
- //参数1:其他图像的数据
- //参数2:图像的宽度
- //参数3:图像的高度
- //参数4:每一行的字节数
- //参数5:图像格式,24位图,每一种颜色使用8位表示
-
- //10.将图像展示到lab中
- ui->cameraLab->setPixmap(QPixmap::fromImage(img));
-
-
- }
-
- //判断是否是人脸录入定时器到位
- if(event->timerId() == studyId)
- {
- //判断ui界面是否有矩形框
- if(faces.empty())return;
-
- //判断人脸识别器是否存在
- if(recognizer.empty())return;
-
- //提示正在录入人脸
- qDebug() << "正在录入人脸...";
-
- //获取ui界面中矩形框框起来的人脸区域
- Mat face = src(faces[0]);
-
- //将该图像进行重新设置大小
- cv::resize(face,face,Size(100,100));
-
- //灰度处理
- cvtColor(face,face,CV_BGR2GRAY);
-
- //均衡化处理
- equalizeHist(face,face);
-
- //将人脸放入学习容器中
- study_face.push_back(face);
- study_lab.push_back(1);
- count++; //表明完成一次人脸的存放
- if(count == 50) //已经收集50张人脸进行学习
- {
- count = 0; //以便于下一次录入
-
- //更新人脸模型
- //函数原型:CV_WRAP virtual void update(InputArrayOfArrays src, InputArray labels);
- //参数1:要进行更新的人脸数组
- //参数2:要更新的人脸标签数组
- //返回值:无
- recognizer->update(study_face,study_lab);
-
- //将数据模型保存到本地磁盘中
- recognizer->save("C:/opencv/resource/myFace.xml");
-
- //殿后工作
- study_face.clear(); //清空人脸数组
- study_lab.clear(); //清空标签数组
- flag = 0; //表明录入已经结束,可以进行人脸检测了
- ui->inputFaceBtn->setEnabled(true); //按钮设置成可用状态
- this->killTimer(studyId); //关闭人脸录入的定时器
- QMessageBox::information(this,"成功","人脸录入成功");
- }
- }
-
- //判断是否是人脸检测的定时器到位
- if(event->timerId() == checkId)
- {
- qDebug() << "正在检测...";
-
- //判断是否处于检测
- if(flag == 0)
- {
- QFile file("C:/opencv/resource/myFace.xml");
- if(file.exists()) //表明人脸模型存在的基础上进行识别
- {
- if(faces.empty() || recognizer.empty()) return; //ui界面无矩形框或者没有人脸识别器
-
- //到此表明可以进行检测
- Mat face = src(faces[0]);
-
- //重新设置大小,保持跟保存人脸时一致
- cv::resize(face,face,Size(100,100));
-
- //灰度处理
- cvtColor(face,face,CV_BGR2GRAY);
-
- //均衡化处理
- equalizeHist(face,face);
-
- //定义记录检测后返回的结果的变量
- int lab = -1; //返回的图像的标签
- double conf = 0.0; //返回图像的可信度
-
- //将该人脸进行预测
- recognizer->predict(face,lab,conf);
- qDebug() << "lab = " << lab << " conf = " << conf;
-
- //对人脸识别后的结果进行判断
- if(lab != -1)
- {
- ui->loginBtn->setEnabled(true);
- }
- }
- }
- }
-
- }
-
- //录入人脸按钮对应的槽函数
- void Widget::on_inputFaceBtn_clicked()
- {
- //启动人脸录入的定时器
- qDebug() << "开始进行人脸录入...";
-
- studyId = this->startTimer(60);
-
- //将按钮设置成不可用状态
- ui->inputFaceBtn->setEnabled(false);
- //将flag设置成1,表示正在录入人脸,不要进行人脸检测了
- flag = 1;
-
- count = 0; //清空计数器
-
- }