【v5lite】调用onnx推理

news2024/11/24 16:55:02

  • 前言
  • 一、主线程
  • 二、推理线程
    • thred_nms(非极大值抑制阈值)的作用
    • thred_cond(置信度阈值)的作用
  • 三、串口线程
  • 总览
  • @改善版本
  • 总结


前言

跟着博主导入的加以修改的,反正v5lite的版本要是1.4版本的,不然容易出现错误!
后面再去把博主的博文导进来
树莓派4B运行yolov5lite转onnx模型(实测3-7fps)这个比较浅显易懂,跟着博主搞几乎不会出现错误。

还有的参考,因为个人水平有限,我本人没看懂,但是我认为极具参考价值,一致贴上来!
1、pogg源大佬的知乎文章工程部署(五):这周不鸽!v5Lite树莓派15帧教程
但是我没看懂这里QWQ转换出onnx模型之后,我不知道如何检测模型的好坏
2、基于树莓派4B的YOLOv5-Lite目标检测的移植与部署(含训练教程)


一、主线程

def main():
    # 模型加载
    model_pb_path = "D:\\YOLOv5-Lite-1.4\\runs\\train\\exp1\\weights\\best.onnx"
    so = ort.SessionOptions()
    net = ort.InferenceSession(model_pb_path, so)
    """
    这里首先指定了模型文件的路径(model_pb_path),然后创建了一个ONNX运行时的会话选项(so),
    最后使用模型路径和会话选项来初始化一个推理会话(net),用于后续对模型进行推理操作。
    """

    # 标签字典
    global dic_labels
    dic_labels = {
   0: 'good_apple',
                  1: 'bad_apple',
                  2: 'good_banana',
                  3: 'bad_banana',
                  4: 'good_mango',
                  5: 'bad_mango'}
    """
    定义了一个全局的字典(dic_labels),用于将模型输出的类别索引映射到对应的水果标签,
    方便后续在检测结果中显示有意义的水果名称。
    """

    # 模型参数
    model_h = 320
    model_w = 320
    nl = 3
    na = 3
    stride = [8., 16., 32.]
    anchors = [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]]
    anchor_grid = np.asarray(anchors, dtype=np.float32).reshape(nl, -1, 2)
    """
    这里定义了一系列模型相关的参数:
    - model_h和model_w指定了模型输入图像的高度和宽度。
    - nl表示模型的检测层数。
    - na表示每层的锚框数量。
    - stride是不同检测层的步长信息。
    - anchors是定义的锚框尺寸列表,经过处理后转换为numpy数组并重塑为合适的形状存储在anchor_grid中,
      这些参数在目标检测模型中用于确定检测框的位置和大小等。
    """

    # 初始化队列和线程
    img_queue = queue.Queue()
    result_queue = queue.Queue()
    result_copy_queue = queue.Queue()
    detection_thread = DetectionThread(img_queue, result_queue, net, model_h, model_w, nl, na, stride, anchor_grid, dic_labels)
    detection_thread.start()
    """
    创建了三个队列:
    - img_queue用于存储待检测的图像数据。
    - result_queue用于存储检测线程得到的检测结果。
    - result_copy_queue用于在另一个线程(串口线程)中传递检测结果副本。

    然后创建了一个检测线程(detection_thread),并传入相关参数后启动该线程,
    该线程将从img_queue中获取图像进行检测,并将结果放入result_queue。
    """

    # 串口线程配置
    serial_port = 'COM12'
    baud_rate = 115200
    serial_thread = SerialThread(serial_port, baud_rate, result_copy_queue)
    serial_thread.start()
    """
    配置了串口相关的参数,包括串口号(serial_port)和波特率(baud_rate),
    然后创建了一个串口线程(serial_thread),并传入相关参数后启动该线程,
    该线程将从result_copy_queue中获取检测结果副本进行后续处理(可能是通过串口发送数据等操作)。
    """

    video = 0
    cap = cv2.VideoCapture(video)
    flag_det = False
    """
    设置视频源为默认摄像头(video = 0),然后使用cv2.VideoCapture创建一个视频捕获对象(cap),
    用于读取视频帧。同时初始化了一个标志变量flag_det为False,用于控制是否启动检测功能。
    """

    prev_time = time.time()  # 上一帧的时间戳
    frame_count = 0          # 总帧数
    try:
        while True:
            success, img0 = cap.read()
            if not success:
                break
            curr_time = time.time()
            # 将图像放入队列(即使检测未启动)
            img_queue.put(img0)
            """
            在循环中,不断从视频捕获对象中读取视频帧(img0),如果读取成功,
            将当前帧放入img_queue队列中,无论检测功能是否启动,都先将图像放入队列等待后续处理。
            """

            # 如果检测启动,从结果队列中获取结果并绘制
            if flag_det:
                if not result_queue.empty():
                    det_boxes, scores, ids = result_queue.get()
                    for box, score, id in zip(det_boxes, scores, ids):
                        label = '%s:%.2f' % (dic_labels[id], score)
                        plot_one_box(box.astype(np.int16), img0, color=(255, 0, 0), label=label, line_thickness=None)
                    result_copy_queue.put( (det_boxes, scores, ids))        # 复制线程
            """
            如果检测标志flag_det为True,表示检测功能已启动,当result_queue队列中有检测结果时,
            从队列中取出检测框信息(det_boxes)、得分(scores)和类别索引(ids),
            然后遍历这些结果,根据类别索引从dic_labels字典中获取对应的水果标签,
            并在图像上绘制检测框和标注信息,最后将检测结果副本放入result_copy_queue队列,以便串口线程获取。
            """

            frame_count += 1
            if frame_count > 1:  # 避免除以零错误
                fps = 1. / (curr_time - prev_time)
                str_FPS = "FPS: %.2f" % fps
            else:
                str_FPS = "FPS: N/A"  # 第一帧时显示N/A
            prev_time = curr_time
            cv2.putText(img0, str_FPS, (50, 50), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 3)
            """
            每处理一帧图像,帧数(frame_count)加1,根据当前帧和上一帧的时间戳计算帧率(fps),
            并将帧率信息以文本形式绘制在图像上,方便实时查看处理速度。
            """

            cv2.imshow("FruitSeeSee", img0)
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                break
            elif key == ord('s'):
                flag_det = not flag_det
                if flag_det:
                    print("Detection started.")
                else:
                    print("Detection stopped.")
                    # 清空队列以防有残留数据
                    while not result_queue.empty():
                        result_queue.get()
                    while not img_queue.empty():
                        img_queue.get()
            """
            显示处理后的图像(img0),并等待用户按键操作:
            - 如果按下'q'键,退出循环,结束程序。
            - 如果按下's'键,切换检测功能的启动和停止状态,当启动检测时打印相应提示信息,
              当停止检测时,除了打印提示信息,还会清空result_queue和img_queue队列中的残留数据。
            """

    finally:
        detection_thread.stop()
        detection_thread.join()
        serial_thread.stop()
        serial_thread.join()
        cap.release()
        cv2.destroyAllWindows()
        """
        在程序结束时(无论是否正常结束),执行以下清理操作:
        - 停止并等待检测线程(detection_thread)结束。
        - 停止并等待串口线程(serial_thread)结束。
        - 释放视频捕获对象(cap)占用的资源。
        - 关闭所有打开的cv2窗口。
        """

二、推理线程

识别线程

"""################# 识别线程 ###########################"""
class DetectionThread(threading.Thread):
    def __init__(self, img_queue, result_queue, net, model_h, model_w, nl, na, stride, anchor_grid, dic_labels):
        """
        识别线程类的构造函数,用于初始化线程相关的属性。

        :param img_queue: 存储待检测图像的队列
        :param result_queue: 用于存储检测结果的队列
        :param net: ONNX模型推理会话对象,用于对图像进行推理
        :param model_h: 模型输入图像的高度
        :param model_w: 模型输入图像的宽度
        :param nl: 模型的检测层数
        :param na: 每层的锚框数量
        :param stride: 不同检测层的步长信息
        :param anchor_grid: 处理后的锚框尺寸数组,用于辅助检测
        :param dic_labels: 类别标签字典,将类别索引映射到具体的标签名称
        """
        threading.Thread.__init__(self)
        self.img_queue = img_queue
        self.result_queue = result_queue
        self.net = net
        self.model_h = model_h
        self.model_w = model_w
        self.nl = nl
        self.na = na
        self.stride = stride
        self.anchor_grid = anchor_grid
        self.dic_labels = dic_labels
        self.running = False

    def run(self):
        """
        线程启动后执行的方法,在此方法中实现了图像的检测和结果推送逻辑。

        只要线程处于运行状态(self.running为True),就会不断从图像队列中获取图像进行检测,
        并将检测结果放入结果队列。
        """
        self.running = True
        while self.rrunning:
            if not self.img_queue.empty():
                img0 = self.img_queue.get()
                det_boxes, scores, ids = infer_img(img0, self.net, self.model_h, self.model_w, self.nl, self.na, self.stride, self.anchor_grid)
                self.result_queue.put((det_boxes, scores, ids))
            time.sleep(0.01)  # 防止线程过于繁忙

    def stop(self):
        """
        用于停止线程运行的方法,通过将self.running设置为False,
        使得线程在下次循环检查时退出循环,从而停止线程的执行。
        """
        self.running = False

重头戏
plot_one_box函数:
功能:在给定图像上绘制一个检测框及对应的标签。
实现:首先根据图像大小动态计算绘制检测框的线条粗细(tl),如果未指定颜色则随机生成一个颜色。然后根据传入的检测框坐标信息绘制矩形检测框。若有标签信息,还会计算合适的字体大小并在检测框上方绘制填充矩形作为背景,再将标签文本绘制在上面。
_make_grid函数:
功能:创建一个二维网格坐标数组,用于后续对模型输出坐标的矫正等操作。
实现:通过np.meshgrid函数分别生成在 x 轴和 y 轴方向的坐标数组,然后将它们堆叠并重塑为形状为(-1, 2)的二维数组,每个元素表示一个网格点的坐标(x, y)。
cal_outputs函数:
功能:对模型输出的坐标等信息进行矫正处理,使其符合实际图像的尺寸和坐标体系。
实现:通过遍历模型的检测层数,根据每层的步长、锚框数量等信息,结合之前创建的网格坐标数组,对模型输出的坐标数据进行一系列的计算和调整,最终返回矫正后的模型输出数据。
post_process_opencv函数:
功能:对模型输出进行后处理,包括计算检测框的实际坐标、进行非极大值抑制(NMS)等操作。
实现:首先从模型输出数据中提取出置信度、中心点坐标、宽度和高度等信息,并根据模型输入和原始输入图像的尺寸关系计算出检测框的实际坐标。然后通过cv2.dnn.NMSBoxes函数进行非极大值抑制操作,根据设定的置信度阈值和非极大值抑制阈值筛选出有效的检测框,最后返回经过处理后的检测框坐标、置信度和类别索引信息。
infer_img函数:
功能:对输入图像进行推理计算,包括图像预处理、模型推理、输出坐标矫正、检测框计算等一系列操作,最终得到检测结果。
实现:
图像预处理:将原始输入图像调整到模型输入的尺寸,转换颜色通道为 RGB,并进行归一化处理,最后将其转换为适合模型输入的张量格式(blob)。
模型推理:使用模型推理会话对象net对预处理后的图像张量进行推理,得到模型的原始输出数据。
输出坐标矫正:调用cal_outputs函数对模型原始输出数据进行坐标矫正。
检测框计算:调用post_process_opencv函数对矫正后的输出数据进行检测框计算,得到最终的检测框坐标、置信度和类别索引信息,并返回这些结果。

def plot_one_box(x, img, color=None, label=None, line_thickness=None) :
    tl = (
            line_thickness or round( 0.002 * (img.shape[0] + img.shape[1]) / 2 ) + 1
    )  # line/font thickness
    color = color or [random.randint(0, 255 ) for _ in range( 3 )]
    c1, c2 = (int( x[0] ), int( x[1] )), (int( x[2] ), int( x[3] ))
    cv2.rectangle( img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA )
    if label :
        tf = max( tl - 1, 1 )  # font thickness
        t_size = cv2.getTextSize( label, 0, fontScale=tl / 3, thickness=tf)[0]
        c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
        cv2.rectangle( img, c1, c2, color, -1, cv2.LINE_AA)  # filled
        cv2.putText(
            img,
            label,
            (c1[0], c1[1] - 2),
            0

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

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

相关文章

SpringCloud实用-OpenFeign 调用三方接口

文章目录 前言正文一、项目环境二、项目结构2.1 包的含义2.2 代理的场景 三、完整代码示例3.1 定义FeignClient3.2 定义拦截器3.3 配置类3.4 okhttp配置3.5 响应体3.5.1 天行基础响应3.5.2 热点新闻响应 3.6 代理类3.6.1 代理工厂3.6.2 代理客户端3.6.3 FeignClient的建造器 四…

C++设计模式行为模式———中介者模式

文章目录 一、引言二、中介者模式三、总结 一、引言 中介者模式是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。 中介者模式可以减少对象之间混乱无序的依赖关系&…

HarmonyOS:使用ArkWeb构建页面

一、简介 页面加载是Web组件的基本功能。根据页面加载数据来源可以分为三种常用场景,包括加载网络页面、加载本地页面、加载HTML格式的富文本数据。 页面加载过程中,若涉及网络资源获取,需要配置ohos.permission.INTERNET网络访问权限。 二、…

矩阵的拼接

矩阵的拼接分为横向拼接和纵向拼接 注意:横向拼接要求两矩阵行数相同,纵向拼接要求两矩阵列数相同 h o r z c a t horzcat horzcat和 v e r t c a t vertcat vertcat函数 h o r z c a t ( a , b ) horzcat(a,b) horzcat(a,b)将 a a a和 b b b横向拼接&a…

SpringCloud框架学习(第五部分:SpringCloud Alibaba入门和 nacos)

目录 十二、SpringCloud Alibaba入门简介 1. 基本介绍 2.作用 3.版本选型 十三、 SpringCloud Alibaba Nacos服务注册和配置中心 1.简介 2.各种注册中心比较 3.下载安装 4.Nacos Discovery服务注册中心 (1) 基于 Nacos 的服务提供者 &#xf…

Ollama vs VLLM:大模型推理性能全面测评!

最近在用本地大模型跑实验,一开始选择了ollama,分别部署了Qwen2.5-14B和Qwen2.5-32B,发现最后跑出来的实验效果很差,一开始一直以为prompt的问题,尝试了不同的prompt,最后效果还是一直不好。随后尝试了vllm部署Qwen2.5…

.NET9 - 新功能体验(一)

被微软形容为“迄今为止最高效、最现代、最安全、最智能、性能最高的.NET版本”——.NET 9已经发布有一周了,今天想和大家一起体验一下新功能。 此次.NET 9在性能、安全性和功能等方面进行了大量改进,包含了数千项的修改,今天主要和大家一起体…

LeetCode 144.二叉树的前序遍历

题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 思路:根 左 右 代码: /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNod…

【论文阅读】WGSR

0. 摘要 0.1. 问题提出 1.超分辨率(SR)是一个不适定逆问题,可行解众多。 2.超分辨率(SR)算法在可行解中寻找一个在保真度和感知质量之间取得平衡的“良好”解。 3.现有的方法重建高频细节时会产生伪影和幻觉,模型区分图像细节与伪影仍是难题。 0.2. …

游戏引擎学习第21天

虽然没有上一节的难但是内容也很多 关于实现和使用脚本语言 以下是详细复述: 许多人经常问一个问题,反复问过好几次,那就是:是否会在项目中实现脚本语言。这个问题的具体形式通常是:你们会使用脚本语言吗&#xff1…

NVR接入录像回放平台EasyCVR视频融合平台加油站监控应用场景与实际功能

在现代社会中,加油站作为重要的能源供应点,面临着安全监管与风险管理的双重挑战。为应对这些问题,安防监控平台EasyCVR推出了一套全面的加油站监控方案。该方案结合了智能分析网关V4的先进识别技术和EasyCVR视频监控平台的强大监控功能&#…

springboot vue工资管理系统源码和答辩PPT论文

人类现已迈入二十一世纪,科学技术日新月异,经济、资讯等各方面都有了非常大的进步,尤其是资讯与网络技术的飞速发展,对政治、经济、军事、文化等各方面都有了极大的影响。 利用电脑网络的这些便利,发展一套工资管理系统…

部署实战(二)--修改jar中的文件并重新打包成jar文件

一.jar文件 JAR 文件就是 Java Archive ( Java 档案文件),它是 Java 的一种文档格式JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,多出了一个META-INF/MANIFEST.MF 文件META-INF/MANIFEST.MF 文件在生成 JAR 文件的时候…

RabbitMQ4:work模型

欢迎来到“雪碧聊技术”CSDN博客! 在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将…

SpringMVC——简介及入门

SpringMVC简介 看到SpringMVC这个名字,我们会发现其中包含Spring,那么SpringMVC和Spring之间有怎样的关系呢? SpringMVC隶属于Spring,是Spring技术中的一部分。 那么SpringMVC是用来做什么的呢? 回想web阶段&#x…

鸿蒙开发-文件与分享

文件分类 按所有者: 应用文件:所有者为应用,包括应用安装文件、应用资源文件、应用缓存文件等。 用户文件:所有者是登录到该终端设备的用户,包括用户私有的图片、视频、音频、文档等。 系统文件:与应用和…

内存级文件原理——Linux

目录 进程与文件 Linux下的文件系统 文件操作,及文件流 C语言函数 文件流 文件描述符 系统调用操作 系统调用参数 重定向与文件描述符 输出重定向 输入重定向 文件内容属性 Linux下一切皆文件 进程与文件 当我们对文件进行操作时,文件必…

KubeSphere 最佳实战:K8s 构建高可用、高性能 Redis 集群实战指南

首发:运维有术。 本指南将逐步引导您完成以下关键任务: 安装 Redis:使用 StatefulSet 部署 Redis。自动或手动配置 Redis 集群:使用命令行工具初始化 Redis 集群。Redis 性能测试:使用 Redis 自带的 Benchmark 工具进…

apr共享内存

下载: Download - The Apache Portable Runtime Project 编译: 使用cmake-gui生成库: apr-1.lib aprapp-1.lib libapr-1.lib libaprapp-1.lib libapr-1.dll 在Developer PowerShell for VS 2019中: 执行nmake -f Makefile.win来…

Javaweb前端HTML css 整体布局

最后一个是线条颜色 盒子,整体还是300,400