Kithara和Halcon (二)

news2024/11/15 4:51:53

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.coloradmin.cn/o/1945991.html

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

相关文章

C++与C中,由函数形参test(int *a)引出的问题

文章参考来源&#xff1a; 1.c函数中形参为引用的情况&#xff1b;C中a和&a的区别 描述&#xff1a; 最近在看循环单链表时&#xff0c;看到有篇文章中&#xff0c;链表初始化函数为图下&#xff0c;我在想&#xff0c;这个函数形参(类似 "int * & a"一样)到…

数据结构(二叉树-1)

文章目录 一、树 1.1 树的概念与结构 1.2 树的相关术语 1.3 树的表示 二、二叉树 2.1 二叉树的概念与结构 2.2特殊的二叉树 满二叉树 完全二叉树 2.3 二叉树的存储结构 三、实现顺序结构二叉树 3.1 堆的概念与结构 3.2 堆的实现 Heap.h Heap.c 默认初始化堆 堆的销毁 堆的插入 …

关于使用宝兰德bes中间件进行windows部署遇到的问题——license不存在

报错信息 日志文件中是这么报错的 遇到的具体情况&#xff1a; 实例按照**的文档手册正常步骤下去节点部署的时候没有报错&#xff0c;成功启动&#xff0c;但是日志里会有报错信息&#xff0c;也是license不存在实例创建的时候失败了&#xff0c;报错信息如下所示 解决方法…

Gitops-Argo-Cli安装与使用

一、安装Argo-Cli工具 Release v2.9.21 argoproj/argo-cd GitHub **选择合适的符合你操作系统以及CPU架构的二进制文件 #依v2.9.21-X86-64-Linux操作系统为例 wget https://github.com/argoproj/argo-cd/releases/download/v2.9.21/argocd-linux-amd64 #添加执行权限并且移…

昇思25天学习打卡营第19天|生成式-DCGAN生成漫画头像

打卡 目录 打卡 GAN基础原理 DCGAN原理 案例说明 数据集操作 数据准备 数据处理和增强 部分训练数据的展示 构造网络 生成器 生成器代码 ​编辑 判别器 判别器代码 模型训练 训练代码 结果展示&#xff08;3 epoch&#xff09; 模型推理 GAN基础原理 原理介…

AV1技术学习:Loop Restoration Filter

环路恢复滤波器&#xff08;restoration filter&#xff09;适用于64 64、128 128 或 256 256 像素块单元&#xff0c;称为 loop restoration units (LRUs)。每个单元可以独立选择是否跳过滤波、使用维纳滤波器&#xff08;Wiener filter&#xff09;或使用自导滤波器&#…

AM62x和rk3568的异同点

AM62x 和 RK3568 是两款不同的处理器&#xff0c;分别来自 Texas Instruments&#xff08;TI&#xff09;和 Rockchip。它们在设计目标、架构、性能和应用领域等方面存在一些异同。以下是这两款处理器的对比&#xff1a; 1. 基本架构 AM62x&#xff1a; 架构&#xff1a;基于…

【云原生】Kubernetes 中的 PV 和 PVC 介绍、原理、用法及实战案例分析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

CRM客户管理系统是什么?如何利用CRM盘活老客户?

人与人之间的差距&#xff0c;不仅在于业务能力的高低&#xff0c;更在于如何高效地管理客户、建立深厚的客户关系。在这个“内卷化”严重的时代&#xff0c;借助工具来管理客户成为必不可少的流程。如果你保持怀疑态度&#xff0c;那我们先来聊聊。 客户管理是什么&#xff1…

HormonyOs之 路由简单跳转

Navigation路由相关的操作都是基于页面栈NavPathStack提供的方法进行&#xff0c;每个Navigation都需要创建并传入一个NavPathStack对象&#xff0c;用于管理页面。主要涉及页面跳转、页面返回、页面替换、页面删除、参数获取、路由拦截等功能。 Entry Component struct Index …

探索 Electron:快捷键与剪切板操作

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

Mysql9安装

目录 一、下载mysql 二、安装 三、配置mysql环境变量 四、mysql初始化和启动 1.以管理员身份运行cmd 2.cd到mysql的安装目录 3.初始化mysql的数据库 4.为Windows系统安装MySQL服务 5.查看一下名为mysql的服务&#xff1a; 6.启动MySQL服务 五、附录 1.系统变量还在&…

grafana对接zabbix数据展示

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

arm环境下构建Flink的Docker镜像

准备工作 资源准备 按需下载 flink&#xff0c;我的是1.17.2版本。官方说1.13版本之后的安装包兼容了arm架构&#xff0c;所以直接下载就行。 如需要cdc组件&#xff0c;提前下载好。 服务器准备 可在某云上购买arm服务器&#xff0c;2c/4g即可&#xff0c;按量付费。 带宽…

2024datawhale电力需求预测挑战赛

电力需求预测挑战赛 比赛链接&#xff1a;https://challenge.xfyun.cn/topic/info?typeelectricity-demand&optionssgy&chdw24_uGS8Gs 学习链接&#xff1a;https://datawhaler.feishu.cn/wiki/CuhBw9vBaiG1nJklIPkcRhqVnmk 一句话介绍赛题任务可以这样理解赛题&am…

【Vue实战教程】之Vuex状态管理详解

Vuex状态管理 1 Vuex简介 1.1 什么是Vuex Vuex是一个专为Vue.js应用程序开发的状态管理工具。它采用了集中式存储管理应用的所有的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 简单来说&#xff0c;Vuex是一个适用于在Vue项目开发时使用的状态管理…

Nginx反向代理概述

正向代理与反向代理概述 正向代理&#xff1a; 定义&#xff1a;正向代理位于客户端和目标服务器之间&#xff0c;客户端的请求首先发送到代理服务器&#xff0c;然后由代理服务器转发到目标服务器&#xff0c;最后将目标服务器的响应返回给客户端。 作用&#xff1a;正向代理…

逻辑回归推导

逻辑回归既可以看作是回归算法&#xff0c;也可以看做是分类算法。通常作为分类算法使用&#xff0c;只可以解决二分类问题。 在上述平面中&#xff0c;每个颜色代表一个类别&#xff0c;即有4个类别 将红色的做为一个类别&#xff0c;其他三个类别都统称为其他类别&#xff0…

javascript 的上下文与作用域

目录 1. 初步了解 上下文&#xff08;context&#xff09;2. 全局上下文(global context)3. 上下文栈 (context stack)4. 作用域链( scope chain)5. 作用域(scope)6. 作用域链增强7. 变量声明7.1 var 声明变量7.2 let 声明变量7.3 const 常量声明 8. 标识符查找总结 带着疑问去…

D3.高精度

1.分类情况 AB、A-B、A*a、A/b A和B指的是超大超长整数&#xff0c;长度<1e6; a的值<10000&#xff1b; 2.大整数的存储 int 变量肯定是存不了这么大的数的&#xff0c;做法是将大整数先存到string字符串&#xff0c;再使用字符串的访问方式&#xff0c;将每一位数存到…