YOLOV5目标检测记录

本文仅讨论YOLOV5的目标检测使用过程的一些记录,不涉及CUDA的配置,以及一些环境的配置问题,相关问题可以参考我的其他博客。

1、运行官网YOLOV5代码

1、下载源代码

首先肯定找开源代码,目前似乎大部分代码都是在下面的代码修改而来的,我们从git上找到大神的开源代码:

ultralytics/yolov5 at v5.0 (github.com)

这里在旁边的分支这里选择v5.0的分支,全文下载也可以,或者电脑如果有git,也可以下面的命令来获取

git clone xxx

下载页如图所示
在这里插入图片描述
这个下完只有1.4M,直觉高速我们肯定不对,所以我们需要看看缺了啥,没错还需要把权重下载下来,打开这个sh文件就可以看到了,这里我们可以之间点到这个链接里面去下载
在这里插入图片描述
进去之后页面下拉,找到需要的版本下载权重,因为下面的无论是训练还是进行目标检测都需要这个权重,这个也可以理解为就是一个模型文件,一个训练好的模型文件
在这里插入图片描述
其实官方模型是一个20类物体的目标见的模型,是比较常见的模型,在data的voc的配置文件里面我们可以看到里面的内容,下面的修改也是基于这个进行的
在这里插入图片描述

2、文件夹解析

这里参考了:目标检测—教你利用yolov5训练自己的目标检测模型

下面对一些重要的文件夹做下说明

在这里插入图片描述

data文件夹

  • 主要是存放一些超参数的配置文件,就是yaml文件,就是一些数据集的配置文件。
  • 官方提供测试的图片,当然自己的测试图片也可以使用的。
  • 如果是训练自己的数据集的话,那么就需要修改其中的yaml文件。
    在这里插入图片描述
    这里其实其他文件没什么用。.sh是用来下载的,所以干脆就都删掉,只留下一个
    在这里插入图片描述

models文件夹:

  • 里面主要是一些网络构建的配置文件和函数,其中包含了该项目的四个不同的版本,分别为是s、m、l、x。
  • 因此就是前面变了这里也要做相应的改变
    在这里插入图片描述

utils文件夹:

  • 存放的是工具类的函数,里面有loss函数,metrics函数,plots函数等等。
    在这里插入图片描述

weights文件夹:

  • 放置训练好的权重参数,这里默认也是一个sh文件,就是下载链接,如果网速不行就先下载好吧,这样就不用下载了

下面是一些重要的py文件的介绍

  • detect.py:利用训练好的权重参数进行目标检测,可以进行图像、视频和摄像头的检测。
  • train.py:训练自己的数据集的函数。
  • test.py:测试训练的结果的函数。

3、开始测试

官方文件下载之后就可以直接进行测试的,这里主要是图片,视频还有摄像头部分的测试

1、图片测试

这里修改下预设的参数即可,就是jpg文件
在这里插入图片描述
然后将我们之前准备好的权重文件放到同一路径下,这里选了什么权重路径上就写什么,下面的测试都是基于这个权重来进行的
在这里插入图片描述
图片用的是官方的图片,运行之后会run这个文件下面显示出相关的结果
在这里插入图片描述
结果如下,还是比较准确的
在这里插入图片描述

2、视频测试

视频的部分这个就是将图片修改为对应的视频即可
在这里插入图片描述
这里我用了一张道路行车的视频,运行的结果如下
在这里插入图片描述

3、摄像头实时测试

实时检测这里需要我们将路径修改为自己的摄像头号码,比如电脑默认的摄像头就是0,这里我用的外接的摄像头,就是1了
在这里插入图片描述

但是经过实测好像运行不起来,因为我是去年就跑过这个,所以我之前也下过相应的权重文件,然后这次写这篇文章也下了一次权重文件,我发现两个权重文件报错不太一样,具体请看下面的描述:

第一是使用最新的权重存在的问题,报错信息如下,据说是新的加上了这个SPPF的模块,所以需要到源文件里面加上这个部分
在这里插入图片描述
这里其他博主的建议是加上这个,就是缺失的SPPF加上,因为这个权重其实是yolov5-6.0版本的权重了,yolov5更新的很快,据官方描述使用这个模块检测速度提升了很多,但是咱这里用不到,所以就试试吧

import warnings


class SPPF(nn.Module):
    # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
    def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.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() warning
            y1 = self.m(x)
            y2 = self.m(y1)
            return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))

但是修改后就会报这个错误,又要去改其他的,干脆就不用这个6.0版本的权重了,直接换到下面的5.0版本的,就是下面的一种方案了
在这里插入图片描述

第二是旧的模型会出现的问题,会报这样一个错误,但是还是可以运行,不过只有一张图显示出来,后面的就卡住了,网上说原因是数据集制作的问题,就是数据集里面有的数据集是空的,没标注就会出现这样的问题
在这里插入图片描述
网上提出的解决办法是需要对数据集重新处理,就是标注的数据集出现了没有标注框的情况,需要把这个部分给他清理掉,但是这样就需要重新训练了,太蛮烦了,这里我觉得不如直接就给他处理掉,把这一行代码注释掉即可
在这里插入图片描述
注释掉就可以进行实时的摄像头检测了

2、训练自己的神经网络模型

1、数据集制作

制作软件:labellmg,这里这个软件觉得比较重要的就是快捷键,快捷键很重要啊,一定要看一看,不然标到怀疑人生,其他的就没什么重要的了,软件基本就是导入图片,然后画框,会导出一个xml文件,这个xml文件就是框的一些信息,位置大小之类的,这样就可以给后面的数据集训练使用了。
在这里插入图片描述

快捷键如下所示:

  • A:切换到上一张图片
  • D:切换到下一张图片
  • W:调出标注十字架
  • del :删除标注框框
  • Ctrl+u:选择标注的图片文件夹
  • Ctrl+r:选择标注好的label标签存在的文件夹

我们经常从网上获取一些目标检测的数据集资源标签的格式都是VOC(xml格式)的,而yolov5训练所需要的文件格式是yolo(txt格式)的,这里就需要对xml格式的标签文件转换为txt文件。同时训练自己的yolov5检测模型的时候,数据集需要划分为训练集和验证集。这里提供了一份代码将xml格式的标注文件转换为txt格式的标注文件,并按比例划分为训练集和验证集。先上代码再讲解代码的注意事项。

2、划分数据集

这里采用的voc2007的数据集格式,参考文章如下:

https://blog.csdn.net/didiaopao/article/details/120022845?spm=1001.2014.3001.5501

首先是修改配置文件,需要修改的如下所示
在这里插入图片描述
这里再次修改训练用的配置文件,其实都是一些必要的信息还有路径什么的
在这里插入图片描述
之后就是数据集部分了,这里先进行新建文件夹
在这里插入图片描述
这里上面的博主提供了将我们的标号的数据集转成voc格式的代码,修改一点参数就可以使用了,可以在这里看到标签种类和一些训练集占比的修改
在这里插入图片描述
输出的yolo使用的txt文件
在这里插入图片描述
运行之后可以看到生成了我们训练需要的文件
在这里插入图片描述

源代码如下:本处代码来源

https://blog.csdn.net/didiaopao/article/details/120022845?spm=1001.2014.3001.5501

import xml.etree.ElementTree as ET
import os
import random
from shutil import copyfile

classes = ["hat", "person"]
TRAIN_RATIO = 80


def clear_hidden_files(path):
    dir_list = os.listdir(path)
    for i in dir_list:
        abspath = os.path.join(os.path.abspath(path), i)
        if os.path.isfile(abspath):
            if i.startswith("._"):
                os.remove(abspath)
        else:
            clear_hidden_files(abspath)


def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


def convert_annotation(image_id):
    in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' % image_id)
    out_file = open('VOCdevkit/VOC2007/YOLOLabels/%s.txt' % image_id, 'w')
    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'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            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')
    in_file.close()
    out_file.close()


wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
    os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_sapce_dir):
    os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
    os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
    os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
    os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
    os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
    os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
    os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
    os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
    os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
    os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)

train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir)  # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0, len(list_imgs)):
    path = os.path.join(image_dir, list_imgs[i])
    if os.path.isfile(path):
        image_path = image_dir + list_imgs[i]
        voc_path = list_imgs[i]
        (nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
        (voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
        annotation_name = nameWithoutExtention + '.xml'
        annotation_path = os.path.join(annotation_dir, annotation_name)
        label_name = nameWithoutExtention + '.txt'
        label_path = os.path.join(yolo_labels_dir, label_name)
    prob = random.randint(1, 100)
    print("Probability: %d" % prob)
    if (prob < TRAIN_RATIO):  # train dataset
        if os.path.exists(annotation_path):
            train_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_train_dir + voc_path)
            copyfile(label_path, yolov5_labels_train_dir + label_name)
    else:  # test dataset
        if os.path.exists(annotation_path):
            test_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_test_dir + voc_path)
            copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()

运行就可以将我们标好的数据转成我们需要的格式了!

3、开始训练

训练就进入到train.py这里了,还是一样的,先进行参数修改
在这里插入图片描述
下面还有一些比较重要的参数吧,可以参考的看一看(根据实际情况进行修改
在这里插入图片描述
之后就可以运行代码了,可以使用tensorboard 实时查看训练过程,输入下面的命令(当然这个要提前安装好)

tensorboard --logdir=runs/train

点开下面的网址就可以查看了
在这里插入图片描述
主要是map,准确率和召回率
在这里插入图片描述

4、训练参数

训练完成后会输出一个文件夹,可以在文件夹里面看一些训练的参数,文件夹打开如下所示
在这里插入图片描述
我个人的话主要看这个图吧
在这里插入图片描述

这部分参数的含义如下所示:

  • 边框检测的损失,越小越准确
  • Objectness:推测为目标检测loss均值,越小目标检测越准
  • Classification:推测为分类loss均值,越小分类越准
  • Precision:准确率(找对的/找到的)
  • Recall:召回率(找对的/该找对的)
  • mAP@0.5 & mAP@0.5:0.95:AP是用Precision和Recall作为两轴作图后围成的面积,m表示平均,@后面的数表示判定iou为正负样本的阈值,@0.5:0.95表示阈值取0.5:0.05:0.95后取均值。

本处参考:

https://blog.csdn.net/flyfish1986/article/details/118858068

5、使用训练好的模型进行预测

这里其实就是跑到原来那块检测那里了,就是修改下模型文件就行了
在这里插入图片描述

3、获取目标中心坐标

一般用yolo进行目标追踪的话,需要进行查找中心位置,当然这是很传统的方法了,所以下面就看看这种经典的方案
在这里插入图片描述
我们进入这个函数就能看到画框函数
在这里插入图片描述
在里面加上一句

print("中心位置的坐标为"+str((c1[0]+c2[0])/2)+','+str((c1[1]+c2[1])/2))

这样就可以了,运行即可看到结果
在这里插入图片描述

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
yolov5旋转目标检测的改进主要是在目标标注方式和模型结构上进行的。在纯俯视角度(无人机/遥感视角)下的物体目标检测中,常见的标注方式包括矩形标注和圆形平滑标注。 矩形标注是一种常见的目标标注方式,通过在目标周围绘制一个矩形框来标注目标的位置和大小。这种标注方式简单直观,但对于旋转目标的检测可能存在一定的困难。 为了改进yolov5在旋转目标检测中的性能,引用提到了一种称为Circular Smooth Label的标注方式。这种标注方式通过在目标周围绘制一个圆形框,并采用平滑的方式定义目标的边界,可以更好地适应旋转目标的形状和姿态变化。这个改进被认为是yolov5在旋转目标检测中的关键之处。 此外,yolov5还对模型结构进行了改进。引用提到新的yolov5源码中进行了许多改动,改建的速度虽然没有其他更新快,但这些改动对于旋转目标检测的效果和性能有着重要的影响。具体的改动内容可以参考yolov5的源码。 综上所述,yolov5旋转目标检测的改进主要包括引入了Circular Smooth Label的标注方式和对模型结构的改进。这些改进使得yolov5在纯俯视角度下的物体目标检测中具有更好的性能和适应性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [YOLOv5在无人机/遥感场景下做旋转目标检测时进行的适应性改建详解(踩坑记录)...](https://blog.csdn.net/qq_29462849/article/details/124642538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃成蹊2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值