【v5lite】调用onnx推理

  • 前言
  • 一、主线程
  • 二、推理线程
    • 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

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

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

相关文章

速度革命:esbuild如何改变前端构建游戏 (1)

什么是 esbuild? esbuild 是一款基于 Go 语言开发的 JavaScript 构建打包工具,以其卓越的性能著称。相比传统的构建工具(如 Webpack),esbuild 在打包速度上有着显著的优势,能够将打包速度提升 10 到 100 倍…

Ros Noetic 20.04 跑通mpc_ros包保姆级教程

前言: 本文将简述mpc_ros包在noetic20.04中的安装,mpc是 一种跟踪、MPC_ROS 是一个基于ROS(Robot Operating System)的模型预测控制(Model Predictive Control,MPC)库。该项目旨在为机器人控制提供一个灵活且高效的MPC实现,使得开发者能够在ROS环境中轻松集成和使用MPC…

接上一主题,C++14中如何设计类似于std::any,使集合在C++中与Python一样支持任意数据?

这篇文章的重点是C多态的应用,但是如果你是C新手, 你需要了解以下C知识: 类 构造函数 拷贝构造函数 虚拟函数 纯虚拟函数 析构函数 类的继承 运算符重写 模板类 模板参数 数组 数组的传递 指针与动态内存分配 Python: s …

AndroidStudio与开发板调试时连接失败或APP闪退的解决方案,涉及SELINUX及获取Root权限

现象 用AndroidStudio打开工程代码,点击运行后,报错: 解决方案 具体原因是尝试运行 su(通常用于获取超级用户权限)时失败了,提示 “Permission denied” 通过 CONFIG_SECURITY_SELINUX 变量控制 SElinux 开启或关闭 在vim /rk3568_android_sdk/device/rockchip/rk…

数据结构 (6)栈的应用举例

1. 递归调用 递归函数在执行时,会将每一层的函数调用信息(包括局部变量、参数和返回地址)存储在栈中。当递归函数返回时,这些信息会从栈中弹出,以便恢复之前的执行状态。栈的后进先出(LIFO)特性…

QT 网络编程 数据库模块 TCP UDP QT5.12.3环境 C++实现

一、网络编程 1. 模块引入 QT network 2. 头文件 #include <QTcpServer> //TCP服务端使用 #include <QTcpSocket> //TCP服务器和客户端都使用 3. TCP网络编程流程 1) 服务端 实例化QTcpServer对象----------------------------->socket 进入监听状态…

使用ENSP实现NAT

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为12.12.12.1/30 ip address 12.12.12.1 30进入e0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置…

Python的tkinter如何把日志弄进文本框(Text)

当我们用python的Tkinter包给程序设计界面时&#xff0c;在有些时候&#xff0c;我们是希望程序的日志显示在界面上的&#xff0c;因为用户也需要知道程序目前运行到哪一步了&#xff0c;以及程序当前的运行状态是否良好。python的通过print函数打印出来的日志通常显示在后台&a…

flux的版本

1.flux1-dev.safetensors https://huggingface.co/black-forest-labs/FLUX.1-devhttps://huggingface.co/black-forest-labs/FLUX.1-dev原生的23.8G的模型。原生12B的模型,float16的。需要配合ae.safetensors,flux1-dev.safetensors以及clip-l和T5的权重使用,注意ae.sft和f…

阿里云私服地址

1.解压apache-maven-3.6.1-bin 2.配置本地仓库&#xff1a;修改conf/dettings.xml中的<localReoisitory>为一个指定目录。56行 <localRepository>D:\apache-maven-3.6.1-bin\apache-maven-3.6.1\mvn_repo</localRepository> 3.配置阿里云私服&#xff1a;…

【大数据学习 | Spark-Core】yarn-client与yarn-cluster的区别

1. yarn的提交命令 # yarn的提交命令参数 --master yarn #执行集群 --deploy-mode # 部署模式 --class #指定运行的类 --executor-memory #指定executor的内存 --executor-cores # 指定核数 --num-executors # 直接指定executor的数量 --queue # 指定队列 2. yarn-client模式…

【汽车制动】汽车制动相关控制系统

目录 1.ABS (Anti-lock Brake System&#xff0c;防抱死制动系统) 2.EBD&#xff08;Electronic Brake-force Distribution&#xff0c;电子制动力分配系统&#xff09; 3.TCS&#xff08;Traction Control System&#xff0c;牵引力控制系统&#xff09; 4.VDC&#xff08…

《TCP/IP网络编程》学习笔记 | Chapter 15:套接字与标准 I/O

《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O 《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O标准 I/O 函数标准 I/O 函数的两个优点标准 I/O 函数和系统函数之间的性能对比标准 I/O 函数的几个缺点 使用标准 I/O 函数利用 fd…

<OS 有关> ubuntu 24 不同版本介绍 安装 Vmware tools

原因 想用 apt-get download 存到本地 / NAS上&#xff0c;减少网络流浪。 看到 VMware 上的确实有 ubuntu&#xff0c;只是版本是16。 ubuntu 版本比较&#xff1a;LTS vs RR LTS: Long-Term Support 长周期支持&#xff0c; 一般每 2 年更新&#xff0c;会更可靠与更稳定…

支持多种快充协议和支持多种功能的诱骗取电协议芯片

汇铭达XSP15是一款应用于手持电动工具、智能家居、显示器、音箱等充电方案的大功率快充协议芯片&#xff0c;支持最大功率100W给设备快速充电&#xff0c;大大缩短了充电时间。芯片支持通过UART串口发送电压/电流消息供其它芯片读取。支持自动识别连接的是电脑或是充电器。支持…

【一篇搞定配置】网络分析工具WireShark的安装与入门使用

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;各种软件安装与配置_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1.…

JavaWeb之综合案例

前言 这一节讲一个案例 1. 环境搭建 然后就是把这些数据全部用到sql语句中执行 2.查询所有-后台&前台 我们先写后台代码 2.1 后台 2.2 Dao BrandMapper&#xff1a; 注意因为数据库里面的名称是下划线分割的&#xff0c;我们类里面是驼峰的&#xff0c;所以要映射 …

【STM32】MPU6050初始化常用寄存器说明及示例代码

一、MPU6050常用配置寄存器 1、电源管理寄存器1&#xff08; PWR_MGMT_1 &#xff09; 此寄存器允许用户配置电源模式和时钟源。 DEVICE_RESET &#xff1a;用于控制复位的比特位。设置为1时复位 MPU6050&#xff0c;内部寄存器恢复为默认值&#xff0c;复位结束…

隐私友好型分析平台Plausible Analytics

什么是 Plausible Analytics &#xff1f; Plausible Analytics 是一个简单、轻量级&#xff08;小于1KB&#xff09;、开源且隐私友好的网站分析工具&#xff0c;旨在作为 Google Analytics 的替代品。它不使用 cookies 并且完全符合 GDPR、CCPA 和 PECR 法规&#xff0c;因此…

Flutter:RotationTransition旋转动画

配置vsync&#xff0c;需要实现一下with SingleTickerProviderStateMixinclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{// 定义 AnimationController late AnimationController _controller;overridevoid initState() {super…