前不久用OpenCV的Haar级联分类器做了一个人脸识别的小demo,为了更直观方便地演示效果,将核心代码放在Qt里面做成一个完整的窗口项目。也是第一次使用Qt开发,遇到一些坑记录在这里。
先看一下我的一些学习的示例方法:
创建一个使用OpenCV和Qt的人脸识别小demo是一个有趣且实用的项目。以下是一个基本的步骤指南,帮助你开始这个项目:
1. 环境准备
安装Qt:从Qt官网下载并安装Qt Creator,这是一个跨平台的C++ IDE,用于开发Qt应用程序。
安装OpenCV:你需要安装OpenCV库。可以从OpenCV官网下载源代码,并按照官方文档编译和安装。也可以使用包管理器(如apt-get或conda)来安装。
配置Qt项目以使用OpenCV:在Qt项目中,你需要配置.pro文件以包含OpenCV的头文件和库。
2. 创建Qt项目
打开Qt Creator并创建一个新的Qt Widgets应用程序。
设计用户界面,包括一个显示视频的窗口和一些控制按钮。
3. 集成OpenCV
在你的Qt项目中包含OpenCV的头文件。
使用OpenCV的VideoCapture类来捕获视频流。
使用OpenCV的人脸检测器(如Haar级联或DNN模块)来检测视频中的人脸。
4. 显示和处理视频
将捕获的视频帧转换为QImage,以便在Qt窗口中显示。
在检测到人脸时,在视频帧上绘制矩形框。
可以添加其他功能,如人脸跟踪、表情识别等。
5. 编译和运行
配置Qt项目以使用OpenCV库。
编译并运行你的应用程序。
6. 优化和调试
优化性能,确保视频流畅。
调试任何可能出现的问题。
大致流程图:
示例代码片段
以下是一个简单的代码片段,展示了如何在Qt中捕获视频并使用OpenCV进行人脸检测:
#include <opencv2/opencv.hpp> #include <opencv2/objdetect/objdetect.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> // ... 其他Qt相关的头文件和代码 ... cv::CascadeClassifier face_cascade; cv::VideoCapture cap; void processFrame(const cv::Mat &frame) { std::vector<cv::Rect> faces; std::matvec faces; cv::Mat frame_gray; cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY); equalizeHist(frame_gray, frame_gray); face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30)); for (size_t i = 0; i < faces.size(); i++) { cv::rectangle(frame, faces[i], cv::Scalar(0, 255, 0), 2); } // 将OpenCV的Mat转换为Qt的QImage以显示 QImage img((const unsigned char*)(frame.data), frame.cols, frame.rows, frame.step, QImage::Format_RGB888); // ... 显示img在Qt窗口中 ... } void startVideoCapture() { cap.open(0); // 打开默认摄像头 if (!cap.isOpened()) { // 处理错误 } face_cascade.load("path_to_haarcascade_frontalface_default.xml"); // 加载人脸检测器 } // 在某个定时器槽函数中调用processFrame void onTimerTimeout() { cv::Mat frame; cap >> frame; if (!frame.empty()) { processFrame(frame); } }
下面我是这样进行的。
首先Qt不用多介绍,一个跨平台的图形用户界面应用程序开发框架,在Qt中调用OpenCV库,首先要将其连接到Qt工程中,在pro文件中加入一些内容。
INCLUDEPATH += /usr/local/include \ /usr/local/include/opencv4 \ /usr/local/include/opencv2 LIBS += /usr/local/lib/libopencv_highgui.so \ /usr/local/lib/libopencv_core.so \ /usr/local/lib/libopencv_imgproc.so \ /usr/local/lib/libopencv_imgcodecs.so \ /usr/local/lib/libopencv_objdetect.so \ /usr/local/lib/libopencv_video.so \ /usr/local/lib/libopencv_videoio.so
主要是将工程中使用到的库文件路径加入其中,这里注意每个人的安装目录不同。
要实现在窗口中显示摄像头采集图像,通过按钮打开摄像头和开启人脸识别功能,退出窗口按钮等。将这些操作定义了几个函数,定义如下:
private: Ui::MainWindow *ui; QTimer *timer; QImage *image; VideoCapture camera; Mat img_cam; Mat img_detect; Mat *frame; bool f_close_camera; private slots: void on_closeButton_clicked(); void openCamera(); void closeCamera(); void readFrame(); QImage MatImageToQt(const Mat &src); void faceDetect(); void openVideoFile();
其中定义了两个Mat矩阵,img_cam用于存放摄像头采集到的图像信息,img_detect用于存放待检测的图像信息。我们先介绍如何在Qt中使用OpenCV进行图像采集并显示在窗口的Label上面。使用OpenCV中用于打开摄像头,视频文件等的类VideoCapture,其使用方法也很简单如下是打开摄像头函数:
void MainWindow::openCamera() { camera.open(0); timer->start(33); f_close_camera = 0; }
每33毫秒刷新一次,结合帧显示函数将视频显示在窗口中:
void MainWindow::readFrame() { camera.read(img_cam); QImage img = MatImageToQt(img_cam); //QImage img = QImage( (const unsigned char*)(img_cam.data), img_cam.cols, img_cam.rows, QImage::Format_RGB888 ); ui->showCamera->setPixmap( QPixmap::fromImage(img) ); }
视频采集到之后就可以进行人脸位置的检测了,使用CascadeClassifier加载训练好XML文件,将人脸左边存放在一个Vector中,绘制矩形框在原图像中。
void MainWindow::faceDetect() { std::vector<Rect> face; //QString xml_name = QFileDialog::getOpenFileName( this, tr("haarcascade_frontalface_default"), ".", tr("Image Files(*.xml)") ); //cout<<"path of xml file is : "<<xml_name.toLatin1().data()<<endl; if (img_cam.empty()) { QMessageBox::warning(NULL, "提醒", "摄像头还没开", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); } CascadeClassifier faceCascade; faceCascade.load("/home/eden/qt_test/proj_1/build-face_detectot-Desktop_Qt_5_14_1_GCC_64bit-Debug/haarcascade_frontalface_default.xml"); if(faceCascade.empty()) cout<<"error 1 : XML file dot load"<<endl; while (true) { camera.read(img_detect); //cv::resize(img_detect, img_detect, Size(450, 450), INTER_LINEAR); //img_detect = img_cam; if (img_detect.empty()) { QMessageBox::warning(NULL, "提醒", "摄像头还没开", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); break; } faceCascade.detectMultiScale(img_detect, face, 1.1, 10); cout<<"br and tl of face is :"<<face.data()->br()<<face.data()->tl()<<face.size()<<endl; for (long unsigned int i = 0; i < face.size(); ++i) { rectangle(img_detect, face[i].tl(), face[i].br(), Scalar(255, 0, 255), 3); string face_num = to_string(i + 1)+" face found"; putText(img_detect , face_num , {face[i].tl().x , face[i].tl().y} , FONT_HERSHEY_PLAIN , 1.5 ,Scalar(0 , 69 , 255) , 2) ; } QImage img = MatImageToQt( img_detect ); ui->showFace->setPixmap( QPixmap::fromImage(img) ); waitKey(1); if(f_close_camera) break; } ui->showFace->clear(); }
窗口样式在ui文件中设计,大致效果如下:
可以考虑到如果没有打开摄像头就按人脸检测按钮,由于检测的图像数据为空,会出现程序异常,这里加了一个信息提示小窗口,提醒打开摄像头,效果如下:
现在打开摄像头试一下识别效果:
个人的帅照挡一下,
解释一下进行前的参考步骤:
在Qt的UI设计文件(通常是.ui文件,由Qt Designer生成)中设计窗口样式时,你可以使用Qt Designer的图形界面来创建和配置窗口的布局、控件和样式。以下是一个大致的步骤和描述,用于创建一个具有基本样式的人脸识别小demo的窗口:
启动Qt Designer:
打开Qt Designer,它通常是Qt安装的一部分。创建新窗口:
在Qt Designer中,选择“Widgets”作为模板,然后点击“创建”来开始一个新的窗口设计。设置窗口属性:
在“对象检查器”(Object Inspector)面板中,你可以设置窗口的标题、大小、图标等属性。添加控件:
从左侧的“控件箱”(Widget Box)中,拖动需要的控件到窗口上。对于人脸识别demo,你可能需要:QLabel:用于显示摄像头预览或识别结果。
QPushButton:用于开始/停止识别,或者加载/保存图片等。
QSlider(可选):用于调整摄像头参数,如亮度、对比度等。
QCheckBox(可选):用于启用/禁用某些功能。
布局管理:
使用布局管理器(如QHBoxLayout、QVBoxLayout、QGridLayout)来组织你的控件,以确保它们在不同屏幕尺寸和分辨率下都能正确显示。设置样式:
在“属性编辑器”(Property Editor)中,你可以为每个控件设置样式属性,如字体、颜色、边框等。
使用Qt样式表(QSS)来为整个窗口或特定控件设置更复杂的样式。你可以在“样式表”(StyleSheet)编辑框中输入QSS代码。
信号与槽:
虽然UI设计文件中不直接编写信号与槽的连接代码,但你可以在Qt Designer中设置控件的信号与槽的关联。这样,当你在Qt Creator中打开UI文件并生成相应的C++代码时,这些关联将被自动转换为代码中的信号与槽连接。保存和导出:
保存你的UI设计文件(.ui),并在Qt Creator中打开它,或者使用uic工具将其转换为C++头文件(.h),以便在你的应用程序中使用。在应用程序中使用:
在你的Qt应用程序中,加载并显示这个UI文件。这通常涉及创建一个继承自QMainWindow或QDialog的类,并在该类中加载UI文件。添加人脸识别逻辑:
在应用程序的逻辑代码中,添加人脸识别功能。这通常涉及调用OpenCV库的相关函数来处理摄像头输入、检测人脸、识别身份等。