当前位置: 首页 > news >正文

【Yolov5+Deepsort】训练自己的数据集(3)| 目标检测追踪 | 轨迹绘制 | 报错分析解决

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

💻环境&配置: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)| 目标检测&追踪 | 轨迹绘制

如果想要实现训练集的采集与划分,Yolov5模型的训练,猛戳这里:

 Ⅰ Deepsort模型训练

0x00 数据集准备

Deepsort所需要的的数据集与前面Yolov5目标检测的有所不同。

这里需要借助labelimg工具手动做出标定生成xml文件,再撰写脚本把图像中的检测目标扣出来,作为我们的数据集。

import cv2
import xml.etree.ElementTree as ET
import numpy as npimport xml.dom.minidom
import os
import argparsedef main():# JPG文件的地址img_path = 'path'# XML文件的地址anno_path = 'path'# 存结果的文件夹cut_path = '/home/zqy/Desktop/yolov5-master/nxm_data/crops/'if not os.path.exists(cut_path):os.makedirs(cut_path)# 获取文件夹中的文件imagelist = os.listdir(img_path)# print(imagelistfor image in imagelist:image_pre, ext = os.path.splitext(image)img_file = img_path + imageimg = cv2.imread(img_file)xml_file = anno_path + image_pre + '.xml'# DOMTree = xml.dom.minidom.parse(xml_file)# collection = DOMTree.documentElement# objects = collection.getElementsByTagName("object")tree = ET.parse(xml_file)root = tree.getroot()# if root.find('object') == None:#     returnobj_i = 0for obj in root.iter('object'):obj_i += 1print(obj_i)cls = obj.find('name').textxmlbox = obj.find('bndbox')b = [int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)),int(float(xmlbox.find('xmax').text)),int(float(xmlbox.find('ymax').text))]img_cut = img[b[1]:b[3], b[0]:b[2], :]path = os.path.join(cut_path, cls)# 目录是否存在,不存在则创建mkdirlambda = lambda x: os.makedirs(x) if not os.path.exists(x) else Truemkdirlambda(path)try:cv2.imwrite(os.path.join(cut_path, cls, '{}_{:0>2d}.jpg'.format(image_pre, obj_i)), img_cut)except:continueprint("&&&&")if __name__ == '__main__':main()

得到完整的数据集后,我们对数据集进行划分 :

import os
from PIL import Image
from shutil import copyfile, copytree, rmtree, movePATH_DATASET = 'path'  # 需要处理的文件夹
PATH_NEW_DATASET = 'path'  # 处理后的文件夹
PATH_ALL_IMAGES = PATH_NEW_DATASET + '/all_images'
PATH_TRAIN = PATH_NEW_DATASET + '/train'
PATH_TEST = PATH_NEW_DATASET + '/test'# 定义创建目录函数
def mymkdir(path):path = path.strip()  # 去除首位空格path = path.rstrip("\\")  # 去除尾部 \ 符号isExists = os.path.exists(path)  # 判断路径是否存在if not isExists:os.makedirs(path)  # 如果不存在则创建目录print(path + ' 创建成功')return Trueelse:# 如果目录存在则不创建,并提示目录已存在print(path + ' 目录已存在')return Falseclass BatchRename():'''批量重命名文件夹中的图片文件'''def __init__(self):self.path = PATH_DATASET  # 表示需要命名处理的文件夹# 修改图像尺寸def resize(self):for aroot, dirs, files in os.walk(self.path):# aroot是self.path目录下的所有子目录(含self.path),dir是self.path下所有的文件夹的列表.filelist = files  # 注意此处仅是该路径下的其中一个列表# print('list', list)# filelist = os.listdir(self.path) #获取文件路径total_num = len(filelist)  # 获取文件长度(个数)for item in filelist:if item.endswith('.jpg'):  # 初始的图片的格式为jpg格式的(或者源文件是png格式及其他格式,后面的转换格式就可以调整为自己需要的格式即可)src = os.path.join(os.path.abspath(aroot), item)# 修改图片尺寸到128宽*256高im = Image.open(src)out = im.resize((128, 256), Image.ANTIALIAS)  # resize image with high-qualityout.save(src)  # 原路径保存def rename(self):for aroot, dirs, files in os.walk(self.path):# aroot是self.path目录下的所有子目录(含self.path),dir是self.path下所有的文件夹的列表.filelist = files  # 注意此处仅是该路径下的其中一个列表# print('list', list)# filelist = os.listdir(self.path) #获取文件路径total_num = len(filelist)  # 获取文件长度(个数)i = 1  # 表示文件的命名是从1开始的for item in filelist:if item.endswith('.jpg'):  # 初始的图片的格式为jpg格式的(或者源文件是png格式及其他格式,后面的转换格式就可以调整为自己需要的格式即可)src = os.path.join(os.path.abspath(aroot), item)# 根据图片名创建图片目录dirname = str(item.split('_')[0])# 为相同车辆创建目录# new_dir = os.path.join(self.path, '..', 'bbox_all', dirname)new_dir = os.path.join(PATH_ALL_IMAGES, dirname)if not os.path.isdir(new_dir):mymkdir(new_dir)# 获得new_dir中的图片数num_pic = len(os.listdir(new_dir))dst = os.path.join(os.path.abspath(new_dir),dirname + 'C1T0001F' + str(num_pic + 1) + '.jpg')# 处理后的格式也为jpg格式的,当然这里可以改成png格式    C1T0001F见mars.py filenames 相机ID,跟踪指数# dst = os.path.join(os.path.abspath(self.path), '0000' + format(str(i), '0>3s') + '.jpg')    这种情况下的命名格式为0000000.jpg形式,可以自主定义想要的格式try:copyfile(src, dst)  # os.rename(src, dst)print('converting %s to %s ...' % (src, dst))i = i + 1except:continueprint('total %d to rename & converted %d jpgs' % (total_num, i))def split(self):# ---------------------------------------# train_testimages_path = PATH_ALL_IMAGEStrain_save_path = PATH_TRAINtest_save_path = PATH_TESTif not os.path.isdir(train_save_path):os.mkdir(train_save_path)os.mkdir(test_save_path)for _, dirs, _ in os.walk(images_path, topdown=True):for i, dir in enumerate(dirs):for root, _, files in os.walk(images_path + '/' + dir, topdown=True):for j, file in enumerate(files):if (j == 0):  # test dataset;每个车辆的第一幅图片print("序号:%s  文件夹: %s  图片:%s 归为测试集" % (i + 1, root, file))src_path = root + '/' + filedst_dir = test_save_path + '/' + dirif not os.path.isdir(dst_dir):os.mkdir(dst_dir)dst_path = dst_dir + '/' + filemove(src_path, dst_path)else:src_path = root + '/' + filedst_dir = train_save_path + '/' + dirif not os.path.isdir(dst_dir):os.mkdir(dst_dir)dst_path = dst_dir + '/' + filemove(src_path, dst_path)rmtree(PATH_ALL_IMAGES)if __name__ == '__main__':demo = BatchRename()demo.resize()demo.rename()demo.split()

0x01 参数调整

1.修改model.py

根据数据集中的类别,修改num_classes:

🚩注:

数据集划分好后train和test文件夹下分别有多少个子文件夹,就代表有多少个类别。

即num_classes的数量。

2.修改train.py

 --data-dir:数据集文件,修改数据集的路径。

--lr:学习率,可以不用修改。

根据需求修改epoches的次数:

 可以修改权重保存的位置以及命名,以免发生覆盖:

修改dataset的预处理:

修改完成后,运行train.py开始训练,最终得到的权重结果保存在deep/checkpoint中。

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

Ⅱ 生成视频&轨迹绘制

0x00 参数设置

 将之前yolov5训练后得到的best.pt和Deepsort训练后得到的权重替换到track.py中:

修改视频的地址: 

运行track.py,得到最终视频,并在视频中显示运动轨迹。

Ⅲ 常见报错分析

为了方便新手小白快速上手,解决报错,暂不讲解报错的具体原因,只给出如何解决报错(给出最简单的解决办法),若想进一步了解报错的具体原因,可以在评论区一起交流。

0x00 未修改num_classes

报错:

解决方法:

在model.py中修改num_classes

 0x01 梯度问题

 报错:

 这个错误是由于在计算梯度的过程中,对一个叶子节点(leaf Variable)进行了原地操作(in-place operation),导致了运行时错误。PyTorch中默认情况下,autograd不支持对叶子节点进行原地操作,因为这会导致梯度计算不正确。

解决方法:

在models文件夹下的yolo.py文件中:

 添加代码:

with torch.no_grad():

0x02 显存不足

报错:

解决方法(这里提供一个最简单的方法):

更改batch_size的大小和epoch的次数。

 或者释放内存:

if hasattr(torch.cuda, 'empty_cache'):torch.cuda.empty_cache()

 ❓有更多报错大家可以写在评论区,博主看到后会尽力帮助大家。

0x03 Wandb问题

报错:

解决方法:

直接关闭wandb。

在wandb_utils.py中,将开头部分的代码:

 try:import wandbfrom wandb import init, finish
except ImportError:wandb = None

 改为:

try:import wandbfrom wandb import init, finish
except ImportError:wandb = None
wandb = None

0x04 权重pt文件不匹配

报错:

权重pt文件和新环境的YOLOv5的小版本不相同

报错代码:

YoloV5:AttributeError: Can‘t get attribute ‘C3‘ on <module ‘models.common‘ from

解决方法:在common.py中加入C3SPPF模块:

#在最上面需要引入warnings库
import warningsclass C3(nn.Module):# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansionsuper(C3, self).__init__()c_ = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c1, c_, 1, 1)self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])# self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))class SPPF(nn.Module):# Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocherdef __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))super().__init__()c_ = c1 // 2  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c_ * 4, c2, 1, 1)self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)def forward(self, x):x = self.cv1(x)with warnings.catch_warnings():warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warningy1 = self.m(x)y2 = self.m(y1)return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))

0x05 YOLOv5断后继续训练 

YOLOv5自带断点保存,可以恢复训练。

在train.py中,把

 改为:

parser.add_argument('--resume', nargs='?', const=True, default=True, help='resume most recent training')

default 后改为True。

运行程序,可以看到从上次中断得到地方继续训练了。

  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)

相关文章:

【Yolov5+Deepsort】训练自己的数据集(3)| 目标检测追踪 | 轨迹绘制 | 报错分析解决

📢前言:本篇是关于如何使用YoloV5Deepsort训练自己的数据集,从而实现目标检测与目标追踪,并绘制出物体的运动轨迹。本章讲解的为第三部分内容:数据集的制作、Deepsort模型的训练以及动物运动轨迹的绘制。本文中用到的数…...

docker desktop如何一键进入容器内部

对着对应的容器 点击 view files...

多机单目标跟踪Cross-Drone Transformer Network for Robust Single Object Tracking

1. 摘要 无人机已被广泛用于各种应用,如空中摄影和军事安全,因为与固定摄像机相比,无人机具有高机动性和广阔的视野。多架无人机跟踪系统可以通过收集不同视角的互补视频片段来提供丰富的目标信息,特别是当目标在某些视角下被遮挡…...

手写Mybatis:第7章-SQL执行器的定义和实现

文章目录 一、目标:SQL执行的定义和实现二、设计:SQL执行的定义和实现三、实现:SQL执行的定义和实现3.1 工程结构3.2 SQL执行实现的关系图3.3 执行器的定义和实现3.3.1 Executor 接口3.3.2 BaseExecutor 抽象基类3.3.3 SimpleExecutor 简单执…...

C语言基础知识理论版(很详细)

文章目录 前述一、数据1.1 数据类型1.2 数据第一种数据:常量第二种数据:变量第三种数据:表达式1、算术运算符及算术表达式2、赋值运算符及赋值表达式3、自增、自减运算符4、逗号运算符及其表达式(‘顺序求值’表达式)5…...

CG MAGIC分享3d Max中的Corona渲染器材质如何成转换VRay材质?

大家无论是使用Corona渲染器还是Vray渲染器时,进行材质问题时,都会遇到转化材质问题。 如何将CR转换成VR或者将VR转换CR材质呢? 对于这两者之间转换最好最好的方法只能是材质转换器。 CG MAGIC小编,梳理了两种方法,大…...

电脑入门:路由器常见问题排错步骤

HiPER系列路由器使用中Ping LAN口不通的诊断步骤 准备工作: 在可以ping通的时候记录下路由器LAN口的MAC地址: 命令hiper% show interface ethernet/1 mac Mac : 0022aa419d1e 以下步骤在ping不通路由器的时候依次操作,并记下结果: 步骤一:观察设备各端口…...

mac电脑识别不出来u盘?mac识别不了u盘怎么办

有些用户反馈说本来想要拷贝文件,但是将U盘插入mac系统后竟然不能识别,这时候我们需要用到NTFS For Mac软件。 其实mac系统只提供了它自身磁盘格式(mac os 扩展)等的读写权限,只提供了读的权限给NTFS、FAT32给硬盘和U盘,我们99%使…...

【系统编程】线程池以及API接口简介

(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮&#xff0…...

Verilog零基础入门(边看边练与测试仿真)-笔记

文章目录 第一讲第二讲第三讲第四讲 第一讲 1、testbench 没有端口,所以没括号 2、testbench 输入端 之后要变动 所以定义为reg 3、#10 :过10个时间单位 ;’timescale 1ns/10ps 即 1ns 的时间单位 10ps的时间精度 4、reg 型变量赋值的时候 用…...

LLMs之Code:Code Llama的简介、安装、使用方法之详细攻略

LLMs之Code:Code Llama的简介、安装、使用方法之详细攻略 导读:2023年08月25日(北京时间),Meta发布了Code Llama,一个可以使用文本提示生成代码的大型语言模型(LLM)。Code Llama是最先进的公开可用的LLM代码任务,并有潜…...

[国产MCU]-W801开发实例-MQTT客户端通信

MQTT客户端通信 文章目录 MQTT客户端通信1、MQTT介绍2、W801的MQTT客户端相关API介绍3、代码实现本文将详细介绍如何在W801中使用MQTT协议通信。 1、MQTT介绍 MQTT 被称为消息队列遥测传输协议。它是一种轻量级消息传递协议,可通过简单的通信机制帮助资源受限的网络客户端。 …...

搭建个人hMailServer 邮件服务实现远程发送邮件

文章目录 1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpolar内网映射工…...

React的 虚拟DOM创建

React是一个流行的JavaScript库,用于构建用户界面。它通过使用虚拟DOM来提高性能和渲染速度。本文将详细介绍React的虚拟DOM的创建方式、用法和案例,以及相关代码和解释。 虚拟DOM是什么? 虚拟DOM是React的一个重要概念,它是一个…...

供热管网安全运行监测,提升供热管网安全性能

城市管网是城市的“生命线”之一,是城市赖以生存和发展的基础,在城市基础设施高质量发展中发挥着重要作用。供热管网作为城市生命线中连接供热管线与热用户的桥梁,担负着向企业和居民用户直接供热的重要职责。随着城市热力需求的急剧增加&…...

手写Mybatis:第14章-解析和使用ResultMap映射参数配置

文章目录 一、目标:ResultMap映射参数二、设计:ResultMap映射参数三、实现:ResultMap映射参数3.1 工程结构3.2 ResultMap映射参数类图3.3 添加类型处理器3.3.1 日期类型处理器3.3.2 类型处理器注册机 3.4 存放映射对象3.4.1 结果标志3.4.2 结…...

GE VME-7807RC-410001350-93007807-410001 K数字输入模块

通道数目: VME-7807RC-410001350-93007807-410001K 数字输入模块通常具有多个数字输入通道,可以同时监测多个数字信号。 输入类型: 这种模块通常用于监测数字信号,例如开关状态(ON/OFF)或计数器脉冲。 采…...

C++插入加密,替代加密

void 插入加密() {//缘由https://bbs.csdn.net/topics/396047473int n 1, j 0;char aa[60]{}, aaa[] "abcde";cin >> aa;while (j < 60 && (aa[j] - \0))cout << aa[j] << aaa[j % 5]; } void 插入加密() {//缘由https://bbs.csdn.n…...

Web前端开发概述

Web&#xff08;World Wide Web&#xff0c;全球广域网&#xff09;是指一种基于互联网的信息系统&#xff0c;通过超文本链接将全球各地的文档、图像、视频等资源相互关联起来&#xff0c;并通过Web浏览器进行交互浏览和访问。Web的发展使得人们可以方便地获取和共享各种类型的…...

Web自动化 —— Selenium元素定位与防踩坑

1. 基本元素定位一 from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By # selenium Service("../../chromedriver.exe") # driver webdriver.Chrome(serviceService) # driver.…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...