基于Qt/C++/Opencv实现的一个视频中二维码解析软件
本文详细讲解了如何利用 Qt 和 OpenCV 实现一个可从视频和图片中检测二维码的软件。代码实现了视频解码、多线程处理和界面更新等功能,是一个典型的跨线程图像处理项目。以下分模块对代码进行解析。
一、项目的整体结构
项目分为以下几部分:
- 主窗口 (
MainWindow
) :负责界面的加载、初始化和用户交互。 - 工作线程 (
mThread
):处理耗时的图像处理任务(如二维码识别)。 - 二维码检测逻辑:使用 OpenCV 进行二维码检测,支持图片和视频两种数据来源。
- 多线程通信:通过信号与槽机制,在主线程和工作线程之间传递状态与数据。
二、主窗口功能解析
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
,用于处理耗时的二维码检测任务。其主要功能包括:
- 根据功能 ID 分别处理视频或图片。
- 在每帧中调用 OpenCV 的
QRCodeDetector
进行二维码检测。 - 通过信号将处理后的图像和数据传递回主线程。
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
。
五、多线程与信号槽
在本项目中,多线程通过信号与槽实现以下功能:
- 更新主界面状态:线程的运行状态(如启动和停止)通过
RuningState
信号通知主线程。 - 实时更新图像和检测结果:
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); // 显示检测到的信息
}
相关文章:

基于Qt/C++/Opencv实现的一个视频中二维码解析软件
本文详细讲解了如何利用 Qt 和 OpenCV 实现一个可从视频和图片中检测二维码的软件。代码实现了视频解码、多线程处理和界面更新等功能,是一个典型的跨线程图像处理项目。以下分模块对代码进行解析。 一、项目的整体结构 项目分为以下几部分: 主窗口 (M…...
智慧理财项目测试文档
目录 幕布思维导图链接:https://www.mubu.com/doc/6xk3c7DzgFs学习链接:https://www.bilibili.com/video/BV15J4m147vZ/?spm_id_from333.999.0.0&vd_source078d5d025b9cb472d70d8fda1a7dc5a6智慧理财项目测试文档项目介绍项目基本信息项目业务特性系…...

R | 统一栅格数据的坐标系、分辨率和行列号
各位同学,在做相关性等分析时,经常会遇到各栅格数据间的行列号不统一等问题,下面的代码能直接解决这类麻烦。以某个栅格数据的坐标系、分辨率和行列号为准,统一文件夹内所有栅格并输出到新的文件夹。 代码只需要更改输入输出和ti…...
C++学习——编译的过程
编译的过程——预处理 引言预处理包含头文件宏定义指令条件编译 编译、链接 引言 C程序编译的过程:预处理 -> 编译(优化、汇编)-> 链接 编译和链接的内容可以查阅这篇文章(点击查看) 预处理 编译预处理是指&a…...

当你要改文件 但是原来的文件内容又不能丢失的时候,拷贝一份(备注原来的),然后添加后缀:.bak
当你要改文件 但是原来的文件内容又不能丢失的时候,拷贝一份(备注原来的),然后添加后缀:.bak !!!文件不要直接删除,若你以后要还原的话会找不到...

MATLAB神经网络(五)——R-CNN视觉检测
5.1 目标分类、检测与分割 在计算机视觉领域,目标分类、检测与分割是常用计数。三者的联系与区分又在哪呢?目标分类是解决图像中的物体是什么的问题;目标检测是解决图像中的物体是什么,在哪里的问题;目标分割时将目标和…...
mock.js:定义、应用场景、安装、配置、使用
前言:什么是mock.js? 作为一个前端程序员,没有mockjs你不感觉很被动吗?你不感觉你的命脉被后端那个男人掌握了吗?所以,我命由我不由天!学学mock.js吧! mock.js 是一个用于生成随机…...

【GAT】 代码详解 (1) 运行方法【pytorch】可运行版本
GRAPH ATTENTION NETWORKS 代码详解 前言0.引言1. 环境配置2. 代码的运行2.1 报错处理2.2 运行结果展示 3.总结 前言 在前文中,我们已经深入探讨了图卷积神经网络和图注意力网络的理论基础。还没看的同学点这里补习下。接下来,将开启一个新的阶段&#…...
Transformer中的Self-Attention机制如何自然地适应于目标检测任务
Transformer中的Self-Attention机制如何自然地适应于目标检测任务: 特征图的降维与重塑 首先,Backbone(如ResNet、VGG等)会输出一个特征图,这个特征图通常具有较高的通道数、高度和宽度(例如CHWÿ…...
2411rust,1.75.0
原文 Rust团队很高兴地声明推出Rust的新版本1.75.0. 如果你rustup安装了以前版本的Rust,你可如下取1.75.0: $ rustup update stable1.75.0稳定版中的功能 async fn和特征中的返回位置impl Trait. 指针字节偏移API 原始指针(*const T和*mutT)过去主要支持,T为单位的操作.如…...

远程办公新宠:分享8款知识共享软件
远程办公模式下,知识共享软件成为了团队协作和沟通的重要工具。以下是8款备受推崇的知识共享软件: 1、HelpLook AI知识库 简介:HelpLook是一款快速搭建AI知识库的系统,具备强大功能,如快速精准的知识检索、灵活定制的…...

3.9MayBeSomeAssembly
就是先从数组里,乘4得到正确地址 32(&s3),s3是基址,32是偏移量,就是先从数组里取出数到临时寄存器,然后再在临时寄存器上加上变量,最后再把临时寄存器上的变量存到数组里,偏移量࿰…...

i春秋-签到题
练习平台地址 竞赛中心 题目描述 题目内容 点击GUESS后会有辨识细菌的选择题 全部完成后会有弹窗提示 输入nickname后提示获得flag F12检查 元素中没有发现信息 检查后发现flag在控制台中 flag flag{663a5c95-3050-4c3a-bb6e-bc4f2fb6c32e} 注意事项 flag不一定要在元素中找&a…...
TypeScript 中扩展现有模块的用法
declare module 是 TypeScript 中用于扩展现有模块的特性。它允许开发者在已有模块的基础上,添加新的功能(比如扩展接口、添加类型声明等)。通过 declare module,可以将额外的声明合并到原模块中。以下是用法详解: 用…...

【报错记录】解决Termux中pulseaudio启动报错,报:E: [pulseaudio] main.c: Daemon startup failed.
前言 在尝试使用Termux-X11启动Minecraft过程中,不知道怎么回事原本好好的pulseaudio居然无法启动了,一直在报: E: [pulseaudio] main.c: Daemon startup failed. 重装了好几次也没用解决方案如下。 排除重复启动 如果pulseaudio之前已经…...
Java list
在 Java 中,链表(LinkedList)是一个非常重要的数据结构,它可以动态地插入和删除元素,因此比数组更灵活。Java 提供了 LinkedList 类,该类实现了 List 接口,并且是基于双向链表实现的,…...

MAC借助终端上传jar包到云服务器
前提:保证工程本地已打包完成:图中路径即为项目的target目录下已准备好的jar包 第一步:打开终端(先不要连接自己的服务器),输入下面的上传命令: scp /path/to/local/app.jar username192.168.1…...

对原jar包解压后修改原class文件后重新打包为jar
文章目录 背景三种修改方式1.POM中移除原jar中依赖的历史版本2.原jar它不使用pom依赖而是直接放在源码中再编译使用JarEditor 插件对源码进行修改(推荐)使用java-decompiler反编译后修改源码覆盖原class(不好用-不推荐直接跳过)提醒 参考资料-推荐阅读拓…...

YY币支付系统改源码(改良版本)
Nginx :1.20.1(版本都可以) MySQL:5.6.50(兼容该版本其他不知道) 简单优化服务器(可不安装,看要求) PHP安装扩展名称:fileinfo | opcache | imagemagick …...
【Swift】类型标注、类型安全和类型推断
文章目录 类型标注类型安全和类型推断什么是类型安全和类型推断为什么说Swift是一门安全语言类型安全带来的好处 类型标注 当你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。如果要添加类…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...