OpenCV Releases:4.6.0
开发平台:QT 6.4.0
编译环境:MSVC 2019 64bit
主要功能:1、预处理图片 2、生成CSV文件 3、生成识别器文件等功能。主要用于学习opencv的整个流程和实现一些简单的功能,比如识别指定的人脸并显示编号。
源码免费下载地址在文末!
OpenCV相关方法:
opencv_camera.cpp
#include "opencv_camera.h"
#include <QVector>
#include <QImage>
#include <fstream>
#include <QDebug>
opencv_camera::opencv_camera(QObject *parent)
: QObject{parent}
{
}
bool opencv_camera::openCameraDev(int devID)
{
this->camera.open(devID);
if(!this->camera.isOpened()) {
qDebug() << "camera opened fail";
return false;
}
qDebug() << "camera opened success";
return true;
}
void opencv_camera::closeCameraDev(void)
{
this->camera.release();
}
QImage* opencv_camera::getCheckFaceImg(void)
{
return &this->imgCheckFace;
}
QImage opencv_camera::getCameraImage(void)
{
Mat frame;
if(!this->camera.isOpened()) {
qDebug() << "camera is not opened";
return QImage();
}
if(!this->camera.grab())
{
qDebug() << "grab in opencv failed";
return QImage();
}
this->camera >> frame;
return MatToQImage(frame);
}
// Mat转图像
QImage opencv_camera::MatToQImage(const cv::Mat& mat)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if (mat.type() == CV_8UC1)
{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for (int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = mat.data;
for (int row = 0; row < mat.rows; row++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if (mat.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if (mat.type() == CV_8UC4)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
return QImage();
}
}
void opencv_camera::setFaceRecognizer(QString path, int mode)
{
if(mode == 0) myModel = cv::face::EigenFaceRecognizer::create();
else if(mode == 1) myModel = cv::face::FisherFaceRecognizer::create();
else if(mode == 2) myModel = cv::face::LBPHFaceRecognizer::create();
else {
myModel.reset();
return ;
}
myModel->read(path.toStdString());
}
QImage opencv_camera::getCameraImage_face(void)
{
Mat frame, gray;
int ret = 0;
if(!this->camera.isOpened()) {
qDebug() << "camera is not opened";
return QImage();
}
if(!this->camera.grab())
{
qDebug() << "grab in opencv failed";
return QImage();
}
this->camera >> frame;
std::vector<Rect>faces(0); // 存放人脸的向量容器
CascadeClassifier faceCascade; // 分类器
faceCascade.load("haarcascade_frontalface_alt2.xml"); // 加载分类器模型
cvtColor(frame, gray, COLOR_RGB2GRAY); // 灰度化处理
equalizeHist(gray, gray); // 变换后的图像进行直方图均值化处理
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, Size(92, 112)); // 以加载模型为准进行检测
flip(frame, frame, 1); // 水平翻转
for(int i = 0; i < faces.size(); i++) {
Scalar color = Scalar(0, 255, 0); // 所取的颜色
rectangle(frame, Point(frame.cols - faces[i].x - faces[i].width, faces[i].y), Point(frame.cols - faces[i].x, faces[i].y + faces[i].height), color, 1, 8); // 框出检测目标
if(myModel.empty()) continue;
Mat faceROI = gray(faces[i]);
Mat faceROI2;
if(faceROI.cols >= 92 && faceROI.rows >= 112) {
resize(faceROI, faceROI2, Size(92, 112));
}
if(!faceROI2.empty()) {
ret = myModel->predict(faceROI2);
putText(frame, QString("%1").arg(ret).toStdString(), Point(frame.cols - faces[i].x - faces[i].width, faces[i].y - 2), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 255, 0), 1, 8); // 添加文字
// qDebug() << "predict code:" << ret;
}
}
return MatToQImage(frame);
}
// 检测图片内是否有人脸
int opencv_camera::checkPicture_face(QString path)
{
if(path.isNull()) return 65535;
Mat picture, gray;
picture = cv::imread(path.toStdString());
std::vector<Rect>faces(0); // 存放人脸的向量容器
CascadeClassifier faceCascade; // 分类器
faceCascade.load("haarcascade_frontalface_alt2.xml"); // 加载分类器模型
cvtColor(picture, gray, COLOR_RGB2GRAY); // 灰度化处理
equalizeHist(gray, gray); // 变换后的图像进行直方图均值化处理
faceCascade.detectMultiScale(gray, faces); // 以加载模型为准进行检测
// 无人脸
if(faces.size() < 1) {
putText(picture, "No target", Point(0,picture.size().height / 2), FONT_HERSHEY_PLAIN, 1, Scalar(0, 0, 255), 1, 8); // 添加文字
} else {
for(int i = 0; i < faces.size(); i++) {
rectangle(picture, Point(faces[i].x, faces[i].y), Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height), Scalar(0,0,255), 2, 8); // 框处检测目标
}
}
// qDebug() << f0aces[0].x << faces[0].y << faces[0].width << faces[0].height;
// qDebug() << "faces size is:" << faces.size();
this->imgCheckFace = MatToQImage(picture);
return faces.size();
}
// 保存一帧摄像头图片
bool opencv_camera::saveCameraImage(QString path)
{
Mat frame;
if(!this->camera.isOpened()) {
qDebug() << "camera is not opened";
return false;
}
if(!this->camera.grab())
{
qDebug() << "grab in opencv failed";
return false;
}
this->camera >> frame;
imwrite(path.toStdString(), frame);
return true;
}
// 将图片预处理为92*112大小的标准图
bool opencv_camera::resizeStdPicture(QString readPath, QString savePath)
{
if(readPath.isNull() || savePath.isNull()) return false;
Mat picture, gray;
picture = cv::imread(readPath.toStdString());
std::vector<Rect>faces(0); // 存放人脸的向量容器
CascadeClassifier faceCascade; // 分类器
faceCascade.load("haarcascade_frontalface_alt2.xml"); // 加载分类器模型
cvtColor(picture, gray, COLOR_RGB2GRAY); // 灰度化处理
equalizeHist(gray, gray); // 变换后的图像进行直方图均值化处理
faceCascade.detectMultiScale(gray, faces); // 以加载模型为准进行检测
for(int i = 0; i < faces.size(); i++) {
Mat faceROI = gray(faces[i]); // 取出包含人脸的矩阵
Mat faceROI2;
// qDebug() << faceROI.cols << faceROI.rows;
// 尺寸要大于等于标准尺寸
if(faceROI.cols >= 92 && faceROI.rows >= 112) {
resize(faceROI, faceROI2, Size(92, 112));
imwrite(savePath.toStdString(), faceROI2);
}
}
return true;
}
// 获取图片的尺寸
QSize opencv_camera::getPictureSize(QString path)
{
Mat picture;
QSize size;
picture = imread(path.toStdString());
size.setWidth(picture.cols);
size.setHeight(picture.rows);
return size;
}
bool opencv_camera::read_csv(const std::string& filename, std::vector<Mat>& images, std::vector<int>& labels, char separator)
{
std::ifstream file(filename.c_str(), std::ifstream::in);
if (!file) {
qDebug() << "csv file open failure";
return false;
}
std::string line, path, classlabel;
while (getline(file, line)) //从文本文件中读取一行字符,未指定限定符默认限定符为“/n”
{
std::stringstream liness(line);//这里采用stringstream主要作用是做字符串的分割
getline(liness, path, separator);//读入图片文件路径以分好作为限定符
getline(liness, classlabel);//读入图片标签,默认限定符
if (!path.empty() && !classlabel.empty()) //如果读取成功,则将图片和对应标签压入对应容器中
{
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
return true;
}
bool opencv_camera::createRecognizerXMLFile(QString csvPath, QString savePath, QString fileName, int mode)
{
std::vector<Mat> images;
std::vector<int> labels;
// 读取CSV出错则返回
try {
read_csv(csvPath.toStdString(), images, labels);
} catch (cv::Exception& e) {
qWarning() << "create recognizer failure, reason:" << e.msg.c_str();
return false;
}
// 图片数量太少则返回
if(images.size() < 1) {
qWarning() << "create recognizer failure, images num too little";
return false;
}
// 图片尺寸不对则返回
for(int i = 0; i < images.size(); i++) {
if(QSize(images[i].cols, images[i].rows) != QSize(92, 112)) {
qWarning() << "create recognizer failure, images size is not std size";
return false;
}
}
std::string path = savePath.append("%1.xml").arg(fileName).toStdString();
if(mode == 0) {
Ptr<cv::face::EigenFaceRecognizer> model = cv::face::EigenFaceRecognizer::create();
model->train(images, labels);
model->save(path);
} else if(mode == 1) {
Ptr<cv::face::FisherFaceRecognizer> model1 = cv::face::FisherFaceRecognizer::create();
model1->train(images, labels);
model1->save(path);
} else if(mode == 2) {
Ptr<cv::face::LBPHFaceRecognizer> model2 = cv::face::LBPHFaceRecognizer::create();
model2->train(images, labels);
model2->save(path);
}
return true;
}
opencv_camera.h
#ifndef OPENCV_CAMERA_H
#define OPENCV_CAMERA_H
#include <QObject>
#include <QImage>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/objdetect/face.hpp>
#include <opencv2/core.hpp>
#include "components/contrib/include/opencv2/face.hpp"
using namespace cv;
class opencv_camera : public QObject
{
Q_OBJECT
public:
explicit opencv_camera(QObject *parent = nullptr);
bool openCameraDev(int devID);
void closeCameraDev(void);
QImage* getCheckFaceImg(void);
QImage getCameraImage(void);
void setFaceRecognizer(QString path, int mode);
QImage getCameraImage_face(void);
int checkPicture_face(QString path);
bool saveCameraImage(QString path);
bool resizeStdPicture(QString readPath, QString savePath);
QSize getPictureSize(QString path);
bool read_csv(const String& filename, std::vector<Mat>& images, std::vector<int>& labels, char separator = ';');
bool createRecognizerXMLFile(QString csvPath, QString savePath, QString fileName, int mode);
signals:
private:
VideoCapture camera;
QImage imgCheckFace;
Ptr<face::FaceRecognizer> myModel;
QImage MatToQImage(const cv::Mat& mat);
};
#endif // OPENCV_CAMERA_H
页面及功能展示:
1、首页
2、预处理图片
3、生成CSV文件
4、生成识别器模型
5、使用说明
OpenCV上位机软件安装包下载地址:
OpenCV上位机软件源码下载地址:
qt6-windows-opencvTeachTool: qt6+qml+opencv+msgv64开发的opencv人脸识别一站式多功能工具,主要功能有:1、预处理图片 2、生成CSV文件 3、生成识别器文件等功能。主要用于学习opencv的整个流程和实现一些简单的功能。 (gitee.com)