OpenCV人脸识别QT上位机(含源码)

news2024/11/28 21:00:03

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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/550659.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓与串口通信-实践篇

前言 在上一篇文章中我们讲解了关于串口的基础知识&#xff0c;没有看过的同学推荐先看一下&#xff0c;否则你可能会不太理解这篇文章所述的某些内容。 这篇文章我们将讲解安卓端的串口通信实践&#xff0c;即如何使用串口通信实现安卓设备与其他设备例如PLC主板之间数据交互…

【计算机网络复习】第五章 数据链路层 1

数据链路层的作用 两台主机&#xff08;端到端&#xff09;之间的通信是依靠相邻的主机/路由器之间的逐步数据传送来实现 数据链路层实现相邻主机/路由器间的可靠的数据传输 网络层&#xff1a;主机-主机通信 数据链路层&#xff1a;点到点通信 数据链路层的主要功能 u 链路…

3R幸福法

3R幸福法 3R幸福法可以帮助我们《建立和谐亲密关系》 模型介绍 3R幸福法体现的是一个人被关注的完整逻辑&#xff1a; Reson-理由&#xff0c;关注缘起。不会让你想表达的感情看起来显得唐突&#xff0c;不会让对方和自己不好意思。Respond-反应&#xff0c;是关注影响。更多…

ROS 工作空间与功能包的创建(三)

执行命令&#xff1a; mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src/catkin_init_workspace echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc 效果&#xff1a; 输入命令查看添加成功了没有 tail ~/.bashrc 编译工程&#xff1a;执行命令 cd ~…

csdn文章markdown格式下载

前言 网上下载CSDN文章的方式多种多样&#xff0c;有的直接下载为pdf格式&#xff0c;有的利用python/java代码将文章下载为md格式&#xff0c;也有的用JavaScript下载文章&#xff0c;但下载的文章仅限于自己写的&#xff08;会介绍&#xff09;&#xff0c;这里也提供一种简单…

关于接口中的一些常用实例以及比较方法的区别

文章目录 &#x1f490;文章导读&#x1f334;Object 类toString() 获取对象信息equals 对象比较方法hashCode 获得对象的具体位置 &#x1f334;接口使用实例Comparable 接口Comparator 接口 &#x1f490;文章导读 在本篇文章中&#xff0c;详解了什么是Object类&#xff0c;…

MyBatis中三级缓存的理解

文章目录 前言1. 环境搭建1.1 依赖引入1.2 mybatis-config.xml配置配置db.properties在mybatis-config.xml引入db.properties 1.3 实体类1.4 mappermapper接口mapper映射文件 1.5 测试 2.缓存2.1 一级缓存mybatis-config.xml 配置日志开启日志配置日志文件logback.xml测试相同m…

深度学习之搭建LSTM模型预测股价

大家好&#xff0c;我是带我去滑雪&#xff01; 本期利用Google股价数据集&#xff0c;该数据集中GOOG_Stock_Price_Train.csv为训练集&#xff0c;GOOG_Stock_Price_Test.csv为测试集&#xff0c;里面有开盘价、最高股价、最低股价、收盘价、调整后的收盘价、成交量&#xff0…

Flutter项目webview加载没有HTTPS证书的网页在Android和iOS设备上无法显示的解决方案

一、问题描述 Flutter项目使用谷歌官方webview库 webview_flutter&#xff0c;加载自签名证书、证书失效、无证书等HTTPS网页地址时&#xff0c;在Android或pc浏览器中提示证书失效&#xff0c;在iOS设备上为空白页&#xff0c;为了加载自签名证书的网页&#xff0c;需要饶过i…

AVR单片机ATemga328P中断原理的介绍

1、一AVR单片机中断原理的介绍 ATmega328P微控制器具有两个外部中断引脚&#xff0c;分别是INT0和INT1。 外部中断0&#xff08;INT0&#xff09;&#xff1a;它对应的引脚是PD2&#xff08;数字引脚2&#xff09;。INT0可以用于响应外部信号的边沿触发&#xff08;上升沿、下…

【服务器】使用Nodejs搭建HTTP web服务器

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 前言 1.安装Node.js环境 2.创建node.js服务 3. 访问node.js 服务 4.内网穿透 4.1 安装配置cpolar内网穿透 4.2 创建隧道映射本地端口 5.固定公网地址 [TOC] 转载自内网穿透…

Unity Addressables学习笔记(1)---创建远程服务器加载资源

例子1&#xff1a;加载一个图片 1.首先创建一个UI Image&#xff0c;空白图片,资源打包方式选择真是部署的 2.修改远程发布和加载配置 Bulid Path选择RemoteBuildPath Load Path我选择了custom,地址是http://localhost:8080/WebGL/ 遇坑1 :最开始我选择的Build Path 是 Loca…

windows安装mysql 5.7.41

前言 要学mysql&#xff0c;肯定得本地装上一个玩一玩啦&#xff0c;下面一起来安装mysql吧 一、下载 https://downloads.mysql.com/archives/community/ 顺便说一下&#xff0c;下载按钮下方有个md5&#xff0c;可以验证下文件是否被篡改&#xff0c;理论上官网下载的应该问…

初识结构体

目录 结构体的声明 结构体的基础知识 结构体的声明 结构体成员的类型 结构体变量的定义和初始化 定义 初始化 结构体成员的访问 结构体变量访问成员 结构体指针访问指向变量的成员 结构体传参 传地址 传结构体 结论 结构体的声明 结构体的基础知识 数组&#xff…

【ChatGPT】IOS如何下载注册使用ChatGPT的APP(教学)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、…

iptables 防火墙

iptables概述 Linux系统的防火墙&#xff1a;ip信息过滤系统&#xff0c;它实际上由两个组件netfilter和iptables组成。 主要工作在网络层&#xff0c;针对IP数据包。体现在对包内的IP地址、端口、协议等信息的处理上 netfilter / iptables关系&#xff1a; netfilter:属于…

Electron中如何创建模态窗口?

目录 前言一、模态窗口1.Web页面模态框2.Electron中的模态窗口3.区分父子窗口与模态窗口 二、实际案例使用总结 前言 模态框是一种常用的交互元素&#xff0c;无论是在 Web 网站、桌面应用还是移动 APP 中&#xff0c;都有其应用场景。模态框指的是一种弹出窗口&#xff0c;它…

【TES714】JFM7K325T(复旦微FPGA)+HI3531DV200(华为海思)的综合视频处理平台设计原理图及调试经验

板卡概述 TES714是自主研制的一款5路HD-SDI视频采集图像处理平台&#xff0c;该平台采用上海复旦微的高性能Kintex系列FPGA加上华为海思的高性能视频处理器HI3531DV200来实现。 华为海思的HI3531DV200是一款集成了ARM A53四核处理器性能强大的神经网络引擎&#xff0c;支持多种…

【运维知识进阶篇】集群架构-Nginx动静分离详解

我们先前将静态资源放到NFS&#xff0c;动态资源放到MySQL&#xff0c;一是为了提高我们Web服务器性能&#xff0c;减轻它的压力&#xff0c;另一面如果Web宕机了&#xff0c;我们的静态和动态资源还可以访问到。但是之前方式不管是静态还是动态文件&#xff0c;都是走的代码文…

ssl vpn 与 ipsec vpn 区别

VPN 安全协议有两种主要类型&#xff0c;IPsec 和 SSL&#xff0c;了解它们之间的区别对于确保客户的安全至关重要。在本文中&#xff0c;我们将解释IPsec 和 SSL VPN 协议之间的区别&#xff0c;以及如何选择合适的协议来满足客户的需求。了解更多SSL技术最新信息&#xff0c;…