【YOLO】目标识别模型的导出和opencv部署

news2024/12/23 10:22:22

文章目录

  • 0 前期教程
  • 1 什么是模型部署
  • 2 怎么部署

0 前期教程

  • 【YOLO】朴实无华的yolov5环境配置

  • 【YOLO】yolov5训练自己的数据集

1 什么是模型部署

  前期教程当中,介绍了yolov5环境的搭建以及如何利用yolov5进行模型训练和测试,虽然能够实现图片或视频的目标识别,但都是基于pytorch这个深度学习框架来实现的。仅仅是为了使用训练好的模型,就需要附加一个巨大的框架,这样程序会显得很臃肿,不够优雅。因此,摆脱对深度学习框架的依赖,是非常有必要的。此即深度学习模型的部署。

2 怎么部署

  这里使用的是opencv的dnn模块,可以实现读取并使用深度学习模型。但是,这个模块不支持pytorch模型,即训练好的pt格式的文件,因此,使用该模型时,还需要先将pt文件转换为opencv能够读取的模型格式,即onnx。

  模型格式的转换使用的是yolov5自带的export.py文件,它提供了多种常见深度学习框架对应的文件格式。老规矩,使用前先看文件开头的注释:

在这里插入图片描述

我们需要的是onnx格式,因此在运行前先安装onnx:

pip install onnx

然后运行export.py文件:

python export.py --weights 'C:\Users\Zeoy\Desktop\Code\Python\yolov5-master\runs\train\exp19\weights\best.pt' --include onnx

生成的onnx文件也在原best.pt所在文件夹下。

  转换完毕,接下来就是使用,运行如下所示代码:

import cv2
import numpy as np

class Onnx_clf:
    def __init__(self, onnx:str='best.onnx', img_size=640, classlist:list=['bottle']) -> None:
        '''	@func: 读取onnx模型,并进行目标识别
            @para	onnx:模型路径
                 	img_size:输出图片大小,和模型直接相关
                    classlist:类别列表
            @return: None
        '''
        self.net = cv2.dnn.readNet(onnx) # 读取模型
        self.img_size = img_size # 输出图片尺寸大小
        self.classlist = classlist # 读取类别列表

    def img_identify(self, img, ifshow=True) -> np.ndarray:
        '''	@func: 图片识别
            @para	img: 图片路径或者图片数组
                    ifshow: 是否显示图片
            @return: 图片数组
        '''
        if type(img) == str: src = cv2.imread(img)
        else: src = img
        height, width, _ = src.shape #注意输出的尺寸是先高后宽
        _max = max(width, height)
        resized = np.zeros((_max, _max, 3), np.uint8)
        resized[0:height, 0:width] = src  # 将图片转换成正方形,防止后续图片预处理(缩放)失真
        # 图像预处理函数,缩放裁剪,交换通道  img     scale              out_size              swapRB
        blob = cv2.dnn.blobFromImage(resized, 1/255.0, (self.img_size, self.img_size), swapRB=True)
        prop = _max // self.img_size  # 计算缩放比例
        self.net.setInput(blob) # 将图片输入到模型
        out = self.net.forward() # 模型输出
        # print(out.shape)
        out = np.array(out[0])
        out = out[out[:, 4] >= 0.5]  # 利用numpy的花式索引,速度更快
        boxes = out[:, :4]
        confidences = out[:, 4]
        class_ids = np.argmax(out[:, 5:], axis=1)
        class_scores = np.max(out[:, 5:], axis=1)
        # out2 = out[0][out[0][:][4] > 0.5]
        # for i in out[0]: # 遍历每一个框
        #     class_max_score = max(i[5:])
        #     if i[4] < 0.5 or class_max_score < 0.25: # 过滤置信度低的目标
        #         continue
        #     boxes.append(i[:4]) # 获取目标框: x,y,w,h (x,y为中心点坐标)
        #     confidences.append(i[4]) # 获取置信度
        #     class_ids.append(np.argmax(i[5:])) # 获取类别id
        #     class_scores.append(class_max_score) # 获取类别置信度
        indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.25, 0.45) # 非极大值抑制, 获取的是索引
        for i in indexes:   # 遍历每一个目标, 绘制目标框
            box = boxes[i]
            class_id = class_ids[i]
            score = round(class_scores[i], 2)
            x1 = int((box[0] - 0.5*box[2])*prop)
            y1 = int((box[1] - 0.5*box[3])*prop)
            x2 = int((box[0] + 0.5*box[2])*prop)
            y2 = int((box[1] + 0.5*box[3])*prop)
            self.drawtext(src,(x1, y1), (x2, y2), self.classlist[class_id]+' '+str(score))
        if ifshow:
            dst = cv2.resize(src, (width//prop, height//prop))
            cv2.imshow('result', dst)
            cv2.waitKey(0)
        return src

    def video_identify(self, video_path:str) -> None:
        '''	@func: 视频识别
            @para  video_path: 视频路径
            @return: None
        '''
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)
        # print(fps)
        while cap.isOpened():
            ret, frame = cap.read()
            #键盘输入空格暂停,输入q退出
            key = cv2.waitKey(1) & 0xff
            if key == ord(" "): cv2.waitKey(0)
            if key == ord("q"): break
            if not ret: break
            img = self.img_identify(frame, False)
            cv2.imshow('result', img)
            # cv2.imshow('result', frame)
            if cv2.waitKey(int(10/fps)) == ord('q'):
                break
        cap.release()
        cv2.destroyAllWindows()

    @staticmethod
    def drawtext(image, pt1, pt2, text):
        '''	@func: 根据给出的坐标和文本,在图片上进行绘制
            @para	image: 图片数组; pt1: 左上角坐标; pt2: 右下角坐标; text: 矩形框上显示的文本,即类别信息
            @return: None
        '''
        fontFace = cv2.FONT_HERSHEY_COMPLEX_SMALL  # 字体
        # fontFace = cv2.FONT_HERSHEY_COMPLEX  # 字体
        fontScale = 1.5  # 字体大小
        line_thickness = 3  # 线条粗细
        font_thickness = 2  # 文字笔画粗细
        line_back_color = (0, 0, 255)  # 线条和文字背景颜色:红色
        font_color = (255, 255, 255)  # 文字颜色:白色

        # 绘制矩形框
        cv2.rectangle(image, pt1, pt2, color=line_back_color, thickness=line_thickness)
        # 计算文本的宽高: retval:文本的宽高; baseLine:基线与最低点之间的距离(本例未使用)
        retval, baseLine = cv2.getTextSize(text,fontFace=fontFace,fontScale=fontScale, thickness=font_thickness)
        # 计算覆盖文本的矩形框坐标
        topleft = (pt1[0], pt1[1] - retval[1]) # 基线与目标框上边缘重合(不考虑基线以下的部分)
        bottomright = (topleft[0] + retval[0], topleft[1] + retval[1])
        cv2.rectangle(image, topleft, bottomright, thickness=-1, color=line_back_color) # 绘制矩形框(填充)
        # 绘制文本
        cv2.putText(image, text, pt1, fontScale=fontScale,fontFace=fontFace, color=font_color, thickness=font_thickness)

if __name__ == '__main__':
    clf = Onnx_clf()
    import tkinter as tk
    from tkinter.filedialog import askopenfilename
    root = tk.Tk()
    root.withdraw() # 隐藏主窗口
    source = askopenfilename(title="打开保存的图片或视频")
    if source.endswith('.jpg') or source.endswith('.png') or source.endswith('.bmp'):
        clf.img_identify(source)
    elif source.endswith('.mp4') or source.endswith('.avi'):
        print('视频识别中...按q退出')
        clf.video_identify(source)
    else:
        print('不支持的文件格式')

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

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

相关文章

语法篇·JSP基础

一、初识JSP 1.1简介 JSP(Java Server Pages),其根本是一个简化的Servlet设计&#xff0c;它实现了在Java中使用HTML标签。JSP是一种动态网页技术标准&#xff0c;也是JavaEE的标准。JSP和Servlet一样&#xff0c;是在服务器端执行的。JSP是在Servlet技术发展之后为了让开发者…

苹果公司开发者账号申请流程

目录 一、注册 Apple ID 账号二、Apple Developer 登录三、申请公司邓白氏编码四、下载 Apple Developer app五、审核六、缴费七、发票 一、注册 Apple ID 账号 注册网址&#xff1a;https://appleid.apple.com/account 二、Apple Developer 登录 登录网址&#xff1a;http…

汽车EBSE测试流程分析(二):关于优势和挑战的案例分析

EBSE专题连载共分为“五个”篇章。此文为该连载系列的“第二”篇章&#xff0c;在之前的“篇章&#xff08;一&#xff09;”中已经阐述了汽车软件工程的特点&#xff0c;以及使用混合方法设计的分阶段EBSE测试过程&#xff0c;并提出问题。接下来&#xff0c;我们将具体分析EB…

抖音矩阵系统源码开发指南

抖音矩阵系统是一个大规模的分布式系统&#xff0c;它可以处理数百万级别的并发请求。要开发和部署抖音矩阵系统源代码 您需要遵循以下步骤&#xff1a; 下载和安装必要的软件依赖项&#xff1a;抖音矩阵系统源代码需要使用Java和Scala编程语言&#xff0c;因此您需要下载和安…

2023年程序员工资中位数增长10%?开发者最常用的语言竟然是……

在调研了全球超过 90000 名开发者之后&#xff0c;程序员社区 Stack Overflow 重磅发布了《2023 Developer Survey》调查报告。在本次报告中&#xff0c;Stack Overflow 从工具、编码、工作、社区等维度展开&#xff0c;同时深入研究了 AI/ML 技术&#xff0c;并解析开发者如何…

python spider 爬虫 之 urllib系列

python 中 集成了 urllib urllib import urllib.request # urlopen 方法 url"url" response urllib.request.urlopen(url)print(type(response )) print(response.read()) # 解码 字节--->字符串 decode 字符串--》字节 encode print(response.read()…

618电商物流内卷,拼速度不是唯一底牌,还有……

每年的618大促&#xff0c;对于消费者来说都是一场购物盛宴&#xff0c;也是各个快递企业的“大练兵”。各大电商平台也纷纷铆足劲&#xff0c;希望能抓住此次机会增加营收。 面对电商平台和消费者需求&#xff0c;今年的快递电商企业在保证速度&#xff0c;提升服务质量的前提…

用CMake下的find_package()函数链接库

文章目录 find_package()原理案例1&#xff1a;为项目添加库 find_package()原理 关于find_package()函数的相关内容可参考&#xff1a; https://www.cnblogs.com/lidabo/p/16635249.html Cmake 会在以下的路径中寻找Config.cmake或Find.cmake文件。找到后即可执行该文件并生…

pycharm 2023 IDE 个人一些常用配置记录|输入法|中文|光标|

1. 中文 文件->设置->插件,找到这个&#xff1a; 2. 光标前进和后退 移除前面的配置&#xff0c;修改一下&#xff0c;改称Ctrl左键头\右箭头 然后点击确定 3.中文输入法 3.1 解决输入法有无问题 在pycharm安装目录bin下的pycharm.sh中&#xff0c;添加如下几行&am…

白酒回收APP开发需具备哪些功能?

开发白酒回收APP软件需要具备哪些功能呢&#xff1f; 1、酒品展示。白酒回收APP首页展示各种人们回收的白酒产品&#xff0c;还可以对白酒进行品牌分类&#xff0c;这样用户在回收售卖的时候可以快速找到自己需要的品牌&#xff0c;点击进入查看回收指南&#xff0c;一步…

中国葡萄酒 当惊世界殊 宁夏贺兰山东麓葡萄酒亮相首都地铁

近日&#xff0c;宁夏贺兰山东麓葡萄酒以“中国葡萄酒 当惊世界殊、中国酒庄酒 天赋贺兰山”为宣传主题的宁夏贺兰山东麓葡萄酒宣传专列&#xff08;列车车号&#xff1a;01055&#xff09;亮相北京地铁1号线。该专列将从4月7日至7月6日持续开行3个月&#xff0c;平均每天往返穿…

Snipaste下载

官网&#xff1a; Snipaste 下载 解压 在桌面右下角状态栏中可以找到软件图标&#xff0c; 如图所示&#xff0c;已经运行成功 鼠标右键点击该图标&#xff0c;选择首选项可以设置相关功能选项。 设置了开机自启 最后将该文件夹放到合适的路径下&#xff0c;重新双击运行Snipa…

计算物理专题:薛定谔方程的有限元解法

计算物理专题&#xff1a;薛定谔方程的有限元解法 简单边值问题的有限元解法 其中&#xff1a;都是上已知的连续函数&#xff0c;且也连续&#xff0c; 等价性定理 如果y(x)是边值问题(1)的解&#xff0c;则y(x)是\mu 中使得泛函I(z)取极小值的函数&#xff1b;反正&#xff0c…

【面试题系列】关于K8s—Job的2个问题

序言 人生是一场消耗&#xff0c;要把美好的时光放在喜欢的人与事上。 写在前面 前面学习了job&#xff0c;现在思考一下两个问题 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用来标…

only up 游戏分析

文章目录 介绍游戏玩法游戏面向的群体游戏所须配置游戏美术风格游戏优点游戏缺点和改进方案游戏爆火原因分析同类型游戏对比和游戏继承性地铁跑酷掘地求升跳跳乐 总结 介绍 游戏玩法 这是一个玩法很简单的跑酷游戏&#xff0c;你必须找到一条可行的道路&#xff0c;一直往上走…

【C++】哈希的应用

文章目录 一、位图1. 位图的引入2. 位图的实现3. 位图的应用4. 哈希切割 二、布隆过滤器1. 布隆过滤器的引入2. 布隆过滤器的实现3. 布隆过滤器的应用4. 布隆过滤器的总结 一、位图 1. 位图的引入 我们先来看一道面试题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没…

vue项目用iframe嵌入另外一个vue项目(cesium)

vue项目用iframe 项目嵌入另外一个vue项目&#xff0c;主要分2种情况&#xff0c;一种情况是嵌入本地项目&#xff0c;另外一种是嵌入用web服务器启动的vue项目。 1&#xff09;嵌入本地项目 vue create hello-world 创建项目后&#xff0c; 用npm run build打包&#xff0c;把…

IPO观察丨健身器材行业加“数”前行,康力源如何重构竞争壁垒?

近年来&#xff0c;健身器材市场的火热&#xff0c;引来了资本的广泛关注。数据显示&#xff0c;2021年中国健身器材市场规模为546.5亿元&#xff0c;同比增长15%&#xff0c;预计2024年或可达到799.6亿元。在这股浪潮之下&#xff0c;多家健身器材企业递出了IPO申请。比如&…

安装mmdetection(windows下)

windows环境安装mmdetection 创建pytorch环境最终安装的版本信息安装过程step1&#xff1a;安装mmcv-fullstep2&#xff1a;安装mmdetection 创建pytorch环境 mmdetection是基于PyTorch、CUDA环境来安装的&#xff0c;所以首先得安装深度学习pytorch环境、参考我的这篇pytorch…

基于企业微电网平台的食用菌工厂的能源管理

摘要&#xff1a;从食用菌生产经营者角度指出食用菌工厂化生产的产品生鲜属性、微生物培养的技术特点和竞争战略难以突破决定了成本控制是经营的核心。分析食用菌生产的成本构成&#xff0c;指出加强能源管理是节本增效的重要途径&#xff0c;从电费的分类和改善方式、灭菌的燃…