草庐IT

【目标检测】YOLOv5针对小目标检测的改进模型/添加帧率检测

zstar-_ 2023-04-15 原文

问题背景

众所周知,YOLOv5会对输入的图片进行放缩,并进行32倍下采样。对于一些分辨率很高的遥感/无人机图片,小目标难以被训练识别。
本篇博文就来尝试这篇博文YOLOV5 模型和代码修改——针对小目标识别所提到的一种改进方案。

我所使用的是YOLOv5-5.0版本,数据集采用VisDrone数据集。

检测头改进

模型方面的修改:作者在模型上增加了一个更小的Anchor并添加了一个更小的检测头。
yolov5l_modify.yaml

# parameters
nc: 10  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple

# anchors
anchors:
  - [5,6, 8,14, 15,11]  #4
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Focus, [64, 3]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, BottleneckCSP, [128]],   #160*160
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 9, BottleneckCSP, [256]],  #80*80
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, BottleneckCSP, [512]], #40*40
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 1, SPP, [1024, [5, 9, 13]]],
   [-1, 3, BottleneckCSP, [1024, False]],  # 9   20*20
  ]

# YOLOv5 head
head:
  [[-1, 1, Conv, [512, 1, 1]],  #20*20
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], #40*40
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4  40*40
   [-1, 3, BottleneckCSP, [512, False]],  # 13     40*40

   [-1, 1, Conv, [512, 1, 1]], #40*40
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3   80*80
   [-1, 3, BottleneckCSP, [512, False]],  # 17 (P3/8-small)  80*80

   [-1, 1, Conv, [256, 1, 1]], #18  80*80
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], #19  160*160
   [[-1, 2], 1, Concat, [1]], #20 cat backbone p2  160*160
   [-1, 3, BottleneckCSP, [256, False]], #21 160*160

   [-1, 1, Conv, [256, 3, 2]],  #22   80*80
   [[-1, 18], 1, Concat, [1]], #23 80*80
   [-1, 3, BottleneckCSP, [256, False]], #24 80*80

   [-1, 1, Conv, [256, 3, 2]], #25  40*40
   [[-1, 14], 1, Concat, [1]],  # 26  cat head P4  40*40
   [-1, 3, BottleneckCSP, [512, False]],  # 27 (P4/16-medium) 40*40

   [-1, 1, Conv, [512, 3, 2]],  #28  20*20
   [[-1, 10], 1, Concat, [1]],  #29 cat head P5  #20*20
   [-1, 3, BottleneckCSP, [1024, False]],  # 30 (P5/32-large)  20*20

   [[21, 24, 27, 30], 1, Detect, [nc, anchors]],  # Detect(p2, P3, P4, P5)
  ]

模型方面的改进有点类似于TPH-YOLOv5。

图像切割

作者在检测的时候(detect.py)增加了一个图像切分的步骤,即将大图切分成各个小块,分别进行检测,然后再进行融合。
增加的代码如下:

 # Inference
 t1 = time_sync()
 # pred = model(img, augment=opt.augment)[0] 原始

 '''
 此处进行改进
 '''
 mulpicplus = "3"  # 1 for normal,2 for 4pic plus,3 for 9pic plus and so on
 assert (int(mulpicplus) >= 1)
 if mulpicplus == "1":
     pred = model(img,
                  augment=augment,
                  visualize=increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False)[0]
 else:
     xsz = img.shape[2]
     ysz = img.shape[3]
     mulpicplus = int(mulpicplus)
     x_smalloccur = int(xsz / mulpicplus * 1.2)
     y_smalloccur = int(ysz / mulpicplus * 1.2)
     for i in range(mulpicplus):
         x_startpoint = int(i * (xsz / mulpicplus))
         for j in range(mulpicplus):
             y_startpoint = int(j * (ysz / mulpicplus))
             x_real = min(x_startpoint + x_smalloccur, xsz)
             y_real = min(y_startpoint + y_smalloccur, ysz)
             if (x_real - x_startpoint) % 64 != 0:
                 x_real = x_real - (x_real - x_startpoint) % 64
             if (y_real - y_startpoint) % 64 != 0:
                 y_real = y_real - (y_real - y_startpoint) % 64
             dicsrc = img[:, :, x_startpoint:x_real,
                      y_startpoint:y_real]
             '''
             可选,查看切片图片内容
             img2 = dicsrc.squeeze(0).cpu().numpy()
             img2 = img2.transpose((1, 2, 0))
             cv2.imshow('123', img2)
             cv2.waitKey(1)  
             '''
             pred_temp = model(dicsrc,
                               augment=augment,
                               visualize=increment_path(save_dir / Path(path).stem,
                                                        mkdir=True) if visualize else False)[0]
             pred_temp[..., 0] = pred_temp[..., 0] + y_startpoint
             pred_temp[..., 1] = pred_temp[..., 1] + x_startpoint
             if i == 0 and j == 0:
                 pred = pred_temp
             else:
                 pred = torch.cat([pred, pred_temp], dim=1)

代码中注释的部分可将切割的图片可视化展示。

效果检测

为了检测这样做是否有效,我使用改进前的YOLOv5l模型和改进后的YOLOv5l模型对VisDrone数据集训练100个epoch,并挑选了VisDrone测试集中的两张角度较高的图片进行检测,结果如下:

左侧是改进前,右侧是改进后:


通过对比发现两者实际上并没有太大的差异,可能是由于VisDrone数据集拍摄高度还是比较低,无法显示出效果,有待尝试更高分辨率的图片。

帧率检测

在尝试视频检测时,我想到如果能在输出视频中显示帧率就好了。
要实现这个功能只需要在detect.py中插入

# 函数开头插入
tt = time.time()
....

# 添加帧率检测
cv2.putText(im0, "FPS:{:.1f}".format(1. / (time.time() - tt)), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 235), 4)
tt = time.time()

# 插入在这个位置
if save_img:
	...

代码备份

改进后的代码:https://www.aliyundrive.com/s/SyPtH4N2jcD

有关【目标检测】YOLOv5针对小目标检测的改进模型/添加帧率检测的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  5. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  6. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  7. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  8. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  9. ruby-on-rails - 如何将验证与模型分开 - 2

    我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:

  10. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

随机推荐