【Yolov5+Deepsort】训练自己的数据集(2)| 目标检测追踪 | 轨迹绘制

📢前言:本篇是关于如何使用YoloV5+Deepsort训练自己的数据集,从而实现目标检测与目标追踪,并绘制出物体的运动轨迹。本章讲解的为第二部分内容:训练集的采集与划分,Yolov5模型的训练。本文中用到的数据集均为自采,实验动物为斑马鱼。

💻环境&配置:RTX 3060、CUDA Version: 11.1、torch_version:1.9.1+cu111、python:3.8

源码如下:

GitHub - mikel-brostrom/yolo_tracking: A collection of SOTA real-time, multi-object tracking algorithms for object detectors

GitHub - Sharpiless/Yolov5-Deepsort: 最新版本yolov5+deepsort目标检测和追踪,能够显示目标类别,支持5.0版本可训练自己数据集

如果想进一步了解Yolov5+Deepsort中的算法,猛戳这里:【Yolov5+Deepsort】训练自己的数据集(1)| 目标检测&追踪 | 轨迹绘制

目录

Ⅰ准备数据集 

0x00 数据集的采集

0x01 数据集的标注

0x02 数据集的划分

Ⅱ Yolov5模型训练

0x00 修改配置文件

0x01 选择预训练模型

0x02 训练结果

0x03 训练结果浅析

0x04 替换权重文件


Ⅰ准备数据集 

0x00 数据集的采集

使用USB3.0工业相机对运动的斑马鱼进行照片的抓拍采集,共采集到照片1w+。

数据集示例:

❓为什么使用工业相机呢:

  • 可以提供高分辨率和高质量的图像,确保准确的视觉分析和检测。
  • 具备高帧率和快速曝光时间,能够在高速运动或快速生产线上捕获清晰的图像,确保高效的生产过程。
  • 工业相机经过严格的测试和质量控制,具有高度的稳定性和可靠性,能够长时间稳定工作。

由于工业相机的成本等问题,不使用工业相机也可以采集到质量较高的图片,但是采集的图片一般要满足以下要求:

  1. 图像质量:图像应该具有足够的清晰度和图像质量,以确保模型能够正确地提取特征并进行准确的预测。低质量或模糊的图像可能会导致模型性能下降。
  2. 统一尺寸:数据集中的图像应该具有统一的尺寸。在训练过程中,通常需要将图像调整为相同的大小,以便于批量处理。
  3. 多样性:数据集应该包含多样性的图像样本,涵盖不同的场景、角度、光照条件、背景等。这样可以确保模型在各种情况下都能表现良好。
  4. 平衡类别:如果数据集是分类任务,每个类别的样本应该尽量保持平衡。不平衡的类别分布可能导致模型对少数类别的表现不佳。

0x01 数据集的标注

在机器学习和计算机视觉领域,有许多常用的图像数据标注软件,用于对图像数据进行标注和注释。

我们使用LabelImg对抓拍的图片进行标记:

由于我们后续要使用Yolov5作为目标检测的模型,故我们的数据集需采用YOLO的格式进行标记。 

 得到标记后的txt格式

 🚩为了方便读者的实际操作,在这里给出VOC格式转YOLO格式(txt格式)的代码:

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import joindef convert(size, box):x_center = (box[0] + box[1]) / 2.0y_center = (box[2] + box[3]) / 2.0x = x_center / size[0]y = y_center / size[1]w = (box[1] - box[0]) / size[0]h = (box[3] - box[2]) / size[1]return (x, y, w, h)def convert_annotation(xml_files_path, save_txt_files_path, classes):xml_files = os.listdir(xml_files_path)print(xml_files)for xml_name in xml_files:print(xml_name)xml_file = os.path.join(xml_files_path, xml_name)out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')out_txt_f = open(out_txt_path, 'w')tree = ET.parse(xml_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'):difficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_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))# b=(xmin, xmax, ymin, ymax)print(w, h, b)bb = convert((w, h), b)out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')if __name__ == "__main__":# 需要转换的类别,需要一一对应classes1 = ['helmet']# 2、voc格式的xml标签文件路径xml_files1 = r'path'# 3、转化为yolo格式的txt标签文件存储路径save_txt_files1 = r'path'convert_annotation(xml_files1, save_txt_files1, classes1)

因为有多种标记工具可以用于标记,若使用LabelMe进行标记,则需要将json格式转为txt格式

import os
import json
from PIL import Imagejson_dir = 'path'  # json文件路径
out_dir = 'path'  # 输出的 txt 文件路径def get_json(json_file, filename):# 读取 json 文件数据with open(json_file, 'r') as load_f:content = json.load(load_f)file_path = 'D:/train/image/'+filename+'.jpg' # 每个json文件对应的图片文件路径img = Image.open(file_path)# imgSize = img.size  # 大小/尺寸image_width = img.width  # 图片的宽image_height = img.height  # 图片的高filename_txt = out_dir + filename+'.txt'# 创建txt文件fp = open(filename_txt, mode="w", encoding="utf-8")# 将数据写入文件#fp.close()for t in content:if(t['type']<=7):# 计算 yolo 数据格式所需要的中心点的 相对 x, y 坐标, w,h 的值x = (t['x'] + t['width']/ 2) / image_width #归一化y = (t['y']+ t['height']/ 2 )/ image_height #归一化w = t['width']/ image_width #归一化h = t['height'] / image_height #归一化fp = open(filename_txt, mode="r+", encoding="utf-8")file_str = str(t['type']-1) + ' ' + str(round(x, 6)) + ' ' + str(round(y, 6)) + ' ' + str(round(w, 6)) + \' ' + str(round(h, 6))line_data = fp.readlines()if len(line_data) != 0:fp.write('\n' + file_str)else:fp.write(file_str)fp.close()def main():files = os.listdir(json_dir)  # 得到文件夹下的所有文件名称s = []for file in files:  # 遍历文件夹filename = file.split('.')[0]get_json(json_dir+'/'+file, filename)if __name__ == '__main__':main()

0x02 数据集的划分

数据集划分是在机器学习和深度学习任务中至关重要的步骤,用于将数据集分成训练集、验证集和测试集。以下是简单的数据集划分方法:

  • 训练集(Training set):用于训练模型的数据集。训练集占据整个数据集的大部分,通常约为总数据集的60-80%。模型通过训练集来学习数据的特征和模式。
  • 验证集(Validation set):用于调整模型的超参数和选择最佳模型。验证集是用来评估模型在训练过程中的性能,并帮助确定哪些超参数设置最优。验证集通常约占数据集的10-20%。
  • 测试集(Test set):用于评估模型的泛化能力和性能。测试集是在训练和调参完成后,用来验证模型在新数据上的表现。测试集应该与训练集和验证集没有重叠,通常约占数据集的10-20%。  

数据集划分应该尽量保持数据的随机性,避免训练集、验证集和测试集之间的数据分布差异过大。

若数据集划分不当,则容易出现过拟合和欠拟合:

 1.过拟合(Overfitting):

  • 当训练集过小,无法充分代表整个数据分布时,模型可能会在训练集上表现得很好,但在未见过的数据上表现不佳,这称为过拟合。
  • 过拟合问题会导致模型过度记忆训练集中的噪声和细节,而无法泛化到新数据上。
  • 过拟合通常在验证集和测试集上表现较差,但在训练集上表现优秀。

2.欠拟合(Underfitting):

  • 当训练集过大或模型复杂度不够高时,模型可能会无法充分学习数据的规律,而表现不佳,这称为欠拟合。
  • 欠拟合问题会导致模型无法学习数据的真实分布和特征,表现较差且泛化能力差。
  • 欠拟合通常在训练集、验证集和测试集上表现均较差。

 划分好的格式如下: 

可以手动进行数据集的划分,也可以使用如下代码进行数据集的划分:

import os
import shutil
import randomrandom.seed(0)def split_data(file_path,xml_path, new_file_path, train_rate, val_rate, test_rate):each_class_image = []each_class_label = []for image in os.listdir(file_path):each_class_image.append(image)for label in os.listdir(xml_path):each_class_label.append(label)data=list(zip(each_class_image,each_class_label))total = len(each_class_image)random.shuffle(data)each_class_image,each_class_label=zip(*data)train_images = each_class_image[0:int(train_rate * total)]val_images = each_class_image[int(train_rate * total):int((train_rate + val_rate) * total)]test_images = each_class_image[int((train_rate + val_rate) * total):]train_labels = each_class_label[0:int(train_rate * total)]val_labels = each_class_label[int(train_rate * total):int((train_rate + val_rate) * total)]test_labels = each_class_label[int((train_rate + val_rate) * total):]for image in train_images:print(image)old_path = file_path + '/' + imagenew_path1 = new_file_path + '/' + 'train' + '/' + 'images'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + imageshutil.copy(old_path, new_path)for label in train_labels:print(label)old_path = xml_path + '/' + labelnew_path1 = new_file_path + '/' + 'train' + '/' + 'labels'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + labelshutil.copy(old_path, new_path)for image in val_images:old_path = file_path + '/' + imagenew_path1 = new_file_path + '/' + 'val' + '/' + 'images'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + imageshutil.copy(old_path, new_path)for label in val_labels:old_path = xml_path + '/' + labelnew_path1 = new_file_path + '/' + 'val' + '/' + 'labels'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + labelshutil.copy(old_path, new_path)for image in test_images:old_path = file_path + '/' + imagenew_path1 = new_file_path + '/' + 'test' + '/' + 'images'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + imageshutil.copy(old_path, new_path)for label in test_labels:old_path = xml_path + '/' + labelnew_path1 = new_file_path + '/' + 'test' + '/' + 'labels'if not os.path.exists(new_path1):os.makedirs(new_path1)new_path = new_path1 + '/' + labelshutil.copy(old_path, new_path)if __name__ == '__main__':file_path = "D:/Files/dataSet/drone_images"xml_path = 'D:/Files/dataSet/drone_labels'new_file_path = "D:/Files/dataSet/droneData"split_data(file_path,xml_path, new_file_path, train_rate=0.7, val_rate=0.1, test_rate=0.2)

Ⅱ Yolov5模型训练

0x00 修改配置文件

 在data中找到coco128.yaml并打开

其中,nc是标签名个数,names就是标签的名字。

train是在path绝对路径条件下的训练集路径,val同上,但是是验证集,这里为了方便,合并训练集和验证集。

0x01 选择预训练模型

yolov5共有4中配置,本次演示选择yolov5s,这个版本对显存的要求较低,但效果一般。

在yolov5下找到train.py 

 

只需要修改以下参数即可:

 --weights:训练的初始权重的位置,以.pt结尾的文件,可在官网上下载权重。

--cfg:训练模型文件,在本项目中对应yolov5s.yaml。

--data:数据集参数文件,在本项目中对应coco128.yaml

--epochs:训练的轮数,这里设置为1000,可根据需要修改

--batch-size:每次迭代(或称为训练步骤)中模型处理的样本数量,决定了训练的速度,要根据自己电脑的显存选择合理的batch。

0x02 训练结果

可在如下路径下找到最后的结果(在train中的最后一个exp文件夹中,训练次数越多,exp的数量越多):

 可以看到训练结果:

可在如下路径下找到训练后得到的权重:

 

best.pt和last.pt是我们训练出来的权重文件,

其中last是最后一次的训练结果,best是效果最好的训练结果。

🚩注:

可能随着不同的训练设定和实验有所变化,因此在不同的实验中,得到的最佳模型参数可能不同。

只是在训练过程中在验证集上表现最好的一个模型快照,但并不能保证它在所有情况下都是最佳的。

0x03 训练结果浅析

1. F1_curve.png —— F1曲线

  • F1分数与置信度阈值(x轴)之间的关系。F1分数是分类的一个衡量标准,是精确率和召回率的调和平均数,介于0,1之间。越大越好。
  • 若F1曲线很“宽敞”且顶部接近1,说明在训练数据集上表现得很好的置信度阈值区间很大。

R_curve.png —— 单一类召回率(置信度阈值 - 召回率曲线图)

  • 当置信度越小的时候,类别检测的越全面(不容易被漏掉,但容易误判)。

P_curve.png —— 单一类准确率(置信度阈值 - 准确率曲线图)

  •  当判定概率超过置信度阈值时,各个类别识别的准确率。当置信度越大时,类别检测越准确。

PR_curve.png —— 精确率和召回率的关系图

  • 在准确率很高的前提下,尽可能的检测到全部的类别。因此希望我曲线接近(1,1),即希望mAP曲线的面积尽可能接近1。

0x04 替换权重文件

将训练后得到的best.pt替换到track.py中:

至此,yolov5部分已经全部结束。

 END


📝因为作者的能力有限,所以文章可能会存在一些错误和不准确之处,恳请大家指出!

 📃参考文献:

[1] Simple Online and Realtime Tracking with a Deep Association Metric

[1703.07402] Simple Online and Realtime Tracking with a Deep Association Metric (arxiv.org)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01-向量究竟是什么?

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan 向量究竟是什么 引入一些数作为坐标是一种鲁莽的行为 ——赫尔曼外尔 The introduction of numbers as coordinates is an act of violence - Hermann Weyl 向量的定义 向量&#xff0…

【TypeScript】类型断言-类型的声明和转换(五)

【TypeScript】类型断言-类型的声明和转换&#xff08;五&#xff09; 【TypeScript】类型断言-类型的声明和转换&#xff08;五&#xff09;一、简介二、断言形式2.1 尖括号语法2.2 as形式 三、断言类型3.1 非空断言3.2 肯定断言-肯定化保证赋值3.3 将任何类型断言为any3.4 调…

6.5.tensorRT高级(1)-alphapose模型导出、编译到推理(无封装)

目录 前言1. alphapose导出2. alphapose推理3. 讨论总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-alphap…

Java基础(八)二维数组

数组 二、二维数组 1. 二维数组使用步骤 定义二维数组 格式&#xff1a;数据类型 数组名[][]; 或 数据类型[][] 数组名; int scores[][]; int[][] scores;为二维数组元素分配内存 格式&#xff1a;数据类型 数组名[][]; 或 数据类型[][] 数组名; int scores[][]; scores …

什么是设计模式?

目录 概述: 什么是模式&#xff01;&#xff01; 为什么学习模式&#xff01;&#xff01; 模式和框架的比较&#xff1a; 设计模式研究的历史 关于pattern的历史 Gang of Four(GoF) 关于”Design”Pattern” 重提&#xff1a;指导模式设计的三个概念 1.重用(reuse)…

基于微信小程序的传染病酒店隔离平台设计与实现(Java+spring boot+MySQL+微信小程序)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于微信小程序的传染病酒店隔离平台设计与实现&#xff08;Javaspring bootMySQL微信小程序&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;…

【windows】windows上如何使用linux命令?

前言 windows上的bat命令感觉不方便&#xff0c;想在windows上使用linux命令。 有人提供了轮子&#xff0c;本文简单介绍一些该轮子的安装与使用&#xff0c;希望能够帮助到和我有一起需求的网友。 我的答案是busybox。 1.安装busybox.exe 在这个网站上安装busybox busyb…

两个状态的马尔可夫链

手动推导如下公式。 证明&#xff1a; 首先将如下矩阵对角化&#xff1a; { 1 − a a b 1 − b } \begin {Bmatrix} 1-a & a \\ b & 1-b \end {Bmatrix} {1−ab​a1−b​} (1)求如下矩阵的特征值&#xff1a; { 1 − a a b 1 − b } { x 1 x 2 } λ { x 1 x 2 }…

vscode终端背景颜色修改以及报错信息颜色修改

引言 刚从pycharm转到vscode上时&#xff0c;很不喜欢vscode终端信息一片白色&#xff0c;于是想尽办法去修改vscode终端风格 这里提供vscode终端背景颜色的修改和vscode终端报错提示信息颜色的修改方法 (1)vscode终端背景颜色优化 步骤一&#xff0c;ctrlshiftp打开设置搜索…

Unity-UGUI优化策略

界面出栈规则&#xff1a; 界面目录导航、策划界面回退需求造成界面套娃问题&#xff0c;夹带一系列层级问题&#xff0c;应该和策划进行友好沟通&#xff0c;避免界面不合理的出栈入栈规则 overdraw&#xff1a; 尽量减少同屏 半透明物体渲染 Unity 之 UGUI优化&#xff08;…

iOS开发-JsonModel的学习及使用

IOS JsonModel的学习及使用 当我们从服务端获取到json数据后的时候&#xff0c;我们需要在界面上展示或者保存起来&#xff0c;下面来看下直接通过NSDictionary取出数据的情况。 NSDictionary直接取出数据的诟病。 NSString *name [self.responseObj objectForKey:"nam…

github上有哪些值得读源码的react项目?

前言 下面是我整理的关于值得一读源码的react项目&#xff0c;希望对你有所帮助~ 1、 calcom Star: 21.6k calcom是一个开源的计算器应用程序。它提供了基本的数学运算功能&#xff0c;例如加法、减法、乘法和除法&#xff0c;还支持 科学计算、进制转换和单位转换等高级功能…

vmwera中安装的centos8出现ifconfig不可用

刚刚在虚拟机中装好centos结果发现自己的ifconfig命令不可用。 看一下环境变量里有没有ifconfig命令的路径&#xff0c;因为ifconfig是在/sbin路径下的&#xff0c;root用户登录进去才可以运行&#xff0c;先看一下root用户的环境变量。 root用户的环境变量里是有/sbin路径的&a…

java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver的解决办法

springcloudAlibaba项目连接mysql时&#xff08;mysql版本8.0.31&#xff0c;Springboot2.2.2,spring cloud Hoxton.SR1,spring cloud alibaba 2.1.0.RELEASE&#xff09;&#xff0c;驱动名称报红&#xff0c;配置如下&#xff1a; 原因&#xff1a;引入的jdbc驱动包和使用的m…

pytest fixture 用于teardown工作

fixture通过scope参数控制setup级别&#xff0c;setup作为用例之前前的操作&#xff0c;用例执行完之后那肯定也有teardown操作。这里用到fixture的teardown操作并不是独立的函数&#xff0c;用yield关键字呼唤teardown操作。 举个例子&#xff1a; 输出&#xff1a; 说明&…

MongoDB文档-基础使用-在客户端(dos窗口)/可视化工具中使用MongoDB基础语句

阿丹&#xff1a; 本文章将描述以及研究mongodb在客户端的基础应用以及在spring-boot中整合使用mongodb来完成基本的数据增删改查。 传送门&#xff1a; MongoDB文档--基本概念_一单成的博客-CSDN博客 MongoDB文档--基本安装-linux安装&#xff08;mongodb环境搭建&#xff0…

Celery嵌入工程的使用

文章目录 1.config 1.1 通过app.conf进行配置1.2 通过app.conf.update进行配置1.3 通过配置文件进行配置1.4 通过配置类的方式进行配置2.任务相关 2.1 任务基类(base)2.2 任务名称(name)2.3 任务请求(request)2.4 任务重试(retry) 2.4.1 指定最大重试次数2.4.2 设置重试间隔时间…

RTC晶振两端要不要挂电容

发现GD32的RTC晶振两端需要挂电容&#xff0c;STM32的RTC晶振两端不需要挂电容。 STM32的RTC晶振两端&#xff0c;不需要挂电容&#xff0c;这样晶振启振很容易&#xff0c;挂大了&#xff0c;却难启动&#xff0c;且温度越低&#xff0c;启动越难。 有人说负载电容为6pF的晶振…

分享21年电赛F题-智能送药小车-做题记录以及经验分享

这里写目录标题 前言一、赛题分析1、车型选择2、巡线1、OpenMv循迹2、灰度循迹 3、装载药品4、识别数字5、LED指示6、双车通信7、转向方案1、开环转向2、位置环速度环闭环串级转向3、MPU6050转向 二、调试经验分享1、循迹2、识别数字3、转向4、双车通信5、逻辑处理6、心态问题 …

IoTDB1.X windows运行失败问题的处理

在windows运行 IoTDB1.x时 会出现如图所示的问题 为什么会出现这样的问题&#xff1f;java没有安装还是未调用成功&#xff0c;我是JAVA8~11~17各种更换都未能解决问题&#xff0c;最后对其bat文件进行查看&#xff0c;发现在conf\datanode-env.bat、conf\confignode-env.bat这…