Kithara和Halcon (二)

Kithara使用Halcon + QT 进行二维码实时识别


目录

    • Kithara使用Halcon + QT 进行二维码实时识别
      • Halcon 简介以及二维码检测的简要说明
          • Halcon 简介
          • Halcon的二维码检测功能
      • Qt应用框架简介
      • 项目说明
      • 关键代码
      • 抖动测试
          • 测试平台:
          • 测试结果:
      • 开源源码


Halcon 简介以及二维码检测的简要说明

Halcon 简介

Halcon 是一款由德国MVTec Software GmbH开发的机器视觉软件包,它为工业自动化提供了强大的图像分析和处理工具。Halcon 软件广泛应用于质量控制、定位、测量、识别和引导机器人等场景,其核心优势在于高性能的图像处理算法、丰富的功能库以及跨平台的兼容性。

Halcon 提供了基于C++和.NET的API,支持Windows、Linux和macOS操作系统,并且能够集成到各种开发环境中,如Visual Studio、Eclipse等。它不仅适用于PC环境,还支持嵌入式系统,使得Halcon成为工业4.0和物联网(IoT)应用的理想选择。

Halcon的二维码检测功能

二维码检测是Halcon中一个重要的应用领域,尤其在物流、制造业和零售业中,二维码的快速准确读取对于追踪和管理物品至关重要。Halcon提供了专门的工具和算子来高效地检测和解码二维码。

常见的二维码检测流程

  • 创建二维码阅读器模板
    使用create_data_code_2d_model算子初始化一个二维码检测模型。这一步会根据预期的二维码类型和环境条件设定初始参数。

  • 设置二维码阅读器参数
    通过set_data_code_2d_param算子调整二维码检测模型的参数。这些参数可能包括二维码的大小范围、旋转角度、噪声容忍度等,以适应不同的应用场景。

  • 检测和读取二维码
    应用find_data_code_2d算子在输入图像中查找二维码。此算子会返回二维码的位置和方向信息。

  • 解码二维码
    read_data_code_2d算子用于从检测到的二维码中提取编码信息。这一步骤将二维码转换为可读的文本或数据。

  • 结果后处理
    解码后的数据通常需要进一步处理,比如验证、存储或发送给其他系统。

  • 二维码检测的关键点
    图像预处理:在检测之前,可能需要对图像进行预处理,例如去噪、增强对比度或校正图像失真,以提高检测的准确性。
    参数调整:适当的参数设置对于提高二维码检测的速度和可靠性至关重要。这可能需要根据具体的应用场景和环境条件进行实验和优化。
    多二维码识别:在复杂场景中,可能需要同时检测多个二维码。Halcon的算子支持这一需求,能够处理密集或重叠的二维码。

总之,Halcon的二维码检测功能结合了先进的图像处理技术和直观的编程接口,使得用户能够在各种工业环境中实现高精度和高效率的二维码识别。

关于 Halcon在Kithara中使用可以查阅此文章Kithara中使用Halcon (一),更多关于学习Halcon的方法可以去 Halcon官网关于二维码检测的介绍。

Qt应用框架简介

  • Qt 应用框架简介
    Qt 是一个跨平台的C++图形用户界面应用程序开发框架,由挪威公司 Trolltech(现为 The Qt Company)于1991年开发。Qt 不仅支持 Windows、Linux 和 macOS 等桌面操作系统,还支持 Android、iOS 等移动平台,甚至可以用于嵌入式系统开发,如 QNX 和 Linux for Devices。

核心特性

  • 跨平台性:Qt 最显著的特点就是其强大的跨平台能力,允许开发者编写一次代码即可在多个平台上运行,极大地提高了开发效率和降低了维护成本。

  • GUI 构建:Qt 提供了一套丰富的组件库,包括按钮、列表、表格、对话框等,用于构建美观且功能完备的用户界面。此外,Qt Creator 集成开发环境中的设计器工具允许开发者通过拖放方式构建界面。

  • 信号与槽机制:这是 Qt 中一种独特的事件处理机制,用于对象之间的通信。信号(Signal)是在对象中定义的,当特定事件发生时被自动触发;槽(Slot)则是可以响应信号的函数。这种机制简化了事件驱动程序的编写。

  • 国际化与本地化:Qt 支持多语言界面,可以轻松地为应用程序添加多种语言支持,满足全球用户的需求。

  • 网络功能:Qt 内置了对网络编程的支持,包括 HTTP、FTP、TCP/IP、UDP 等协议,使得开发网络应用变得简单。
    数据库集成:Qt 提供了数据库访问模块,支持 SQLite、MySQL、PostgreSQL 等多种数据库,便于开发数据驱动的应用。

  • 多媒体支持:通过 QtMultimedia 模块,开发者可以轻松地在应用中集成音频和视频功能。

  • 性能优化:Qt 提供了多种工具和技术,如 QML 和 OpenGL,用于构建高性能的图形界面和动画效果。

开发工具
Qt Creator:官方提供的集成开发环境,集成了代码编辑器、调试器、项目管理工具和 UI 设计器,大大提高了开发效率。
Qt Designer:一个用于设计和编辑用户界面的工具,支持拖放操作,可以生成 Qt 的 UI 代码。
Qt Assistant:一个帮助文档浏览器,包含了 Qt 的所有 API 文档和教程,是学习 Qt 的重要资源。

社区与支持
Qt 拥有庞大的开发者社区,提供了丰富的资源、示例代码和第三方库。无论是初学者还是经验丰富的开发者,都能在社区中找到所需的支持和解决方案。
总之,Qt 是一个功能全面、易于使用的开发框架,特别适合那些希望快速开发高质量跨平台应用的开发者。无论是桌面应用、移动应用还是嵌入式设备上的应用,Qt 都能提供强大的支持。

项目说明

使用Kithara Windows实时套件和Haclon的组合,可以进行二维码检测,并结合Qt图形化应用框架实时显示检测图像,实现选择不同网口的摄像头并实时调节检测圆的参数,监控测试抖动。

编写流程:

  1. 导入Kithara Windows实时套件和Halcon库。
  2. 使用Qt图形化应用框架创建一个界面,包括一个图像显示区域和解析数据展示。
  3. 初始化Kithara并打开摄像头,开始实时获取图像。
  4. 在任务处理中,将实时获取的图像传递给Halcon任务进行二维码检测。
  5. 根据检测结果,在图像上绘制二维码加检测区域,并通过共享内存将数据回传到应用层将图像实时显示在界面的图像显示区域中以及显示检测结果。
  6. 可以添加抖动检测功能,进行抖动测试。
  7. 结束时,释放资源和关闭摄像头。

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

关键代码


// 创建Halcon对象
HObject CreateImage(const uint type, const Hlong width, const Hlong height, void* data)
{KS_printK("CreateImage");HObject ho_image;switch (type){case KS_CAMERA_PIXEL_MONO_8:{const HImage image("byte", width, height, data);ho_image = image;break;}case KS_CAMERA_PIXEL_RGB_8:{HImage image;image.GenImageInterleaved(data, "rgb", width, height, 0,  "byte", width, height, 0, 0, 8, 0);Rgb1ToGray(image,&ho_image);break;}default:break;}return ho_image;
}// 识别二维码
HTuple QCoderCheck(const HTuple& hv_data_code_handle,const HObject& ho_image, SharedData *krenel_data_ptr)
{HObject ho_symbol_xl_ds;HTuple hv_result_handles;HTuple hv_decoded_data_strings;HTuple hv_row{}, hv_col{};//“二维码”运算符将句柄返回给二维数据代码模型,可用于所有进一步的用途对数据代码的操作。FindDataCode2d(ho_image, &ho_symbol_xl_ds, hv_data_code_handle, HTuple(), HTuple(), &hv_result_handles, &hv_decoded_data_strings);GetContourXld(ho_symbol_xl_ds, &hv_row, &hv_col);if ( hv_row.Length() <= QCODE_XLD_SIZE){for (int i = 0; i < hv_row.Length(); i++){const double xld_row = hv_row.ToDArr()[i];const double xld_col = hv_col.ToDArr()[i];krenel_data_ptr->check_qcode_param.qcode_xld_row[i] = xld_row;krenel_data_ptr->check_qcode_param.qcode_xld_col[i] = xld_col;}}return  hv_decoded_data_strings;
}// 这是实时任务将运行的函数,并对接收到的图像执行 Halcon 操作。只有实时任务才应调用 Halcon 函数。
KSError __stdcall HalconCallback(void * /*pArgs*/, void * /*pContext*/)
{KS_printK("HalconCallback called!\n");// 表示已准备好处理图像。krenel_data_ptr_->ready = 1;// 图形抖动性测试int64 last_diff_time {0};int is_valid_time = 0;  // 时间是否有效 0 无效 1 时间有效int count = 0;  // 计数器int64 jitter_time_sum {0};  // 抖动总时间// 设置halcon编码格式//SetSystem("filename_encoding", "utf8");HTuple hv_data_code_handle;CreateDataCode2dModel("QR Code", HTuple(), HTuple(), &hv_data_code_handle);//SetDataCode2dParam (hv_data_code_handle, "string_encoding", "utf8");// 处理循环,此循环仅在发出中止信号时停止。for (;;){// 等待图像接收或停止的通知。KSError error = KS_waitForEvent(krenel_data_ptr_->image_received_event_handle, KSF_NO_FLAGS, 0);if (error != KS_OK) { KS_printK("KS_waitForEvent failed! \n"); }if (krenel_data_ptr_->abort != 0) { break; }// 计数器count++;// 获取当前时间,用于计算图像处理的抖动时间int64 last_time {0};error = KS_getClock(&last_time, KS_CLOCK_MEASURE_HIGHEST);if (error != KS_OK) { return error; }// 获取接收到的图像数据的缓冲区KSCameraBlock *camera_block;void *image_data;error = KS_recvCameraImage(krenel_data_ptr_->stream_handle, &image_data, &camera_block,KSF_NO_FLAGS);if (error != KS_OK){krenel_data_ptr_->ready = 1;continue;}//如果接收到的块类型不是图像,我们跳过。在任何情况下,如果 KS_recvCameraImage() 成功接收到的缓冲区必须使用 KS_releaseCameraImage() 释放。if (camera_block->blockType != KS_CAMERA_BLOCKTYPE_IMAGE){KS_releaseCameraImage(krenel_data_ptr_->stream_handle, image_data, KSF_NO_FLAGS);break;}// 在构建图形之前,请检查接收到的图像是否具有正确的像素格式。const auto *image_block = reinterpret_cast<KSCameraImage *>(camera_block);// 现在,我们将GigE Vision图像转换为Halcon图像。有几种方法可以实现此目的。// 请参阅 Halcon 文档,了解从指针到像素创建图像的正确函数数据。// 这里我们使用 HImage 类的构造函数之一,这等于调用运算符 gen_image1。// 它将复制像素数据。尽管如此,像素的格式必须得到 Halcon 的支持,// 否则,必须执行转换。// 二维码识别HObject ho_image = CreateImage(image_block->pixelFormat, image_block->width, image_block->height, image_data);HTuple ret = QCoderCheck(hv_data_code_handle, ho_image, krenel_data_ptr_);const char *ret_char = ret.ToString();if (const size_t ret_size = ret.ToString().Length(); ret_size < QCODE_VALUE_SIZE - 1){KSRTL_strncpy(krenel_data_ptr_->check_qcode_param.qcode_value, ret_char, QCODE_VALUE_SIZE);}else{KSRTL_strncpy(krenel_data_ptr_->check_qcode_param.qcode_value, "", QCODE_VALUE_SIZE);}// 填充图像信息到共享内存中krenel_data_ptr_->image_info.image_height = image_block->height;krenel_data_ptr_->image_info.image_width = image_block->width;krenel_data_ptr_->image_info.pixel_format = image_block->pixelFormat;if (image_block->pixelFormat == KS_CAMERA_PIXEL_MONO_8){KS_memCpy(pixel_buffer_, image_data, image_block->width * image_block->height, KSF_NO_FLAGS);}else if (image_block->pixelFormat == KS_CAMERA_PIXEL_BGR_8 || image_block->pixelFormat == KS_CAMERA_PIXEL_RGB_8){KS_memCpy(pixel_buffer_, image_data,  image_block->width * image_block->height * 3, KSF_NO_FLAGS);}// 释放图像数据error = KS_releaseCameraImage(krenel_data_ptr_->stream_handle, image_data, KSF_NO_FLAGS);if (error != KS_OK) { KS_printK("KS_releaseCameraImage failed! \n"); }//  图形处理完成后,减去上次处理完成的时间int64 time {0};error = KS_getClock(&time, KS_CLOCK_MEASURE_HIGHEST);if (error != KS_OK) { return error; }// 检测圆处理时间const int64 diff_time = time - last_time;int64 time_cyc = diff_time;KS_convertClock(&time_cyc, KS_CLOCK_MEASURE_HIGHEST, KS_CLOCK_MACHINE_TIME, KSF_NO_FLAGS);krenel_data_ptr_->jitter_value.time_cyc = time_cyc;if (is_valid_time == 0){last_diff_time = diff_time;is_valid_time = 1;}else{// 处理时间的抖动const int64 jitter_time = diff_time - last_diff_time;int64 single_time = jitter_time;KS_convertClock(&single_time, KS_CLOCK_MEASURE_HIGHEST, KS_CLOCK_MACHINE_TIME, KSF_NO_FLAGS); // 100 ns 为单位last_diff_time = diff_time;jitter_time_sum += single_time;if (krenel_data_ptr_->jitter_value.lat_min > single_time){krenel_data_ptr_->jitter_value.lat_min = single_time;}if (krenel_data_ptr_->jitter_value.lat_max < single_time){krenel_data_ptr_->jitter_value.lat_max = single_time;}krenel_data_ptr_->jitter_value.lat_avg = jitter_time_sum / count;krenel_data_ptr_->jitter_value.cur_val = single_time;}krenel_data_ptr_->ready = 1;}return KS_OK;
}

抖动测试

测试平台:

在这里插入图片描述

测试结果:
  • CPU GPU空载测试
    在这里插入图片描述
    在这里插入图片描述

  • CPU满载运行,GPU空载运行
    在这里插入图片描述

  • CPU满载运行,GPU满载运行
    在这里插入图片描述

  • CPU空载运行,GPU满载运行
    在这里插入图片描述

Kithara Windows实时套件得益于其CPU独占技术,即使在Windows cpu负载较高的情况下,也能够稳定地处理Haclon对图像中二维码的检测任务并输出结果,但是GPU负载对图像处理响应较大,在实际项目中应避免GPU存在过高负载。 这种稳定性确保了在各种工作负载下,检测任务都能保持一致的性能表现。此外,我们还对不同平台对检测任务的影响进行了测试,进一步验证了Kithara Windows实时套件在多种环境中的优越性能。这些测试结果表明,无论平台和负载如何,该套件都能提供可靠、高效的图像处理能力。

在进行相同的检测任务时,我们发现抖动现象存在显著差异,这表明用于性能检测的CPU在图像处理方面具有一定的影响。此外,在测试过程中我们还注意到,不同的算法和图像的复杂度也会对结果产生影响。这些因素综合作用,揭示了在图像处理任务中,硬件和软件的选择对性能的最终表现有着重要的决定性作用。通过深入分析这些变量,我们可以更好地优化检测系统,从而提高整体的处理效率和准确性。

开源源码

测试源码现已开源,项目Demo均是测试代码,请勿用于实际项目!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

vue3+vite纯前端实现自动触发浏览器刷新更新版本内容,并在打包时生成版本号文件

前言 在前端项目中&#xff0c;有时候为了实现自动触发浏览器刷新并更新版本内容&#xff0c;可以采取一系列巧妙的措施。我的项目中是需要在打包时候生成一个version.js文件&#xff0c;用当前打包时间作为版本的唯一标识&#xff0c;然后打包发版 &#xff0c;从实现对版本更…

基于SpringBoot的矩形范围面时空分析-以震中附近历史地震为例

目录 前言 1、分析的必要性 2、分析的紧迫性 一、数据库物理模型及空间分析实现 1、数据库物理模型 2、空间数据库中的空间查询分析 二、Java后台程序开发 1、模型层设计 2、业务层的设计与实现 三、WebGIS功能设计与实现 1、同时展示4幅地图 2、初始化地图 3、展示…

动态创建标签jQuery效果

动态创建标签jQuery效果https://www.bootstrapmb.com/item/14832 使用jQuery来动态创建HTML标签并添加效果是一种常见的方法。以下是一个简单的示例&#xff0c;说明如何使用jQuery来动态创建<div>标签&#xff0c;并给它们添加一些基本的效果。 1. 创建一个新的<di…

go语言day17 通道channel

Golang-100-Days/Day16-20(Go语言基础进阶)/day18_channel通道.md at master rubyhan1314/Golang-100-Days (github.com) go语言day09 通道 协程的死锁-CSDN博客 channel for range 循环通道对象 单向通道 单项通道常用于函数参数&#xff0c;只是用来限定在函数中只能进行通道…

Langchain核心模块与实战[8]:RAG检索增强生成[loader机制、文本切割方法、长文本信息处理技巧]

Langchain核心模块与实战[8]:RAG(Retrieval Augmented Generation,检索增强生成) RAG(Retrieval-Augmented Generation)技术是一种结合检索和生成功能的自然语言处理(NLP)技术。该技术通过从大型外部数据库中检索与输入问题相关的信息,来辅助生成模型回答问题。其核心…

Mysql中(基于GTID方式)实现主从复制,单主复制详细教程

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

《深入探秘Java中的枚举:掌握Enum的魔力》

目录 &#x1f4dd; 枚举枚举的定义枚举的使用1、表示一组固定常量2、实现接口3、枚举与策略模式4、EnumSet5、EnumMap &#x1f4ce; 参考文章 &#x1f600; 准备好了吗&#xff1f;让我们一起步入这座Java神奇的城堡&#xff0c;探寻枚举&#xff08;Enum&#xff09;这个强…

grafana对接zabbix数据展示

目录 1、初始化、安装grafana 2、浏览器访问 3、安装zabbix 4、zabbix数据对接grafana 5、如何导入模板&#xff1f; ① 设置键值 ② 在zabbix web端完成自定义监控项 ③ garafana里添加nginx上面的的三个监控项 6、如何自定义监控项&#xff1f; 以下实验沿用上一篇z…

Python学习笔记44:游戏篇之外星人入侵(五)

前言 上一篇文章中&#xff0c;我们成功的设置好了游戏窗口的背景颜色&#xff0c;并且在窗口底部中间位置将飞船加载出来了。 今天&#xff0c;我们将通过代码让飞船移动。 移动飞船 想要移动飞船&#xff0c;先要明白飞船位置变化的本质是什么。 通过上一篇文章&#xff0…

vue上传Excel文件并直接点击文件列表进行预览

本文主要内容&#xff1a;用elementui的Upload 组件上传Excel文件&#xff0c;上传后的列表采用xlsx插件实现点击预览表格内容效果。 在项目中可能会有这样的需求&#xff0c;有很多种方法实现。但是不想要跳转外部地址&#xff0c;所以用了xlsx插件来解析表格&#xff0c;并展…

使用 vSphere vCenter 管理 ESXi

使用 vSphere vCenter 管理 ESXi 1、新建数据中心 在 vSphere Client 中&#xff0c;左上角图标&#xff0c;进入 “清单”&#xff0c;鼠标右键名称&#xff0c;新建数据中心。 输入数据中心名称&#xff0c;我这里直接使用默认值&#xff0c;点击确定。 2、往数据中心中添加…

Linux epoll 机制——原理图解与源码实现分析

epoll概述 epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。 epoll可以理解为event poll&#xff0c;它是一种事件驱动的I/O模型&#xff0c;可以用来替代传统的select和poll模型…

leetcode-98. 验证二叉搜索树

题目描述 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 1&…

功能性的安全性保障:TOKEN鉴权校验

1. 引言 在软件开发过程中&#xff0c;确保系统的安全性是至关重要的一环。它不仅关乎保护用户数据的完整性和隐私性&#xff0c;也是维护系统稳定运行的基石。我认为&#xff0c;从宏观角度审视&#xff0c;软件开发的安全性保障主要可分为两大类&#xff1a;功能性的安全性保…

Golang | Leetcode Golang题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; func hIndex(citations []int) int {n : len(citations)return n - sort.Search(n, func(x int) bool { return citations[x] > n-x }) }

JDBC操作MySQL数据

一准备、 1、首先在IDEA中导入导入包&#xff1a;mysql-connector-java-8.0.23 2、写初始化语句 &#xff08;1&#xff09;在目录下找到driver类 &#xff08;2&#xff09;在JDBCUtil函数中把驱动器的类路径改掉 ①打开driver类 ②按住类名 Driver用快捷键 CtrlAltshiftC …

AIGC的神秘面纱——利用人工智能生成内容改变我们的生活

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;正在迅速改变我们与数字世界互动的方式。从自动写作到图像生成&#xff0c;AIGC正逐渐走进我们的日常生活。它不仅提高了效率&#xff0c;还为创意和商业活动带来了新的可能性。让我们一起来探索AIGC的世界&…

17.jdk源码阅读之LinkedBlockingQueue

1. 写在前面 LinkedBlockingQueue 是 Java 并发包中的一个重要类&#xff0c;常用于生产者-消费者模式等多线程编程场景。上篇文章我们介绍了ArrayBlockingQueue&#xff0c;并且与LinkedBlockingQueue做了简单的对比&#xff0c;这篇文章我们来详细分析下LinkedBlockingQueue…

从零开始构建你的第一个Python Web应用

在本文中&#xff0c;我们将带领你从零开始构建一个简单的Python Web应用。不需要任何先验知识&#xff0c;我们会一步步地指导你完成设置、框架选择、代码编写到部署的整个过程。无论你是Web开发新手还是希望扩展技能的老手&#xff0c;这篇文章都将为你提供一个实践操作的起点…

Spring-Aop源码解析(二)

书接上文&#xff0c;上文说到&#xff0c;specificInterceptors 不为空则执行createProxy方法创建代理对象&#xff0c;即下图的createProxy方法开始执行&#xff0c;生成代理对象&#xff0c;生成代理对象有两种方式&#xff0c;JDK和CGLIB。 createAopProxy就是决定使用哪…