当前位置: 首页 > news >正文

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

本文详细讲解了如何利用 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); // 显示检测到的信息
}

相关文章:

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

本文详细讲解了如何利用 Qt 和 OpenCV 实现一个可从视频和图片中检测二维码的软件。代码实现了视频解码、多线程处理和界面更新等功能&#xff0c;是一个典型的跨线程图像处理项目。以下分模块对代码进行解析。 一、项目的整体结构 项目分为以下几部分&#xff1a; 主窗口 (M…...

智慧理财项目测试文档

目录 幕布思维导图链接&#xff1a;https://www.mubu.com/doc/6xk3c7DzgFs学习链接&#xff1a;https://www.bilibili.com/video/BV15J4m147vZ/?spm_id_from333.999.0.0&vd_source078d5d025b9cb472d70d8fda1a7dc5a6智慧理财项目测试文档项目介绍项目基本信息项目业务特性系…...

R | 统一栅格数据的坐标系、分辨率和行列号

各位同学&#xff0c;在做相关性等分析时&#xff0c;经常会遇到各栅格数据间的行列号不统一等问题&#xff0c;下面的代码能直接解决这类麻烦。以某个栅格数据的坐标系、分辨率和行列号为准&#xff0c;统一文件夹内所有栅格并输出到新的文件夹。 代码只需要更改输入输出和ti…...

C++学习——编译的过程

编译的过程——预处理 引言预处理包含头文件宏定义指令条件编译 编译、链接 引言 C程序编译的过程&#xff1a;预处理 -> 编译&#xff08;优化、汇编&#xff09;-> 链接 编译和链接的内容可以查阅这篇文章&#xff08;点击查看&#xff09; 预处理 编译预处理是指&a…...

当你要改文件 但是原来的文件内容又不能丢失的时候,拷贝一份(备注原来的),然后添加后缀:.bak

当你要改文件 但是原来的文件内容又不能丢失的时候&#xff0c;拷贝一份&#xff08;备注原来的&#xff09;&#xff0c;然后添加后缀&#xff1a;.bak &#xff01;&#xff01;&#xff01;文件不要直接删除&#xff0c;若你以后要还原的话会找不到...

MATLAB神经网络(五)——R-CNN视觉检测

5.1 目标分类、检测与分割 在计算机视觉领域&#xff0c;目标分类、检测与分割是常用计数。三者的联系与区分又在哪呢&#xff1f;目标分类是解决图像中的物体是什么的问题&#xff1b;目标检测是解决图像中的物体是什么&#xff0c;在哪里的问题&#xff1b;目标分割时将目标和…...

mock.js:定义、应用场景、安装、配置、使用

前言&#xff1a;什么是mock.js&#xff1f; 作为一个前端程序员&#xff0c;没有mockjs你不感觉很被动吗&#xff1f;你不感觉你的命脉被后端那个男人掌握了吗&#xff1f;所以&#xff0c;我命由我不由天&#xff01;学学mock.js吧&#xff01; mock.js 是一个用于生成随机…...

【GAT】 代码详解 (1) 运行方法【pytorch】可运行版本

GRAPH ATTENTION NETWORKS 代码详解 前言0.引言1. 环境配置2. 代码的运行2.1 报错处理2.2 运行结果展示 3.总结 前言 在前文中&#xff0c;我们已经深入探讨了图卷积神经网络和图注意力网络的理论基础。还没看的同学点这里补习下。接下来&#xff0c;将开启一个新的阶段&#…...

Transformer中的Self-Attention机制如何自然地适应于目标检测任务

Transformer中的Self-Attention机制如何自然地适应于目标检测任务&#xff1a; 特征图的降维与重塑 首先&#xff0c;Backbone&#xff08;如ResNet、VGG等&#xff09;会输出一个特征图&#xff0c;这个特征图通常具有较高的通道数、高度和宽度&#xff08;例如CHW&#xff…...

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款知识共享软件

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

3.9MayBeSomeAssembly

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

i春秋-签到题

练习平台地址 竞赛中心 题目描述 题目内容 点击GUESS后会有辨识细菌的选择题 全部完成后会有弹窗提示 输入nickname后提示获得flag F12检查 元素中没有发现信息 检查后发现flag在控制台中 flag flag{663a5c95-3050-4c3a-bb6e-bc4f2fb6c32e} 注意事项 flag不一定要在元素中找&a…...

TypeScript 中扩展现有模块的用法

declare module 是 TypeScript 中用于扩展现有模块的特性。它允许开发者在已有模块的基础上&#xff0c;添加新的功能&#xff08;比如扩展接口、添加类型声明等&#xff09;。通过 declare module&#xff0c;可以将额外的声明合并到原模块中。以下是用法详解&#xff1a; 用…...

【报错记录】解决Termux中pulseaudio启动报错,报:E: [pulseaudio] main.c: Daemon startup failed.

前言 在尝试使用Termux-X11启动Minecraft过程中&#xff0c;不知道怎么回事原本好好的pulseaudio居然无法启动了&#xff0c;一直在报&#xff1a; E: [pulseaudio] main.c: Daemon startup failed. 重装了好几次也没用解决方案如下。 排除重复启动 如果pulseaudio之前已经…...

Java list

在 Java 中&#xff0c;链表&#xff08;LinkedList&#xff09;是一个非常重要的数据结构&#xff0c;它可以动态地插入和删除元素&#xff0c;因此比数组更灵活。Java 提供了 LinkedList 类&#xff0c;该类实现了 List 接口&#xff0c;并且是基于双向链表实现的&#xff0c…...

MAC借助终端上传jar包到云服务器

前提&#xff1a;保证工程本地已打包完成&#xff1a;图中路径即为项目的target目录下已准备好的jar包 第一步&#xff1a;打开终端&#xff08;先不要连接自己的服务器&#xff09;&#xff0c;输入下面的上传命令&#xff1a; scp /path/to/local/app.jar username192.168.1…...

对原jar包解压后修改原class文件后重新打包为jar

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

YY币支付系统改源码(改良版本)

Nginx &#xff1a;1.20.1&#xff08;版本都可以&#xff09; MySQL&#xff1a;5.6.50&#xff08;兼容该版本其他不知道&#xff09; 简单优化服务器&#xff08;可不安装&#xff0c;看要求&#xff09; PHP安装扩展名称&#xff1a;fileinfo | opcache | imagemagick …...

【Swift】类型标注、类型安全和类型推断

文章目录 类型标注类型安全和类型推断什么是类型安全和类型推断为什么说Swift是一门安全语言类型安全带来的好处 类型标注 当你声明常量或者变量的时候可以加上类型标注&#xff08;type annotation&#xff09;&#xff0c;说明常量或者变量中要存储的值的类型。如果要添加类…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...

简单介绍C++中 string与wstring

在C中&#xff0c;string和wstring是两种用于处理不同字符编码的字符串类型&#xff0c;分别基于char和wchar_t字符类型。以下是它们的详细说明和对比&#xff1a; 1. 基础定义 string 类型&#xff1a;std::string 字符类型&#xff1a;char&#xff08;通常为8位&#xff09…...