前言:
本篇文章总结了我学习yolov5从0到1的过程,十分详细,同时记录了可能会遇到的报错及解决办法,文章若有不当之处,恳请各位批评指正。
目录
1、在yolov5文件夹下建立以下文件夹,作为数据集存放位置
一、安装Anaconda
1、为什么要安装Anaconda
简单来说,Anaconda就是一个环境和依赖的管理器,可以创建一个独立虚拟环境,在这个虚拟环境中安装需要的依赖,使其满足项目的requirements。打个比方就是,Anaconda可以隔断出一个个独立的小房间,随便你在里面装修什么样的风格,都不会影响到外面和其他人,只要你喜欢就行。
2、安装过程
官网下载链接:Free Download | Anaconda
下载好,双击打开exe文件,一直点next,到这一步更改一下安装位置。
然后就一直next,到这里切记两个勾都要勾上。
直到安装完成。
二、安装Python和Pycharm
1、安装Python
Python建议安装较的版本,这里给出3.9.6的华为镜像源地址:Index of python-local/3.9.6 (huaweicloud.com)
如果需要其他版本也可以自行在镜像源中下载。
选择.exe文件下载,下载完成后打开
下面两个勾勾上。
后面就一直next,直到安装完成。
快捷键win+R,输入cmd回车,输入python回车,显示如下则说明安装完成。
2、安装Pycharm
官网链接:Download PyCharm: The Python IDE for data science and web development by JetBrains
下翻选择community edition(社区版),下载后打开安装包
到这一步,修改安装路径
到这一步,全勾上,然后一直next,直至安装完成。
三、获取yolov5包
GitHub链接:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
可以直接下载zip压缩包,解压到自己对应的盘。如果安装过git包的,也可以直接克隆
四、使用Anaconda创建虚拟环境
win+R,输入cmd,运行以下代码:
conda create -n yolov5 python=3.9 #第一步创建虚拟环境,yolov5是自拟的环境名,可以更改
运行后可能会让你选择y或n,输入y回车即可
等待安装完毕,输入以下代码,进入虚拟环境
activate yolov5
可以看到,在路径的前面,多了一个环境名,这就说明进入了该虚拟环境。
五、安装依赖
将解压后的yolov5文件夹拖到Pycharm的图标上打开整个项目,或在pycharm中左上角files,打开文件夹,选择yolov5文件夹打开
点击下方终端,输入activate yolov5,进入虚拟环境。
如果运行命令后,没有反应,且路径前面有(PS),请看我这一篇文章修改:pycharm终端Power shell修改成cmd-CSDN博客
顺利进入环境后,输入以下代码安装依赖:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
#这里使用清华源镜像下载,速度更快
等待安装完成,如果报错有依赖安装失败,就使用命令pip install + 依赖名,进行安装。
然后输入
python train.py
等待一会,这里根据电脑性能,运行速度有快慢之分。
如果出现以下类似代码,则恭喜你,代码已经跑通了
如果报错了,很大可能都是因为依赖没有安装完成,按照我上面说的,单独安装一下没有的依赖即可。
至此,你已经可以使用cpu进行训练了,但速度较慢,下文接着讲述如何配置pytorch,cuda加速
六、pytorch、cuda、cudnn版本选择及安装
win+R-cmd,运行nvidia-smi,划红线处就是你支持的最大cuda版本。
打开pytorch官网:PyTorch
如果你的CUDA Version大于12.1,就选择下图CUDA 12.1。
如果小于12.1,大于11.8,就选择下图CUDA 11.8.
其他版本点下面的previous version中寻找。
确定好自己的版本后,复制pip3开头的下载链接。
先activate yolov5,进入你创建的虚拟环境,然后运行刚才复制的链接,开始安装pytorch。
等待安装完毕。
进入:cuDNN Archive | NVIDIA Developer,查看对应自己cuda的版本号
可以看到,无论是CUDA12还是11版本,都对应着很多小版本的cudnn,所以小版本号无所谓。
依然是在刚才的虚拟环境中,运行下面命令,安装
conda install cudnn=8.9 #这里我选择8.9版本,小版本让系统自行选择
等待安装完成。逐行运行以下代码
python
import torch
print(torch.cuda.is_available())
如果返回值为True,则说明安装完成。此时可以使用gpu加速模型训练。
七、yolov5的使用教程
1、在yolov5文件夹下建立以下文件夹,作为数据集存放位置
2、安装labelimg,进行打标签
在cmd终端中,运行下面代码
pip install labelimg
等待下载完成,输入labelimg,即可 运行
功能解释如下,标注格式一般选择voc(会生成.xml文件)
在view中勾选Auto save mode 和 Display Labels
选择好图片文件夹的位置images_dataset,和标签存放位置xml_dataset即可开始打标签
A键为上一张、D键为下一张,W键出现画框工具,鼠标左键进行框选。
如果在使用过程中,labelimg出现闪退等情况,请参考我的这一篇文章Labelimg打标签闪退-CSDN博客
3、xml转txt,训练集和验证集的划分
先说以下为什么要xml转txt,而不直接在打标签是直接选择yolo的标签格式(txt)
事实上,yolov5训练使用的为txt文件,而我们使用xml文件,是因为xml打开后可以看见你所打的标签名,方便检查查看。而txt文件打开后只是一串二进制数字。
训练集:
训练集用来训练模型,即确定模型的权重和偏置这些参数,通常我们称这些参数为学习参数。
验证集:
验证集用于模型的选择,更具体地来说,验证集并不参与学习参数的确定,也就是验证集并没有参与梯度下降的过程。验证集只是为了选择超参数,比如网络层数、网络节点数、迭代次数、学习率这些都叫超参数。比如在k-NN算法中,k值就是一个超参数。所以可以使用验证集来求出误差率最小的k。
看不懂没关系,不影响使用,如果想深入了解,请另查相关内容
这里我给出xml转txt、训练集验证集划分代码,我划分的比例是(4:1)。即80%图片用于训练,20%图片用于验证。
只需要将图片放入images_dataset,xml文件放入xml_dataset,然后运行以下代码即可
import os
import random
import shutil
import xml.etree.ElementTree as ET
# 定义类别
classes = ["dog","cat", "elephant","giraffe", "horse","bird"] #标签类别
# 获取当前目录
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
# 将边界框的坐标从绝对值转换为相对值
def convert(size, box):
dw = 1. / size[0]
dh = 1. / size[1]
x = (box[0] + box[1]) / 2.0 # (x_min + x_max) / 2.0
y = (box[2] + box[3]) / 2.0 # (y_min + y_max) / 2.0
w = box[1] - box[0] # x_max - x_min
h = box[3] - box[2] # y_max - y_min
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
# 读取XML文件,转换为YOLO格式,并写入TXT文件
def convert_annotation(image_id):
in_file = open('./xml_dataset/%s.xml' % (image_id), encoding='UTF-8') #xml文件相对路径
out_file = open('./txt_dataset/%s.txt' % (image_id), 'w') # 生成txt格式文件 #txt文件相对路径
tree = ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
cls = obj.find('name').text
if cls not in classes:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
bb = convert((w, h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
# 转换所有XML文件为TXT文件
xml_path = os.path.join(CURRENT_DIR, './xml_dataset/') #xml文件相对路径
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
label_name = img_xml.split('.')[0]
print(label_name)
convert_annotation(label_name)
# 划分数据集
def split_dataset(image_dataset_dir, text_dataset_dir, train_image_dir, train_text_dir, test_image_dir, test_text_dir,
split_ratio=0.8):
# 创建训练集和测试集目录
if not os.path.exists(train_image_dir):
os.makedirs(train_image_dir)
if not os.path.exists(train_text_dir):
os.makedirs(train_text_dir)
if not os.path.exists(test_image_dir):
os.makedirs(test_image_dir)
if not os.path.exists(test_text_dir):
os.makedirs(test_text_dir)
if not os.path.exists(text_dataset_dir):
os.makedirs(text_dataset_dir)
# 获取图像数据集中所有文件的列表
image_file_list = os.listdir(image_dataset_dir)
# 获取文本数据集中所有文件的列表
text_file_list = os.listdir(text_dataset_dir)
# 打乱图像文件列表顺序
random.shuffle(image_file_list)
# 计算训练集和测试集的样本数量
num_train_samples = int(len(image_file_list) * split_ratio)
num_test_samples = len(image_file_list) - num_train_samples
# 将图像文件列表中的前 num_train_samples 个文件复制到训练集目录
for file_name in image_file_list[:num_train_samples]:
src_image_path = os.path.join(image_dataset_dir, file_name)
dst_image_path = os.path.join(train_image_dir, file_name)
shutil.copyfile(src_image_path, dst_image_path)
# 将图像文件列表中的剩余文件复制到测试集目录
for file_name in image_file_list[num_train_samples:]:
src_image_path = os.path.join(image_dataset_dir, file_name)
dst_image_path = os.path.join(test_image_dir, file_name)
shutil.copyfile(src_image_path, dst_image_path)
# 根据相同的文件名将对应的文本文件复制到相应的训练集和测试集目录中
for file_name in image_file_list:
src_text_path = os.path.join(text_dataset_dir, os.path.splitext(file_name)[0] + ".txt")
if os.path.exists(src_text_path):
if file_name in image_file_list[:num_train_samples]:
dst_text_path = os.path.join(train_text_dir, os.path.splitext(file_name)[0] + ".txt")
shutil.copyfile(src_text_path, dst_text_path)
else:
dst_text_path = os.path.join(test_text_dir, os.path.splitext(file_name)[0] + ".txt")
shutil.copyfile(src_text_path, dst_text_path)
# 定义数据集目录
xml_dataset_dir = "xml_dataset" # XML文件目录
text_dataset_dir = "txt_dataset" # txt存放目录
image_dataset_dir = "image_dataset" # image存放目录
train_image_dir = "images/train" # 训练集图片
test_image_dir = "images/val" # 验证集图片
train_text_dir = "labels/train" # 训练集txt
test_text_dir = "labels/val" # 验证集txt
# 划分数据集
split_dataset(image_dataset_dir, text_dataset_dir, train_image_dir, train_text_dir, test_image_dir, test_text_dir)
注意,在代码最后,我使用的是相对路径,要求将该.py文件放在如下图位置
4、修改配置文件
第一:models-yolov5m.yaml 将第一行nc修改成你的标签种类总数
第二:data-coco128.yaml如下图修改
train:训练集图片的地址(相对地址)
val:验证集图片的地址(相对地址)
nc:标签种类总数
class:你的标签种类名
也可以直接复制我的替换,修改即可
# YOLOv5 🚀 by Ultralytics, AGPL-3.0 license
# COCO 2017 dataset http://cocodataset.org by Microsoft
# Example usage: python train.py --data coco.yaml
# parent
# ├── yolov5
# └── datasets
# └── coco ← downloads here (20.1 GB)
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
train: VOC/images/train # train images (relative to 'path') 118287 images
val: VOC/images/val # val images (relative to 'path') 5000 images
# test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
nc: 6
# Classes
names: ["dog","cat", "elephant","giraffe", "horse","bird"]
5、修改并运行train.py
大概位置在四百多行,需要修改以下五处
1:你所使用的pt文件
2:刚才修改的models/yolov5m.yaml
3:刚才修改的data/coco128.yaml
4: 迭代次数,默认是300轮
5:batch_size:一次训练图片的张数。这个需要根据自己具体的gpu来选择,(2、4、8、16、32、64...)数值过大会爆显存,训练中断。我使用的是3050laptop(4g),数值为4已经跑满了显存。
到这里就全部修改完毕了,可以开始训练了
在pycharm的终端,activate yolov5进入虚拟环境,python train.py即可开始训练。
等待训练完成即可。P和R的值越接近1,训练效果越好。
训练出来的模型在
runs/train/exp/weights/best.pt
每一行的代码解释如下,感兴趣自行阅读
def parse_opt(known=False):
parser = argparse.ArgumentParser()
# weights 权重的路径./weights/yolov5s.pt....
parser.add_argument('--weights', type=str, default=ROOT / 'yolov5m.pt', help='initial weights path')
# cfg 配置文件(网络结构) anchor/backbone/numclasses/head,该文件需要自己生成
parser.add_argument('--cfg', type=str, default='', help='model.yaml path')
# data 数据集配置文件(路径) train/val/label/, 该文件需要自己生成
parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path')
# hpy超参数设置文件(lr/sgd/mixup)
parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch-low.yaml', help='hyperparameters path')
# epochs 训练轮次
parser.add_argument('--epochs', type=int, default=300)
# batchsize 训练批次
parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs, -1 for autobatch')
# imagesize 设置图片大小
parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)')
# rect 是否采用矩形训练,默认为False
parser.add_argument('--rect', action='store_true', help='rectangular training')
# resume 是否接着上次的训练结果,继续训练
parser.add_argument('--resume', nargs='?', const=True, default=True, help='resume most recent training')
# nosave 保存最好的模型
parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
# noval 最后进行测试
parser.add_argument('--noval', action='store_true', help='only validate final epoch')
# noautoanchor 不自动调整anchor, 默认False
parser.add_argument('--noautoanchor', action='store_true', help='disable AutoAnchor')
# evolve参数进化
parser.add_argument('--evolve', type=int, nargs='?', const=300, help='evolve hyperparameters for x generations')
# bucket谷歌优盘
parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
# cache 是否提前缓存图片到内存,以加快训练速度,默认False
parser.add_argument('--cache', type=str, nargs='?', const='ram', help='--cache images in "ram" (default) or "disk"')
# mage-weights 加载的权重文件
parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
# device 设备选择
parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
# multi-scale 多测度训练
parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
# single-cls 数据集是否多类/默认True
parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
# optimizer 优化器选择
parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
# sync-bn:是否使用跨卡同步BN,在DDP模式使用
parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
# workers/dataloader的最大worker数量
parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')
# 保存路径
parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name')
# 实验名称
parser.add_argument('--name', default='exp', help='save to project/name')
# 项目位置是否存在
parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
parser.add_argument('--quad', action='store_true', help='quad dataloader')
# cos-lr 余弦学习率
parser.add_argument('--cos-lr', action='store_true', help='cosine LR scheduler')
# 标签平滑
parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
# 早停止忍耐次数
parser.add_argument('--patience', type=int, default=100, help='EarlyStopping patience (epochs without improvement)')
# 冻结训练次数
parser.add_argument('--freeze', nargs='+', type=int, default=[0], help='Freeze layers: backbone=10, first3=0 1 2')
parser.add_argument('--save-period', type=int, default=-1, help='Save checkpoint every x epochs (disabled if < 1)')
parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')
# Weights & Biases arguments
# 在线可视化工具,类似于tensorboard工具,想了解这款工具可以查看https://zhuanlan.zhihu.com/p/266337608
parser.add_argument('--entity', default=None, help='W&B: Entity')
# upload_dataset: 是否上传dataset到wandb tabel(将数据集作为交互式 dsviz表 在浏览器中查看、查询、筛选和分析数据集) 默认False
parser.add_argument('--upload_dataset', nargs='?', const=True, default=False, help='W&B: Upload data, "val" option')
# bbox_interval: 设置界框图像记录间隔 Set bounding-box image logging interval for W&B 默认-1 opt.epochs // 10
parser.add_argument('--bbox_interval', type=int, default=-1, help='W&B: Set bounding-box image logging interval')
# 使用数据的版本
parser.add_argument('--artifact_alias', type=str, default='latest', help='W&B: Version of dataset artifact to use')
# 传入的基本配置中没有的参数也不会报错# parse_args()和parse_known_args()
# parse = argparse.ArgumentParser()
# parse.add_argument('--s', type=int, default=2, help='flag_int')
# parser.parse_args() / parse_args()
opt = parser.parse_known_args()[0] if known else parser.parse_args()
return opt
6、修改并运行detect.py
使用训练出来的best.pt模型去检测目标物体
在二百多行修改以下几个地方
1:训练出来的模型的位置
2:data/images是存放需要检测的图片的位置
3:data/coco128.yaml
可以直接按照我下面的修改
修改完成后,进入虚拟环境,python detect.py即可
检测结果在runs/detect/exp中
如果需要实时摄像头视频识别,就把原来的data/images的那一行注释掉,换成下面给的那一行代码即可。
default的数值为0,则调用内置摄像头,为1,则调用外接摄像头
#parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)')
parser.add_argument('--source', type=str, default='0', help='file/dir/URL/glob, 1 for webcam')#摄像头实时识别
完成了以上的内容,说明大家已经训练出了模型,实现了目标检测,已经基本入门了yolov5。当然这只是深度学习这条路上的起点,后面可能会出现识别准确率低、识别帧率不够高、算力不够等等其他情况,这就需要各位同学针对自己的目标物体,进行参数的调整和算法的改进。
以下内容继续讲述yolov5的应用层面,如何部署到不同的设备与环境中
7、转换onnx文件进行推理
(1)什么是onnx文件?
ONNX定义了一种模型表示方法,包括一系列的操作(operators)和数据结构。模型被表示为一个计算图,图中的节点是操作,边是数据流。ONNX模型包含两部分:
模型定义:描述了模型的结构,包括层、节点和连接方式。
模型权重:包含了模型训练过程中学习到的参数,如卷积核、偏置项等。ONNX使用JSON格式来描述模型,这使得模型易于理解和修改。同时,ONNX还提供了一系列的工具,如ONNXChecker、ONNX Runtime等,用于模型的验证和推理。
(2)为什么要使用ONNX文件
模型共享:ONNX格式使得模型可以在不同的深度学习社区和项目之间共享,从而促进了知识的传播和协作。
模型转换:ONNX提供了一个中间格式,可以将一个框架训练的模型转换为ONNX格式,然后在其他支持ONNX的框架中使用。
跨平台部署:ONNX支持多种硬件和软件平台,使得模型可以轻松地部署到不同的设备和操作系统上,包括服务器、移动设备和嵌入式系统。
模型优化:ONNX模型可以被优化和精简,以适应特定的部署环境和性能要求。
生态系统支持:ONNX生态系统提供了一系列的工具和库,支持模型的验证、推理、可视化和转换。
多样化的应用场景:ONNX模型可以应用于各种领域,如计算机视觉、自然语言处理、语音识别等。
(3)修改并运行export.py得到onnx模型
修改划线处,大概在七百多行
图像尺寸建议640*640,因为yolov5在训练时是将图片转换成640*640的大小进行训练的,这样识别效果可能会更好,后面给出的推理代码也是基于640*640写的。
修改完后,进入虚拟环境,python export.py,运行结束后会得到onnx文件,位置在best.pt的同一个路径
(4)使用onnx进行推理检测
以下就是推理代码,我使用chatgpt编写的
标签、中文映射、onnx路径位置根据情况修改
import cv2
import numpy as np
import onnxruntime
CLASSES = ["dog","cat", "elephant","giraffe", "horse","bird"] # 请将您的类别列表补充完整
#建议顺序与coco128中的标签顺序一致
class YOLOV5():
def __init__(self, onnxpath):
self.onnx_session = onnxruntime.InferenceSession(onnxpath)
self.input_name = self.get_input_name()
self.output_name = self.get_output_name()
def get_input_name(self):
input_name = []
for node in self.onnx_session.get_inputs():
input_name.append(node.name)
return input_name
def get_output_name(self):
output_name = []
for node in self.onnx_session.get_outputs():
output_name.append(node.name)
return output_name
def get_input_feed(self, img_tensor):
input_feed = {}
for name in self.input_name:
input_feed[name] = img_tensor
return input_feed
def inference(self, image):
or_img = cv2.resize(image, (640, 640))
img = or_img[:, :, ::-1].transpose(2, 0, 1) # BGR2RGB和HWC2CHW
img = img.astype(dtype=np.float32)
img /= 255.0
img = np.expand_dims(img, axis=0)
input_feed = self.get_input_feed(img)
pred = self.onnx_session.run(None, input_feed)[0]
return pred, or_img
def xywh2xyxy(x):
y = np.copy(x)
y[:, 0] = x[:, 0] - x[:, 2] / 2
y[:, 1] = x[:, 1] - x[:, 3] / 2
y[:, 2] = x[:, 0] + x[:, 2] / 2
y[:, 3] = x[:, 1] + x[:, 3] / 2
return y
def filter_box(org_box, conf_thres, iou_thres):
org_box = np.squeeze(org_box)
conf = org_box[..., 4] > conf_thres
box = org_box[conf == True]
cls_cinf = box[..., 5:]
cls = []
for i in range(len(cls_cinf)):
cls.append(int(np.argmax(cls_cinf[i])))
all_cls = list(set(cls))
output = []
for i in range(len(all_cls)):
curr_cls = all_cls[i]
curr_cls_box = []
curr_out_box = []
for j in range(len(cls)):
if cls[j] == curr_cls:
box[j][5] = curr_cls
curr_cls_box.append(box[j][:6])
curr_cls_box = np.array(curr_cls_box)
curr_cls_box = xywh2xyxy(curr_cls_box)
boxes = curr_cls_box[:, :4]
scores = curr_cls_box[:, 4]
indices = cv2.dnn.NMSBoxes(boxes.tolist(), scores.tolist(), conf_thres, iou_thres)
for idx in indices:
curr_out_box.append(curr_cls_box[idx])
output.extend(curr_out_box)
output = np.array(output)
return output
def draw(image, box_data):
# 中文标签映射
ENGLISH_TO_CHINESE = {
'bird': '鸟',
'elephant': '大象',
'cat': '猫',
'dog': '狗',
'giraffe': '长颈鹿',
'horse': '马',
# 如果有其他标签,继续添加
}
if len(box_data) == 0:
print("没有检测到任何对象。")
return
boxes = box_data[..., :4].astype(np.int32)
scores = box_data[..., 4]
classes = box_data[..., 5].astype(np.int32)
for box, score, cl in zip(boxes, scores, classes):
top, left, right, bottom = box
# 获取中文标签,如果不存在则使用英文标签
chinese_label = ENGLISH_TO_CHINESE.get(CLASSES[cl], CLASSES[cl])
# 绘制框时显示英文标签
cv2.rectangle(image, (top, left), (right, bottom), (255, 0, 0), 2)
cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),
(top, left),
cv2.FONT_HERSHEY_SIMPLEX,
0.6, (0, 0, 255), 2)
# 终端输出中文标签
print('类别: {}'.format(chinese_label))
def main():
onnx_path = 'runs/train/exp/weights/best.onnx'
model = YOLOV5(onnx_path)
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
break
output, or_img = model.inference(frame)
outbox = filter_box(output, 0.5, 0.5)
draw(or_img, outbox)
cv2.imshow('Video', or_img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
至此,便可以将yolov5轻松地部署到不同的设备和操作系统上。
下面是我在学习过程中,使用的两个很好用的工具
分享给大家:
如果数据集很大,建议大家看一下我的这篇文章,讲述了如何使用Autolabelimg自动打标签Autolabelimg全自动打标签,详细教程-CSDN博客
如果算力不够,训练速度很慢,也可以看这篇文章,讲述了如何租用云gpu进行训练AutoDL云gpu训练yolov5,保姆级教程-CSDN博客
结语:
“我之所以看的更远是因为我站在巨人肩上”,在此致谢CSDN以及所有博主,为我学习yolo入门指引了方向,此刻我站在巨人的肩膀上,愿未来我们每一个人都将成为巨人。