0
点赞
收藏
分享

微信扫一扫

数组排序——从荷兰国旗问题到快速排序

OpenCV Releases:4.6.0

开发平台:QT 6.4.0

编译环境:MSVC 2019 64bit

主要功能:1、预处理图片 2、生成CSV文件 3、生成识别器文件等功能。主要用于学习opencv的整个流程和实现一些简单的功能,比如识别指定的人脸并显示编号。

源码免费下载地址在文末!

核心方法介绍:

1. 使用directshow组件获取摄像头信息内容。

2. 获取摄像头视频帧并进行人脸识别加框处理。

3. 使用<QQuickImageProvider>实现C++传递图片给QML的Image组件。

4. 提供抓拍功能,并可以将原图片处理为可供opencv生成识别器模型使用的标准图。

5. 依据文件目录结构,生成CSV文件(文件路径+标签),供生成识别器模型使用。

6. 移植opencv的contrib文件夹,提供三种识别器模型生成方式(Eigen,Fisher,LBPH)。

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上位机软件安装包下载地址:

https://download.csdn.net/download/m0_50669075/87804667

OpenCV上位机软件源码下载地址:

qt6-windows-opencvTeachTool: qt6+qml+opencv+msgv64开发的opencv人脸识别一站式多功能工具,主要功能有:1、预处理图片 2、生成CSV文件 3、生成识别器文件等功能。主要用于学习opencv的整个流程和实现一些简单的功能。 (gitee.com)

举报

相关推荐

0 条评论