基于Qt/C++/Opencv实现的一个视频中二维码解析软件

ops/2024/11/23 22:32:59/

本文详细讲解了如何利用 Qt 和 OpenCV 实现一个可从视频和图片中检测二维码的软件。代码实现了视频解码、多线程处理和界面更新等功能,是一个典型的跨线程图像处理项目。以下分模块对代码进行解析。


在这里插入图片描述
在这里插入图片描述

一、项目的整体结构

项目分为以下几部分:

  1. 主窗口 (MainWindow) :负责界面的加载、初始化和用户交互。
  2. 工作线程 (mThread):处理耗时的图像处理任务(如二维码识别)。
  3. 二维码检测逻辑:使用 OpenCV 进行二维码检测,支持图片和视频两种数据来源。
  4. 多线程通信:通过信号与槽机制,在主线程和工作线程之间传递状态与数据。

二、主窗口功能解析

1. 初始化界面和变量

MainWindow 类的构造函数调用了 initializeUI()initializeVariable(),分别完成了界面的样式加载和核心变量的初始化。

void MainWindow::initializeVariable()
{m_tip = nullptr;m_lamp[0] = QImage(":/Img/e.png");m_lamp[1] = QImage(":/Img/i.png");m_lamp[2] = QImage(":/Img/w.png");mthread = new mThread();  // 创建工作线程m_Threadrun = false;// 线程信号与主窗口槽函数的连接connect(mthread, SIGNAL(RuningState(bool)), this, SLOT(onRespondThreadRuningState(bool)));connect(mthread, SIGNAL(errors(QString)), this, SLOT(onRespondThreaderrors(QString)));connect(mthread, SIGNAL(infors(QString)), this, SLOT(onRespondThreadinfors(QString)));connect(mthread, SIGNAL(warings(QString)), this, SLOT(onRespondThreadwarings(QString)));connect(mthread, &mThread::imageProcessed, this, &MainWindow::processImage);
}
2. 启动和停止线程

用户点击按钮后,调用 on_btn_Start_Stop_clicked,判断当前线程状态以启动或停止工作线程。

void MainWindow::on_btn_Start_Stop_clicked()
{m_Threadrun ? mthread->stop() : mthread->start(); // 根据当前状态启动或停止线程
}
3. 文件选择

QFileDialog 被用来让用户选择视频或图像文件,并将这些参数传递到线程处理。

void MainWindow::on_btn_Loadfile_clicked()
{QString fileName = QFileDialog::getOpenFileName(nullptr, tc("选择视频文件"), "", tc("视频文件(*.mp4)"));mthread->setFunId(0); // 设置功能 ID:0 表示处理视频if (!fileName.isEmpty())mthread->setThreadParams(fileName); // 传递参数到线程
}void MainWindow::on_btn_Loadimages_clicked()
{QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, tc("选择图像文件"), "", tc("图片文件(*.jpg *.bmp *.png)"));mthread->setFunId(1); // 设置功能 ID:1 表示处理图片if (!fileNames.isEmpty())mthread->setThreadParams(fileNames);
}

三、工作线程实现

mThread 类继承自 QThread,用于处理耗时的二维码检测任务。其主要功能包括:

  1. 根据功能 ID 分别处理视频或图片
  2. 在每帧中调用 OpenCV 的 QRCodeDetector 进行二维码检测
  3. 通过信号将处理后的图像和数据传递回主线程
1. 核心线程逻辑

线程的运行逻辑集中在 run() 方法中。getFunId() 决定了是处理视频还是图片,分别调用 anayVideo()anayImages()

void mThread::run()
{m_isRun = true;emit RuningState(true); // 通知主线程:线程开始运行emit infors(tc("线程启动"));switch (getFunId()) {case 0:anayVideo(); // 处理视频break;case 1:anayImages(); // 处理图片break;default:break;}emit RuningState(false); // 通知主线程:线程结束运行emit infors(tc("线程退出"));
}
2. 视频处理

anayVideo() 中,使用 OpenCV 的 VideoCapture 解码视频逐帧处理。每一帧调用 delectDecoded() 检测二维码,并通过信号将结果传回主线程。

void mThread::anayVideo()
{cv::VideoCapture cap;if (!cap.open(m_Params.toString().toLocal8Bit().data()) || !cap.isOpened()){emit errors(tc("视频未打开"));m_isRun = false;}else{cv::Mat frame;int frameCount = cap.get(cv::CAP_PROP_FRAME_COUNT);while ((frameCount--) > 0 && m_isRun) // 帧循环{cap >> frame; // 读取一帧if (frame.empty())break;QString msg;delectDecoded(frame, msg); // 检测二维码emit imageProcessed(MatToQImage(frame), msg); // 发射处理信号cv::waitKey(50);}cap.release();}
}
3. 图片处理

图片处理逻辑与视频类似,只是直接从文件路径中读取。

void mThread::anayImages()
{QStringList files = m_Params.toStringList();for (auto file : files){cv::Mat frame = cv::imread(file.toStdString().c_str());if (frame.empty() && !m_isRun)break;QString msg;delectDecoded(frame, msg);emit imageProcessed(MatToQImage(frame), msg); // 发射信号cv::waitKey(1000);}
}

四、二维码检测实现

1. 使用 OpenCV 进行检测

delectDecoded() 方法中,利用 OpenCV 的 QRCodeDetector 类进行二维码检测和解码,并将结果绘制到图像中。

int mThread::delectDecoded(cv::Mat &image, QString &code)
{cv::Mat bbox, rectifiedImage;std::string data = qrDecoder.detectAndDecode(image, bbox, rectifiedImage);if (data.length() > 0){code = QString::fromStdString(data); // 将结果返回std::vector<cv::Point> points;for (int i = 0; i < bbox.cols; i++){points.push_back(cv::Point(static_cast<int>(bbox.at<cv::Point2f>(0, i).x), static_cast<int>(bbox.at<cv::Point2f>(0, i).y)));}for (size_t i = 0; i < points.size(); i++){cv::line(image, points[i], points[(i + 1) % points.size()], cv::Scalar(0, 255, 0), 3); // 绘制绿色边框}int minY = points[0].y;for (const auto &point : points) {minY = std::min(minY, point.y);}cv::putText(image, data, cv::Point(points[0].x, minY - 10), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2); // 显示二维码信息}else{code = tc("未检测到二维码!");}return 0;
}
2. Mat 转 QImage

为了在 Qt 界面中显示 OpenCV 的图像,MatToQImage() 将 OpenCV 的 cv::Mat 转换为 Qt 的 QImage


五、多线程与信号槽

在本项目中,多线程通过信号与槽实现以下功能:

  1. 更新主界面状态:线程的运行状态(如启动和停止)通过 RuningState 信号通知主线程。
  2. 实时更新图像和检测结果imageProcessed 信号传递处理后的图像和二维码信息,更新界面。
connect(mthread, &mThread::imageProcessed, this, &MainWindow::processImage);void MainWindow::processImage(const QImage &image, const QString &msg)
{ui->lab_disp->setPixmap(QPixmap::fromImage(image).scaled(image.width() / 2, image.height() / 2)); // 显示缩放后的图像ui->lab_disData->setText(msg); // 显示检测到的信息
}


http://www.ppmy.cn/ops/135846.html

相关文章

华纳云:多IP服务器在网站SEO中的作用是什么

搜索引擎优化(SEO)已成为网站运营不可或缺的一部分。它不仅能够提升网站在搜索引擎结果页面(SERP)中的排名&#xff0c;还能有效增加网站的曝光度和流量。而多IP服务器作为一种高级的网络技术&#xff0c;在SEO策略中扮演着越来越重要的角色。多IP服务器是指一台物理服务器上配…

Scala案例:全文单词统计

2.txt内容如下 Thank you very much.Well I want to thank you all very much this is great, these are our friends, we have thousands of friends in this incredible movement.This was a movement like no nobodys ever seen before, and frankly this was I believe the…

ZYNQ-7020嵌入式系统学习笔记(1)——使用ARM核配置UART发送Helloworld

本工程实现调用ZYNQ-7000的内部ARM处理器&#xff0c;通过UART给电脑发送字符串。 硬件&#xff1a;正点原子领航者-7020 开发平台&#xff1a;Vivado 2018、 SDK 1 Vivado部分操作 1.1 新建工程 设置工程名&#xff0c;选择芯片型号。 1.2 添加和配置PS IP 点击IP INTEGR…

开源 - Ideal库 - 枚举扩展设计思路及实现难点(三)

今天想和大家分享关于枚举扩展设计思路和在实现过程中遇到的难点。 01、设计思路 设计思路说起来其实也很简单&#xff0c;就是通过枚举相关信息&#xff1a;枚举值、枚举名、枚举描述、枚举项、枚举类型&#xff0c;进行各种转换&#xff0c;通过一个信息获取其他信息。比如通…

fio检测硬盘的读写是都正常

有时候发现访问磁盘上文件很慢,但是不知道到底是不是硬盘的问题,此时可以使用该工具进行检测以方便排查问题 一、下载 https://github.com/axboe/fio/releases 注:(1)官网地址无法下载(https://bsdio.com/fio/、https://brick.kernel.dk/snaps/) 二、安装 1、Windo…

服务器被隔离导致无法登录

现象描述 云服务器可能会因安全违规&#xff08;内容或行为违规&#xff09;或因 DDoS 攻击被封堵隔离&#xff0c;被隔离的云服务器在控制台显示为 “BANNING” 状态。 云服务器被隔离可能由于该台服务器违反了当前法律法规的要求。您可以通过以下方式查看该台服务器是否处于…

Java List 集合

怀旧网个人博客网站地址&#xff1a;怀旧网&#xff0c;博客详情&#xff1a;Java List 集合 List 集合的特点 List 集合的特有方法 因为List是Collection 的子类&#xff0c;所以List也直接继承了所有的Collection 的方法。 List 集合方法代码测试 创建集合对象 因为List也…

【数据结构】【线性表】栈的顺序存储实现(附C语言源码)

顺序栈 栈的顺序存储实现顺序栈的定义顺序栈的初始化进栈出栈读栈顶元素共享栈 栈的顺序存储实现 在之前的内容中我们讲过&#xff0c;栈也是线性表的一种&#xff0c;它和顺序表以及链表的区别不在存储结构上&#xff0c;而是在删除和插入的操作上&#xff0c;栈只允许在其一…