【opencv】示例-barcode.cpp 条形码检测和解码

1ce9180bf8c47adb82523917f999eb40.png

1c74df5541a26c4098cec9e129df0914.png

702d02bf7722514270c75a9636335253.png

#include <iostream> // 引入标准输入输出流库
#include "opencv2/objdetect.hpp" // 引入OpenCV物体检测库
#include "opencv2/imgproc.hpp" // 引入OpenCV图像处理库
#include "opencv2/highgui.hpp" // 引入OpenCV高层GUI库using namespace cv; // 使用OpenCV命名空间
using namespace std; // 使用标准库命名空间// 预定义一些颜色常量供后续使用
static const Scalar greenColor(0, 255, 0); // 绿色
static const Scalar redColor(0, 0, 255); // 红色
static const Scalar yellowColor(0, 255, 255); // 黄色
// 生成随机颜色的函数
static Scalar randColor()
{RNG &rng = theRNG(); // 获取随机数发生器的引用return Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); // 生成随机颜色
}//==============================================================================// TheApp结构体,其中封装了应用程序的主要逻辑
struct TheApp
{Ptr<barcode::BarcodeDetector> bardet; // 指向条码检测器的智能指针//! [output]vector<Point> corners; // 存储检测到的条码的角点vector<string> decode_info; // 存储条码的解码信息vector<string> decode_type; // 存储条码的类型//! [output]bool detectOnly; // 标记是否只进行检测而不解码// 清理函数,用于清除存储结果的vectorvoid cleanup()
{corners.clear();decode_info.clear();decode_type.clear();}// 返回当前模式对应的字符串inline string modeString() const
{return detectOnly ? "<detect>" : "<detectAndDecode>";}// 绘制检测和解码结果的函数void drawResults(Mat &frame) const
{//! [visualize]for (size_t i = 0; i < corners.size(); i += 4) // 遍历所有角点{const size_t idx = i / 4; // 计算当前idx// 判断当前条码是否被成功解码const bool isDecodable = idx < decode_info.size()&& idx < decode_type.size()&& !decode_type[idx].empty();const Scalar lineColor = isDecodable ? greenColor : redColor; // 根据是否解码成功选择颜色// 绘制条码轮廓的矩形vector<Point> contour(corners.begin() + i, corners.begin() + i + 4);const vector< vector<Point> > contours {contour};drawContours(frame, contours, 0, lineColor, 1); // 画轮廓// 绘制轮廓的四个角点for (size_t j = 0; j < 4; j++)circle(frame, contour[j], 2, randColor(), -1);// 如果解码成功,写出解码文本if (isDecodable){ostringstream buf;buf << "[" << decode_type[idx] << "] " << decode_info[idx];putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1);}}//! [visualize]}// 绘制FPS信息的函数void drawFPS(Mat &frame, double fps) const
{ostringstream buf;buf << modeString()<< " (" << corners.size() / 4 << "/" << decode_type.size() << "/" << decode_info.size() << ") "<< cv::format("%.2f", fps) << " FPS "; // 组织FPS显示的文本内容putText(frame, buf.str(), Point(25, 25), FONT_HERSHEY_COMPLEX, 0.8, redColor, 2); // 将FPS信息绘制到帧上}// 调用解码函数的中间处理函数inline void call_decode(Mat &frame)
{cleanup(); // 清理之前的结果if (detectOnly){//! [detect]bardet->detectMulti(frame, corners); // 仅进行检测,不解码//! [detect]}else{//! [detectAndDecode]bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners); // 检测并解码,获取类型信息//! [detectAndDecode]}}// 实时视频流中条码检测的函数int liveBarCodeDetect()
{VideoCapture cap(0); // 创建视频捕获对象,并打开默认摄像头if (!cap.isOpened()) // 如果摄像头没有成功打开{cout << "Cannot open a camera" << endl; // 输出错误信息return 2; // 返回错误码2}Mat frame; // 创建Mat对象用于存储捕获的帧Mat result; // 创建另一个Mat对象用于存放处理结果cap >> frame; // 从摄像头读取一帧到framecout << "Image size: " << frame.size() << endl; // 输出帧的尺寸// 输出提示信息cout << "Press 'd' to switch between <detect> and <detectAndDecode> modes" << endl;cout << "Press 'ESC' to exit" << endl;for (;;) // 无限循环读取帧并处理{cap >> frame; // 捕获一帧if (frame.empty()) // 如果帧为空,说明视频流结束{cout << "End of video stream" << endl; // 输出视频流结束信息break; // 跳出循环}if (frame.channels() == 1)cvtColor(frame, frame, COLOR_GRAY2BGR); // 如果帧是灰度图像,则转换为BGRTickMeter timer; // 创建计时器timer.start(); // 开始计时call_decode(frame); // 调用解码函数处理当前帧timer.stop(); // 停止计时drawResults(frame); // 绘制检测结果drawFPS(frame, timer.getFPS()); // 显示帧率(FPS)imshow("barcode", frame); // 显示带有条码信息的帧const char c = (char)waitKey(1); // 等待1ms,并读取用户按键if (c == 'd') // 如果按下'd'键{detectOnly = !detectOnly; // 切换检测模式cout << "Mode switched to " << modeString() << endl; // 输出当前模式}else if (c == 27) // 如果按下'ESC'键(ASCII码为27){cout << "'ESC' is pressed. Exiting..." << endl; // 输出退出信息break; // 跳出循环终止程序}}return 0; // 正常退出返回0}// 静态图像中条码检测的函数int imageBarCodeDetect(const string &in_file, const string &out_file)
{Mat frame = imread(in_file, IMREAD_COLOR); // 读入图像文件cout << "Image size: " << frame.size() << endl; // 输出图像尺寸cout << "Mode is " << modeString() << endl; // 输出当前模式const int count_experiments = 100; // 设置实验次数TickMeter timer; // 创建计时器for (size_t i = 0; i < count_experiments; i++){timer.start(); // 开始计时call_decode(frame); // 调用解码函数处理图像timer.stop(); // 停止计时}cout << "FPS: " << timer.getFPS() << endl; // 输出平均帧率(FPS)drawResults(frame); // 绘制检测结果if (!out_file.empty()) // 如果输出文件名不为空{cout << "Saving result: " << out_file << endl; // 输出保存文件信息imwrite(out_file, frame); // 将结果图像保存到文件}imshow("barcode", frame); // 显示结果图像cout << "Press any key to exit ..." << endl; // 输出退出提示waitKey(0); // 等待用户按键退出return 0; // 正常退出返回0}
};//==============================================================================int main(int argc, char **argv)
{// 命令行参数定义const string keys = "{h help ? |        | print help messages }""{i in     |        | input image path (also switches to image detection mode) }""{detect   | false  | detect 1D barcode only (skip decoding) }""{o out    |        | path to result file (only for single image decode) }""{sr_prototxt|      | super resolution prototxt path }""{sr_model |        | super resolution model path }";CommandLineParser cmd_parser(argc, argv, keys); // 创建命令行解析对象cmd_parser.about("This program detects the 1D barcodes from camera or images using the OpenCV library."); // 程序介绍if (cmd_parser.has("help")) // 如果用户请求帮助信息{cmd_parser.printMessage(); // 打印帮助信息return 0; // 并退出程序}// 提取命令行指定的参数const string in_file = cmd_parser.get<string>("in");const string out_file = cmd_parser.get<string>("out");const string sr_prototxt = cmd_parser.get<string>("sr_prototxt");const string sr_model = cmd_parser.get<string>("sr_model");if (!cmd_parser.check()) // 检查参数解析是否有误{cmd_parser.printErrors(); // 打印错误信息return -1; // 有误则返回-1}TheApp app; // 创建应用程序实例app.detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect"); // 设置检测模式//! [initialize]try // 尝试初始化条码检测器{app.bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model); // 使用超分辨率模型和配置文件创建条码检测器对象}catch (const std::exception& e) // 如果初始化失败则捕获异常{// 输出错误信息提示用户下载并放置相应文件cout <<"\n---------------------------------------------------------------\n""Failed to initialize super resolution.\n""Please, download 'sr.*' from\n""https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n""and put them into the current directory.\n""Or you can leave sr_prototxt and sr_model unspecified.\n""---------------------------------------------------------------\n";cout << e.what() << endl; // 打印异常信息return -1; // 初始化失败则返回-1}//! [initialize]// 根据命令行参数执行相应的检测函数if (in_file.empty())return app.liveBarCodeDetect(); // 如果未提供输入文件则启动实时摄像头检测elsereturn app.imageBarCodeDetect(in_file, out_file); // 否则进行单帧图像检测
}

bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners);

5e2ece7e4f0977f912342d32acc88289.png

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

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

相关文章

169.乐理基础-调式板块总结、调式判断

如果到这五线谱还没记住还不认识的话去看102.五线谱-高音谱号与103.五线谱-低音谱号这两个里&#xff0c;这里面有五线谱对应的音名&#xff0c;对比着看 如果不认识调号去看112.五线谱的调号&#xff08;一&#xff09;、113.五线谱的调号&#xff08;二&#xff09;、114.快…

如何使用 Midjourney?2024年最新更新

一&#xff1a;基础篇 1&#xff1a;注册 首先&#xff0c;你需要注册一个 Discord 账号&#xff0c;然后加入 Midjourney 的 Discord 服务器。或者去 Midjourney 的官网点击右下角的 Join the Beta&#xff1a; ​ 2&#xff1a;在 Discord 公共服务器里使用 注册并进入到…

JVM基础

初识JAM JVM就是JAVA虚拟机&#xff0c;本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行JAVA字节码文件. 下面是java代码执行过程 JVM的功能 1.解释和运行 对字节码文件中的指令实时的解释成机器码 2.内存管理 自动为对象&#xff0c;方法等分配内存自动的垃圾回…

基于顺序表实现通讯管理系统!(有完整源码!)

​​​​​​​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 文章专栏&#xff1a;C语言实战项目 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01;​​​​​​​ 目录 1、实现思路 ​…

OCm (Radeon Open Compute) 和 CUDA (Compute Unified Device Architecture)

OCm&#xff08;Radeon Open Compute&#xff09;和CUDA&#xff08;Compute Unified Device Architecture&#xff09;是两种旨在利用图形处理单元&#xff08;GPU&#xff09;进行通用计算的技术和框架。 OCm&#xff08;Radeon Open Compute&#xff09;&#xff1a; OCm&…

CentOS 7 下离线安装RabbitMQ教程

CentOS 7 下安装RabbitMQ教程一、做准备&#xff08;VMWare 虚拟机上的 CentOS 7 镜像 上安装的&#xff09; &#xff08;1&#xff09;准备RabbitMQ的安装包&#xff08;rabbitmq-server-3.8.5-1.el7.noarch&#xff09;下载地址mq https://github.com/rabbitmq/rabbitmq-se…

os.listdir()bug总结

今天测试出一个神奇的bug&#xff0c;算是教训吧&#xff0c;找了两天不知道问题在哪&#xff0c;最后才发现问题出现在这 原始文件夹显示 os.listdir()结果乱序 import os base_path "./file/"files os.listdir(base_path)print(files)问题原因 解决办法(排序)

NB-IOT 介绍 1

1 名称介绍 NB-----Narrow Band IOT -----Internet of things NB-IOT---窄带物联网 2 物联网技术发展 以太网&#xff1a;网线 RS232一种串行通信标准&#xff0c;通常采用正负电压来表示逻辑值&#xff0c;如正电压表示逻辑1&#xff0c;负电压表示逻辑0。 RS485一种串行通…

(学习日记)2024.04.06:UCOSIII第三十四节:互斥量函数接口讲解

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

【二分查找】Leetcode 二分查找

题目解析 二分查找在数组有序可以使用&#xff0c;也可以在数组无序的时候使用&#xff08;只要数组中的一些规律适用于二分即可&#xff09; 704. 二分查找 算法讲解 当left > right的时候&#xff0c;我们循环结束&#xff0c;但是当left和right缩成一个点的时候&#x…

大数据分析与内存计算——Spark安装以及Hadoop操作——注意事项

一、Spark安装 1.相关链接 Spark安装和编程实践&#xff08;Spark3.4.0&#xff09;_厦大数据库实验室博客 (xmu.edu.cn) 2.安装Spark&#xff08;Local模式&#xff09; 按照文章中的步骤安装即可 遇到问题&#xff1a;xshell以及xftp不能使用 解决办法&#xff1a; 在…

Node.js------Express

◆ 能够使用 express.static( ) 快速托管静态资源◆ 能够使用 express 路由精简项目结构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念&#xff1a;Express 是基…

AcWing 312. 乌龟棋(每日一题)

原题链接&#xff1a;312. 乌龟棋 - AcWing题库 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行&#xff0c;该行有 N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。 棋盘第 1 格是唯一的起点&#xff0c;第…

LC 222.完全二叉树的节点个数

222. 完全二叉树的节点个数 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中…

解决沁恒ch592单片机在tmos中使用USB总线时,接入USB Hub无法枚举频繁Reset的问题

开发产品时采用了沁恒ch592&#xff0c;做USB开发时遇到了一个奇葩的无法枚举问题。 典型症状 使用USB线直连电脑时没有问题&#xff0c;可以正常使用。 如果接入某些特定方案的USB Hub&#xff08;例如GL3510、GL3520&#xff09;&#xff0c;可能会出现以下2种情况&#xf…

2024年第八届人工智能与虚拟现实国际会议(AIVR 2024)即将召开!

2024年第八届人工智能与虚拟现实国际会议&#xff08;AIVR 2024&#xff09;将2024年7月19-21日在日本福冈举行。人工智能与虚拟现实的发展对推动科技进步、促进经济发展、提升人类生活质量等具有重要意义。AIVR 2024将携手各专家学者&#xff0c;共同挖掘智能与虚拟的无限可能…

【C++初阶】 vector 在OJ中的使用

前言&#xff1a; &#x1f3af;个人博客&#xff1a;Dream_Chaser &#x1f388;博客专栏&#xff1a;C &#x1f4da;本篇内容&#xff1a;只出现一次的数字 和 杨辉三角 OJ 目录 一、只出现一次的数字 题目描述&#xff1a; 二、杨辉三角OJ 题目描述&#xff1a; 一、只…

AI设计优化电机、电路与芯片?

一、AI进行电机本体设计 使用AI进行电机本体设计是一种前沿且具有潜力的方法&#xff0c;通过深度学习、强化学习、遗传算法等AI技术&#xff0c;可以实现电机设计的自动化和优化。具体应用可以包括以下几个方面&#xff1a; 此图片来源于网络 1. **参数优化**&#xff1a; …

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考&#xff1a;docker miniconda python 环境安装与迁移&#xff08;简化版&#xff09;-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…

vscode 连接远程服务器 服务器无法上网 离线配置 .vscode-server

离线配置 vscode 连接远程服务器 .vscode-server 1. .vscode-server下载 使用vscode连接远程服务器时会自动下载配置.vscode-server文件夹&#xff0c;如果远程服务器无法联网&#xff0c;则需要手动下载 1&#xff09;网址&#xff1a;https://update.code.visualstudio.com…