基于zbar的二维码识别和机器人视觉巡线,附源码,使用ROS 2与OpenCV 结合的方式,让机器人识别二维码并执行设定动作

目录

前言

二维码扫描库——Zbar

Zbar库的功能主要包含以下四个部分:

代码实现

运行结果


拉到文末有惊喜

前言

微信登录要扫二维码,手机支付要扫二维码,共享单车也要扫二维码。除了这些在日常生活中已经非常普及的扫码场景之外,二维码在工业生产中也已经普遍应用,比如使用二维码标记物料型号,或者在二维码中保存产品的生产信息,只要通过相机扫一扫,很快就可以看到对应的内容。 

既然二维码可以保存很多信息,那有没有可能和机器人应用结合?当然没有问题,在很多机器人应用场景中也有广泛的二维码识别需求。二维码识别和机器人视觉巡线类似,大家同样可以使用ROS 2与OpenCV 结合的方式,让机器人识别二维码并执行预先在二维码中设定的一些动作。

二维码扫描库——Zbar

Zbar 是一个开源的条形码和二维码扫描库,可以用于快速识别和解码条形码和二维码。安装起来也非常简单,只需要执行以下命令:

$ sudo apt install libzbar-dev

Zbar库的功能主要包含以下四个部分:

1、图像获取与预处理 Zbar 首先需要获取输入图像,可以从相机捕获实时图像,也可以是已保存的静态图像文件。在处理之前,通常需要对图像进行预处理,如灰度化、降噪、边缘检测等操作,以提高后续解码的准确性和效率。

2、符号定位与定位模式 Zbar 使用图像处理技术来定位输入图像中的条形码或二维码符号。对于不同类型的符号(如二维码、一维条形码等),Zbar 会采用不同的定位算法和策略来确定符号的位置和边界。对于二维码,通常会检测其定位模式(Finder Patterns)以及可能的三个定位角。

3、符号解码 一旦符号被正确定位,Zbar 就会进行解码操作。对于一维条形码,这涉及到解析条形的宽度和间距信息,然后映射到特定的编码规则(如 EAN-13、Code 128 等)。对于二维码,Zbar 则会解析图案中的数据矩阵,根据 QR 码或 Data Matrix 码的编码规则提取数据。

4、数据输出与应用集成 Zbar 解码成功后,会输出识别到的数据内容,如文本、网址、数字等。这些数据可以被进一步处理,用于应用程序的功能实现,如自动填充表单、商品信息查询、登录验证等。

代码实现

#include "rclcpp/rclcpp.hpp"#include "sensor_msgs/msg/image.hpp"#include <cv_bridge/cv_bridge.hpp>#include "opencv2/opencv.hpp"#include "opencv2/imgproc.hpp"#include "opencv2/imgcodecs.hpp"#include "opencv2/highgui.hpp"#include "zbar.h"#include <std_msgs/msg/string.hpp>
class QrCodeDetection : public rclcpp::Node{public:  QrCodeDetection() : Node("qr_code_detection")  {    subscription_ = this->create_subscription<sensor_msgs::msg::Image>(      "/camera/image_raw", 10, std::bind(&QrCodeDetection::imageCallback, this, std::placeholders::_1));
    qr_code_pub_ = this->create_publisher<std_msgs::msg::String>("qr_code", 10);    image_pub_ = this->create_publisher<sensor_msgs::msg::Image>("qr_code_image", 10);  }
private:  void imageCallback(const sensor_msgs::msg::Image::SharedPtr msg){    try {      cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);      cv::Mat frame = cv_ptr->image;      cv::Mat gray;      cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
      zbar::ImageScanner scanner;      scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);      zbar::Image zbar_image(frame.cols, frame.rows, "Y800", (uchar *)gray.data, frame.cols * frame.rows);      scanner.scan(zbar_image);
      for (zbar::Image::SymbolIterator symbol = zbar_image.symbol_begin();            symbol != zbar_image.symbol_end(); ++symbol) {        std::string qr_code_data = symbol->get_data();        RCLCPP_INFO(this->get_logger(), "Scanned QR Code: %s", qr_code_data.c_str());
        // 发布二维码数据        auto qr_code_msg = std_msgs::msg::String();        qr_code_msg.data = qr_code_data;        qr_code_pub_->publish(qr_code_msg);
        // 在图像上绘制二维码边界和信息        std::vector<cv::Point> points;        for (int i = 0; i < symbol->get_location_size(); i++) {          points.push_back(cv::Point(symbol->get_location_x(i), symbol->get_location_y(i)));        }        cv::polylines(frame, points, true, cv::Scalar(0, 255, 0), 2);
        cv::Point text_origin = points[0];        text_origin.y -= 10;  // 将文本位置稍微上移        cv::putText(frame, qr_code_data, text_origin, cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 0), 2);      }
      // 发布带有二维码标记的图像      sensor_msgs::msg::Image::SharedPtr out_img = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", frame).toImageMsg();      image_pub_->publish(*out_img);    }    catch (cv_bridge::Exception &e) {      RCLCPP_ERROR(this->get_logger(), "cv_bridge exception: %s", e.what());      return;    }  }
  rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_;  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr qr_code_pub_;  rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr image_pub_;};
int main(int argc, char *argv[]){  rclcpp::init(argc, argv);  rclcpp::spin(std::make_shared<QrCodeDetection>());  rclcpp::shutdown();  return 0;}

重点分析下以上代码的关键内容:

    subscription_ = this->create_subscription<sensor_msgs::msg::Image>(       "/camera/image_raw", 10, std::bind(&QrCodeDetection::imageCallback, this, std::placeholders::_1));

首先通过订阅图像话题的数据捕获到图像,每接收到一次图像消息就执行一次回调函数。正如下面的代码,每接收一次image话题数据就会执行一次imageCallback的代码。​​​​​​​

      // 遍历识别到的QR码      for (zbar::Image::SymbolIterator symbol = zbar_image.symbol_begin();         symbol != zbar_image.symbol_end(); ++symbol) {        const char *qrCode_msg = symbol->get_data().c_str();        RCLCPP_INFO(this->get_logger(), "Scanned QR Code: %s", qrCode_msg);
        auto sign_com_msg = std_msgs::msg::String();        sign_com_msg.data = qrCode_msg;
        // 发布QR码内容        auto qr_code_msg = std_msgs::msg::String();        qr_code_msg.data = qr_code_data;        qr_code_pub_->publish(qr_code_msg);

在收到话题数据进入到回调函数后,进一步实现二维码的定位与解析。先按照要求将输入的图像进行灰度化处理,然后调用了Zbar的二维码定位和scan方法进行和识别,最终就可以将识别出来的结果给发布出来。​​​​​​​

        // 在图像上绘制二维码边界和信息        std::vector<cv::Point> points;        for (int i = 0; i < symbol->get_location_size(); i++) {          points.push_back(cv::Point(symbol->get_location_x(i), symbol->get_location_y(i)));        }        cv::polylines(frame, points, true, cv::Scalar(0, 255, 0), 2);
        cv::Point text_origin = points[0];        text_origin.y -= 10;  // 将文本位置稍微上移        cv::putText(frame, qr_code_data, text_origin, cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 0), 2);      }
      // 发布带有二维码标记的图像      sensor_msgs::msg::Image::SharedPtr out_img = cv_bridge::CvImage(std_msgs::msg::Header(), "bgr8", frame).toImageMsg();      image_pub_->publish(*out_img);

此外还可以将二维码结果和图像信息进行融合,大家可以使用以上OpenCV的接口进行实现。

运行结果

图片

  • 在实际应用中,有时会结合使用这两种方法,如使用自适应步长策略或混合显隐式方法。这样可以在不同的时间区间内根据问题的特性选择最合适的方

    完整资源获取——关注公众号,后台回复IT资源  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源OpenStack

1.查询HCS基于OpenStack哪个版本开发 2.九大核心组件 OpenStack可以对接FC也可以对接KVM主机&#xff1b;&#xff08;OpenStack 对接华为FusionCompute&#xff0c;一个集群对应 openstack 一台计算主机&#xff09;-引申出nova compute 2.1nova nova两个核心组件nova contro…

图的最小生成树算法--普里姆(Prim)算法和克鲁斯克尔(Kruskal)算法

一、图的最小生成树 最小生成树&#xff08;Minimum spanning tree&#xff0c;MST&#xff09;是最小权重生成树&#xff08;Minimum weight spanning tree&#xff09;的简称&#xff0c;是一个连通加权无向图中一棵权值最小的生成树。 在一给定的无向图 G ( V , E ) G …

win11环境下成功安装mamba

文章目录 1. Mamba环境搭建2. triton安装3. causal_conv1d安装3.1 下载causal_conv1d工程文件源码3.2 修改setup.py文件3.3 安装 causal_conv1d 4. Mamba安装4.1 下载mamba工程文件源码4.2 修改setup.py文件4.3 安装 mamba 5. 查看所有成功安装的库6. 测试mamba安装是否成功6.1…

软件质量管理体系,软件评审资料,资质认证资料,安全建设,数据安全及项目管理全套资料(原件参考)

软件项目质量管理体系是指一套系统化的管理方法、流程、工具和文档&#xff0c;旨在确保软件项目从需求分析、设计、开发、测试到部署和维护的整个生命周期中&#xff0c;都能达到预定的质量标准和客户期望。该体系通过明确的角色和责任、标准化的工作流程、有效的质量控制和持…

MySQL(python开发)——(3)表数据的基本操作,增删改查

MySQL&#xff08;python开发)——&#xff08;1&#xff09;数据库概述及其MySQL介绍 MySQL&#xff08;python开发)——&#xff08;2&#xff09;数据库基本操作及数据类型 MySQL—— 表数据基本操作 一、表中插入(insert)数据——增 insert into 表名 values (值1&#…

springboot2.0x 和springboot 1.0 整合redis 使用自定义CacheManager 问题

问题描述&#xff1a; 在我们深入理解springboot2.0x的缓存机制的时候&#xff0c;发现在springboot1.0 和springboot2.0 中默认的序列化都是使用的jdk的 Serializer 实现这个接口&#xff0c;jdk自带的序列化方法&#xff0c;由此我们需要自己去创建自定义的RedisCacheManager…

解决springboot redisTemplate lua execute hash脚本 field有转义符的问题

问题&#xff1a;使用execute&#xff0c;是 result redisTemplate.execute(redisScript,Collections.singletonList(hashKey), // KEYSargs.toArray()); // ARGV会存在field有转义符 发现这个方法是直接调用下图的方法 使用的序列化的方式是 template.getValueSerializer(…

详解23种设计模式——第一部分:概述+创建型模式

目录 1. 概述 2. 创建型模式 2.1 简单&#xff08;静态&#xff09;工厂模式 2.1.1 介绍 2.1.2 实现 2.2 工厂模式 2.3 抽象工厂模式 2.4 单例模式 2.4.1 饿汉模式 2.4.2 懒汉模式 2.4.3 线程安全的懒汉式 2.4.4 DCL单例 - 高性能的懒汉式 2.5 建造者模式 2.6 原…

【进阶OpenCV】 (19)-- Dlib库 --人脸表情识别

文章目录 表情识别一、原理二、代码实现1. 摄像头前预处理2. 计算嘴唇变化3. 绘制嘴唇轮廓4. 显示结果5. 完整代码展示 总结 表情识别 目标&#xff1a;识别人物的喜悦状态。 一、原理 我们在对一张人脸图片进行关键点定位后&#xff0c;得到每个关键点的位置&#xff1a; 比…

go压缩的使用

基础&#xff1a;使用go创建一个zip func base(path string) {// 创建 zip 文件zipFile, err : os.Create("test.zip")if err ! nil {panic(err)}defer zipFile.Close()// 创建一个新的 *Writer 对象zipWriter : zip.NewWriter(zipFile)defer zipWriter.Close()// 创…

【Linux】————动静态库

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;Linux 创作时间 &#xff1a;2024年10月22日 一&#xff0e;库的定义 什么是库&#xff0c;在windows平台和linux平台下都大量存在着库。 本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统载…

渗透实战 JS文件怎么利用

1.前言 关于JS在渗透测试中的关键作用&#xff0c;想必不用过多强调&#xff0c;在互联网上也有许多从JS中找到敏感信息从而拿下关键系统的案例。大部分师傅喜欢使用findsomething之类的浏览器插件&#xff0c;也有使用诸如Unexpected.information以及APIFinder之类的Burp插件…

ES6 Promise的用法

学习链接&#xff1a;ES6 Promise的用法&#xff0c;ES7 async/await异步处理同步化&#xff0c;异步处理进化史_哔哩哔哩_bilibili 一、同步与异步区别 1.JavaScript代码是单线程的程序&#xff0c;即通过一行一行代码顺序执行&#xff0c;即同步概念。 2.若处理一些简短、…

算法魅力-双指针的实战

目录 1.双指针的介绍 1. 左右指针&#xff08;对撞指针&#xff09; 2. 快慢指针 2.题目练习讲解 2.1 移动零 算法思路 代码展示 画图效果效果 2.2 复写零 算法思路 代码展示 2.3 快乐数 算法思路 代码展示 2.4 盛最多水的容器 算法思路 代码展示 结束语 1.双指针的…

宝塔PHP8.1安装fileinfo拓展失败解决办法

在宝塔面板中安装PHP8.1后&#xff0c;安装fileinfo扩展一直安装不上&#xff0c;查看日志有报错&#xff0c;于是手动来安装也报错。 宝塔报错&#xff1a; 手动命令行编译安装同&#xff0c;也有报错 cd /www/server/php/81/src/ext/fileinfo/ make distclean ./configure …

【用74ls194实现1000-0100-0010-0001转换】2022-5-13

试用74194附加门电路设计1011011010序列发生器&#xff0c;并用示波器观察。要求&#xff1a;&#xff08;1&#xff09;写出设计过程&#xff1b;&#xff08;2&#xff09;画出电路图。 2、用multisim软件仿真实现上述序列信号发生器&#xff0c;CP频率为1KHz&#xff0c;用示…

【HarmonyOS】应用实现APP国际化多语言切换

【HarmonyOS】应用实现APP国际化多语言切换 前言 在鸿蒙中应用国际化处理&#xff0c;与Android和IOS基本一致&#xff0c;都是通过JSON配置不同的语言文本内容。在UI展示时&#xff0c;使用JSON配置的字段key进行调用&#xff0c;系统选择对应语言文本内容。 跟随系统多语言…

【scene_manager】与 MoveIt 机器人的规划场景进行交互

scene_manager Scene Manager包是由 Robotnik 创建的 ROS 包&#xff0c;旨在帮助构建和与 MoveIt 机器人的规划场景进行交互。 背景信息 MoveIt 规划场景 是一个用于存储机器人周围世界的表示&#xff08;外部碰撞&#xff09;以及机器人自身状态&#xff08;内部碰撞和当…

rollup.js 插件实现原理与自定义

Rollup.js 是一个JavaScript模块打包器&#xff0c;它主要用于将小块代码编译成大块复杂的库或应用程序。相较于Webpack&#xff0c;Rollup更专注于代码的ES模块转换和优化&#xff0c;特别适合构建库或者那些对代码体积、执行效率有严格要求的应用。Rollup的核心特性之一就是它…

NETSH端口转发

NETSH介绍 netsh是windows系统自带命令行程序&#xff0c;攻击者无需上传第三方工具即可利用netsh程序可进行端口转 发操作&#xff0c;可将内网中其他服务器的端口转发至本地访问运行这个工具需要管理员的权限 实验场景 现在有如下的网络&#xff0c;电脑A是攻击机器&#x…