Yolov5.6增加注意力机制+ByterTrack:目标检测与跟踪

简介:本项目使用ESP32-CAM采集图像上传至上位机进行手部目标检测与追踪,使用了YOLOv5.6(注意力机制ECA,CBAM)+ByteTrack

博主同款迅雷链接:
链接:https://pan.xunlei.com/s/VOSO1EIzmXhBb_BIKM58cM5cA1#
提取码:8ms6
需要付费指导的查看简介联系我!

项目拉取:

git clone https://github.com/ultralytics/yolov5.git

环境准备:

Python3.10:https://mirrors.aliyun.com/python-release/windows/python-3.10.8.exe

进入Yolov5根目录创建虚拟环境

python -m venv venv
venv\Scripts\activate #激活虚拟环境
pip install -e .      #编辑式安装,之后修改Yolov5源码直接运行

请添加图片描述

数据集准备:

手部数据egohands_data:http://vision.soic.indiana.edu/egohands_files/egohands_data.zip

数据格式转换:https://blog.csdn.net/wukong168/article/details/122783179

请添加图片描述

需要添加自定义数据集的可以录制视频,使用脚本提取帧,使用Labelme标注图像。

数据集文件夹目录必须符合一下结构,且图像与标注文件名必须一致:

-images-train #训练集图片-val   #验证集图片
-labels-train #训练集标注文件-val   #验证集图片文件

coco128.yaml配置是数据集路径:

path: D:/VUE/ModelData/egohands_data/data
train: images/train
val: images/val
test: # test images (optional)# Classes
names:0: Hand

YOLOv5结构:

使用AI简单了解即可。
请添加图片描述

注意力机制添加:

在Yolov5根目录下的models/common.py文件末尾添加自定义模块,也可以创建一个独立的文件表示一个模块:

CBAM:

请添加图片描述

import torch
import math
import torch.nn as nn
import torch.nn.functional as Fclass BasicConv(nn.Module):def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, relu=True, bn=True, bias=False):super(BasicConv, self).__init__()self.out_channels = out_planesself.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)self.bn = nn.BatchNorm2d(out_planes,eps=1e-5, momentum=0.01, affine=True) if bn else Noneself.relu = nn.ReLU() if relu else Nonedef forward(self, x):x = self.conv(x)if self.bn is not None:x = self.bn(x)if self.relu is not None:x = self.relu(x)return xclass Flatten(nn.Module):def forward(self, x):return x.view(x.size(0), -1)class ChannelGate(nn.Module):def __init__(self, gate_channels, reduction_ratio=16, pool_types=['avg', 'max']):super(ChannelGate, self).__init__()self.gate_channels = gate_channelsself.mlp = nn.Sequential(Flatten(),nn.Linear(gate_channels, gate_channels // reduction_ratio),nn.ReLU(),nn.Linear(gate_channels // reduction_ratio, gate_channels))self.pool_types = pool_typesdef forward(self, x):channel_att_sum = Nonefor pool_type in self.pool_types:if pool_type=='avg':avg_pool = F.avg_pool2d( x, (x.size(2), x.size(3)), stride=(x.size(2), x.size(3)))channel_att_raw = self.mlp( avg_pool )elif pool_type=='max':max_pool = F.max_pool2d( x, (x.size(2), x.size(3)), stride=(x.size(2), x.size(3)))channel_att_raw = self.mlp( max_pool )elif pool_type=='lp':lp_pool = F.lp_pool2d( x, 2, (x.size(2), x.size(3)), stride=(x.size(2), x.size(3)))channel_att_raw = self.mlp( lp_pool )elif pool_type=='lse':# LSE pool onlylse_pool = logsumexp_2d(x)channel_att_raw = self.mlp( lse_pool )if channel_att_sum is None:channel_att_sum = channel_att_rawelse:channel_att_sum = channel_att_sum + channel_att_rawscale = F.sigmoid( channel_att_sum ).unsqueeze(2).unsqueeze(3).expand_as(x)return x * scaledef logsumexp_2d(tensor):tensor_flatten = tensor.view(tensor.size(0), tensor.size(1), -1)s, _ = torch.max(tensor_flatten, dim=2, keepdim=True)outputs = s + (tensor_flatten - s).exp().sum(dim=2, keepdim=True).log()return outputsclass ChannelPool(nn.Module):def forward(self, x):return torch.cat( (torch.max(x,1)[0].unsqueeze(1), torch.mean(x,1).unsqueeze(1)), dim=1 )class SpatialGate(nn.Module):def __init__(self):super(SpatialGate, self).__init__()kernel_size = 7self.compress = ChannelPool()self.spatial = BasicConv(2, 1, kernel_size, stride=1, padding=(kernel_size-1) // 2, relu=False)def forward(self, x):x_compress = self.compress(x)x_out = self.spatial(x_compress)scale = F.sigmoid(x_out) # broadcastingreturn x * scaleclass CBAM(nn.Module):def __init__(self, gate_channels, reduction_ratio=16, pool_types=['avg', 'max'], no_spatial=False):super(CBAM, self).__init__()self.ChannelGate = ChannelGate(gate_channels, reduction_ratio, pool_types)self.no_spatial=no_spatialif not no_spatial:self.SpatialGate = SpatialGate()def forward(self, x):x_out = self.ChannelGate(x)if not self.no_spatial:x_out = self.SpatialGate(x_out)return x_out

请添加图片描述

class ECA(nn.Module):"""Constructs a ECA module.Args:channel: Number of channels of the input feature mapk_size: Adaptive selection of kernel size"""def __init__(self, c1, c2, k_size=3):super(ECA, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):# feature descriptor on the global spatial informationy = self.avg_pool(x)y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)# Multi-scale information fusiony = self.sigmoid(y)return x * y.expand_as(x)
添加到YOLO系统配置输入参数:

在Yolov5根目录下的models/yolo.py文件导入自定义模块:
请添加图片描述
输入参数配置,此处有大量if语句用于个性化输入通道配置:
请添加图片描述
请添加图片描述

修改YOLOv5结构文件:

在Yolov5根目录下的models/yolov5s.yaml文件定义模型结构:

#YOLOv5s_custom summary: 320 layers, 1046153 parameters, 1046153 gradients, 2.5 GFLOPs
#YOLOv5s summary:        214 layers, 7022326 parameters, 7022326 gradients, 15.9 GFLOPs
nc: 1 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
anchors:- [10, 13, 16, 30, 33, 23] # P3/8- [30, 61, 62, 45, 59, 119] # P4/16- [116, 90, 156, 198, 373, 326] # P5/32activation: nn.RReLU() # 激活函数可以自定义# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 3, 2, 1]], # 0-P1/2[-1, 1, Conv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]], # 2[-1, 1, Conv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]], # 5-P4/16[-1, 4, C3, [512]],[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32[-1, 1, C3, [1024]],[-1, 1, ECA, [1024]],  # 添加 ECA 提高小目标检测效果[-1, 1, SPPF, [1024, 5]], # 10]# YOLOv5 v6.0 head
head: [# [from, number, module, args][-1, 1, GhostConv, [512, 1, 1]], # 11[-1, 1, nn.Upsample, [None, 2, "nearest"]],[[-1, 6], 1, Concat, [1]], #13 cat backbone P4[-1, 3, C3, [512, False]], # 14[-1, 1, GhostConv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, "nearest"]],[[-1, 4], 1, Concat, [1]], # 17 cat backbone P3[-1, 3, C3, [256, False]], # 18 (P3/8-small)[-1, 1, ECA, [256]],  # 在检测头中添加 ECA[-1, 1, GhostConv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]], # 21 cat head P4[-1, 3, C3, [512, False]], # 22 (P4/16-medium)[-1, 1, GhostConv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3, [128, False]], # 25 (P5/32-large)[[18, 22, 25], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]

训练:

​ 由于修改了模型结构,建议不加载官方预训练权重yolov5s.pt从0训练,当然可以提前使用遗传算法获取合适的超参数加快收敛速度。

python train.py --data coco128.yaml --weights '' --cfg yolov5s.yaml --img 640

ByteTrack引入:

原理:Yolov5模型输出检测框列表,ByteTrack接收预测跟踪目标,最重要的是ID参数。

具体查看博主重新编写的检测函数:

# -*- coding: utf-8 -*-
"""
@FileName:YoloModelRun.py
@Description:
@Author: 核知坊,一个激发创造力的网站:http://wwww.CoreKSets.cn 
@Time:2025/3/23 20:02
"""
import pathlib
import time
import numpy as np
from PIL import Image
import torch
from models.common import DetectMultiBackend
from utils.augmentations import letterbox
from utils.general import non_max_suppression
from ultralytics.utils.plotting import Annotator
from utils.dataloaders import LoadImages
from utils.general import (LOGGER,Profile,check_img_size,scale_boxes,)
from bytetracker import BYTETracker# 兼容 Windows 下的路径问题
temp = pathlib.PosixPath
pathlib.PosixPath = pathlib.WindowsPathclass YoloModelRun():"""@ClassName:YoloModelRun@Description:@Author:锦沐Python"""def __init__(self, weights="best.onnx", imgsz = (640, 640), conf_thres=0.2, iou_thres=0.45, save_result = False, half=False):self.weights = weightsself.conf_thres = conf_thresself.iou_thres = iou_thresself.save_result = save_resultself.device = torch.device("cpu")# Load modelLOGGER.info("模型加载中")self.Model = DetectMultiBackend(weights, device=self.device, dnn=False, fp16=half)self.Model.eval()# 追踪系统self.Tracker = BYTETracker(track_thresh=0.25, track_buffer=10, match_thresh=0.7, frame_rate=8)self.stride=self.Model.strideself.names=self.Model.namesself.pt = self.Model.ptself.imgsz = check_img_size(imgsz, s=self.stride)  # check image sizeself.Model.warmup(imgsz=(1 , 3, *self.imgsz))  # warmup# [[x1, y1, x2, y2, conf, cls], [x1, y1, x2, y2, conf, cls],....]self.detect_results = []LOGGER.info("模型准备就绪")def detect_image(self,source)->(list[[float,float,float,float,float,int,int]],Image.Image):self.detect_results.clear()# 处理不同类型的输入if isinstance(source, str):# 如果输入是图片路径,使用 LoadImages 进行加载dataset = LoadImages(source, img_size=self.imgsz, stride=self.stride, auto=self.pt, vid_stride=1)path, im, im0s, vid_cap, s = next(iter(dataset))  # 读取一张图片elif isinstance(source, Image.Image):im0s = np.array(source)  # 原始图像 (RGB)im0s = im0s[..., ::-1]  # 转换为 BGR 格式(因为 OpenCV 使用 BGR)# **使用与 LoadImages 类似的预处理**im = letterbox(im0s, self.imgsz, stride=self.stride, auto=self.pt)[0]  # 调整大小im = im.transpose((2, 0, 1))[::-1]  # HWC -> CHW, BGR -> RGBim = np.ascontiguousarray(im)  # 确保数据连续else:raise ValueError("输入必须是图片路径 (str) 或 PIL.Image 对象!")# Run inferencedetect_time_tuble = (Profile(device=self.device), Profile(device=self.device), Profile(device=self.device), Profile(device=self.device))# 图像预处理with detect_time_tuble[0]:im = torch.from_numpy(im).to(self.Model.device)im = im.half() if self.Model.fp16 else im.float()  # uint8 to fp16/32im /= 255  # 0 - 255 to 0.0 - 1.0if len(im.shape) == 3:im = im[None]  # expand for batch dim# Inference 预测with detect_time_tuble[1]:pred = self.Model(im, augment=False, visualize=False)# NMSwith detect_time_tuble[2]:pred = non_max_suppression(pred, self.conf_thres, self.iou_thres, None, False, max_det=10)# 目标绘制im0 = im0s.copy()annotator = Annotator(im0, line_width=3, example=str(self.names[0]))# Process predictionswith detect_time_tuble[3]:det = pred[0]# print(det)s = ""if len(det):det = self.Tracker.update(det)# 没有跟踪到物体直接返回if not det:return  [], Nonedet = torch.tensor(det, dtype=torch.float32)# print(det)# Rescale boxes from img_size to im0 sizedet[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()# Print resultsfor c in det[:, 5].unique():n = (det[:, 5] == c).sum()  # detections per classs += f"{n} {self.names[int(c)]}{'s' * (n > 1)}, "  # add to stringfor *xyxy, conf, cls, id in reversed(det):x1,y1,x2,y2 = xyxyc = int(cls)  # integer classlabel = f"{self.names[c]} {conf:.2f}"annotator.box_label(xyxy, label, color= (255, 36, 125))# 添加检测结果w = 640h = 480self.detect_results.append([round(x1.item() / w, 6),  # 归一化 x1,保留6位小数round(y1.item() / h, 6),  # 归一化 y1,保留6位小数round(x2.item() / w, 6),  # 归一化 x2,保留6位小数round(y2.item() / h, 6),  # 归一化 y2,保留6位小数round(conf.item(), 6),  # 置信度,保留6位小数self.names[c],  # 类别名称int(id)])# Stream resultsif self.save_result:timestamp = int(time.time())annotator.save(f"{timestamp}_result.jpg")show_img = Image.fromarray(np.asarray(annotator.im)[..., ::-1])# Print time (inference-only)LOGGER.info(f"{s}{'' if len(det) else '(没有检测到目标), '}{detect_time_tuble[1].dt * 1e3:.1f}ms")# Print resultsLOGGER.info(f"Speed: %.1fms 预处理, %.1fms 识别, %.1fms NMS ,%d.1ms ByteTrack 每张图像 {(1, 3, *self.imgsz)}" %(detect_time_tuble[0].dt * 1e3,detect_time_tuble[1].dt * 1e3,detect_time_tuble[2].dt * 1e3,detect_time_tuble[3].dt * 1e3))return self.detect_results, show_img

结果:

请添加图片描述
请添加图片描述

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

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

相关文章

C++进阶—C++中的继承

第一章:继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向…

力扣Hot100每日N题(11~14)

200. 岛屿数量 BFS或DFS class Solution {private int[] dx {0, 0, 1, -1};private int[] dy {1, -1, 0, 0};int ans 0, n, m;void dfs(char[][] grid, int x, int y){if(x < 0 || y < 0 || x > n || y > m || grid[x][y] 0) return;grid[x][y] 0;for(int i…

人工智能 倒底是 智能 还是 智障?

假设有如下哈希运算的过程和结果&#xff0c;然后让人工智能根据初始条件和最终结果的最后几个字符推理出中间过程。 yw "123456" salt "a1b2c3d4e5f6" sda256(saltsha1(md5(yw.encode)salt)) 1c5852fa5d3c450621c17b9ba87ffdab8d336b16f015b4a10cffc945…

传智健康---十天项目总结

第一天&#xff1a; 基本内容如下&#xff1a; 从gitee拉取对应的基础代码。做好配置相关工作。测试页面是否可以正常打开。 无问题 需要学习的内容&#xff1a;spring security 了解到这个框架的基础作用大概是&#xff1a;管理请求路径&#xff0c;管理用户权限&#xf…

AbMole| Angiotensin II human(M6240;血管紧张素Ⅱ)

Angiotensin II&#xff08;血管紧张素II&#xff09;是一种生物活性肽和血管收缩剂。Angiotensin II作为肾素-血管紧张素-醛固酮系统&#xff08;RAAS&#xff09;的关键活性成分&#xff0c;在动物模型中&#xff0c;它通过调节于血管平滑肌细胞上的血管紧张素II受体&#xf…

【C/C++】gmock vs mockcpp

文章目录 gmock vs mockcpp1 基本介绍2 语法风格与使用方式gmock 特点&#xff08;基于接口 Mock&#xff09;&#xff1a;mockcpp 特点&#xff08;基于重写/拦截原函数&#xff09;&#xff1a; 3 对比总结4 实际使用建议 gmock vs mockcpp gmock 和 mockcpp 是 C 中常用的两…

自己的服务器被 DDOS跟CC攻击了怎么处理,如何抵御攻击?

今天后台突然弹出警报&#xff1a;服务器带宽瞬间跑满&#xff0c;CPU 占用率飙到 100%。刷新页面时&#xff0c;首页加载像卡带般断断续续&#xff0c;图片刚显示半张就卡住&#xff0c;点击任何按钮都没反应。登录服务器一看&#xff0c;访问日志里密密麻麻全是陌生 IP 的高频…

icg真的只能用latch不能用Flip-flop吗

soc设计中常用latch来做时钟门控&#xff0c;它的rtl描述如下&#xff1a; input EN; input clk; input TE; output E_clk;always (*) beginif (clk1d0)E_latch EN | TE; endassign E_clk E_latch & clk;实际soc实现会把上面代码中latch和与操作换成专用CLKLANQ的libcel…

基于python大数据的nba球员可视化分析系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

从0开始学习R语言--Day22--km曲线

KM曲线 在分析疾病的死亡率时&#xff0c;我们往往会纠结于怎样在逻辑架构中去考虑未死亡的人群&#xff0c;以及想研究两种药物的表现效果&#xff0c;但病人的指标表现都不明显&#xff0c;作用于其他指标且很难量化。 而KM曲线可以很好地反映人群在时间序列上的生存率&…

SpringBoot ​@ControllerAdvice 处理异常

应用中的异常&#xff0c;有两件事要考虑&#xff0c;怎么处理这个异常&#xff0c;怎么把异常可读性高地返回给前端用户 1.怎么把异常可读性高的返回给前端用户或API的消费者 自定义错误代码和错误内容 2.怎么处理异常 比如遇到某个异常时需要发邮件通知IT团队 Controlle…

爬百度图片如何解决{“antiFlag“:1,“message“:“Forbid spider access“}

在学习深度学习的卷积神经算法时&#xff0c;需要猫和狗的训练数据集。这时想到在百度网上爬取猫和狗的图片。 在爬取狗狗图片的时候&#xff0c;我抓包分析了下获取这个url1 “https://image.baidu.com/search/index?tnbaiduimage&ipnr&ct201326592&cl2&lm&…

QWebEngine

Qt自带的QWebEngine 不支持播放MP4, 需要手动编译QWebEngine模块 不支持播放mp4 // mainwindow.cpp , m_webEngine(new MyWebEngine(this)) void MainWindow::init() { //关闭系统代理&#xff0c;提高速度,采用release会更快QNetworkProxyFactory::setUseSystemConfigurati…

Rust 学习笔记1

Basic基础 actix_web基础 #[get("/favicon")] 获取静态图片 #[get("/welcome")] 简单的欢迎 #`/user/{name}/` basic.rs源码 源码 use std::{convert::Infallible, io};use actix_files::{Files, NamedFile}; use actix_session::{storage::Cooki…

3GPP协议PDF下载

https://www.tech-invite.com/3m38/tinv-3gpp-38.html 可以进入3GPP官网界面&#xff0c;也可以进入PDF下载界面 PDF加载比较慢

高性能服务器程序框架知识梳理

服务器编程框架 服务器程序种类有很多&#xff0c;但是基本框架都一样&#xff0c;核心不同点在于逻辑处理单元。基本框架包含&#xff1a;I/O处理单元、逻辑单元、网络存储单元以及请求队列。 I/O处理单元&#xff08;主线程&#xff09;&#xff1a;服务器用来管理客户连接…

【AI】从0开始玩转混元3D⼤模型,如何让一张静态实物图片一键转为3D实物图,大模型都表示服了,超级简单易上手,快来试试!

HAI 与 NVIDIA &#xff0c;为开发者提供一键部署及生图的能力&#xff0c;让开发者体验3D 模型的同时&#xff0c;也了解云的便利性。 混元3D 2.0是腾讯推出的尖端3D⽣成模型&#xff0c;能够创建带有⾼分辨率纹理贴图的⾼保真3D资产 参赛报名&#xff1a;https://marketing.c…

电路图识图基础知识-电动机的保护电路保护方式(二十六)

电动机保护电路是确保电动机安全、可靠运行的关键技术之一。在工业和日常生活中&#xff0c;电动机被广泛应用于各种设备中&#xff0c;其安全运行对于保障生产效率和人身安全至关重要。本文将详细介绍电动机保护电路的重要性、保护方式以及具体的电路分析&#xff0c;以期为电…

【Pandas】pandas DataFrame droplevel

Pandas2.2 DataFrame Reshaping sorting transposing 方法描述DataFrame.droplevel(level[, axis])用于**从 DataFrame 的索引&#xff08;行或列&#xff09;中删除指定层级&#xff08;level&#xff09;**的方法 pandas.DataFrame.droplevel() pandas.DataFrame.droplev…

Delivering Arbitrary-Modal Semantic Segmentation(CVPR2023)任意模态语义分割论文阅读

文章目录 文章研究思路创建了DeLiVER任意模态分割基准数据集统计信息4种模态25个语义类 提出了任意跨模态分割模型CMNeXt自查询中心&#xff08;Self-Query Hub&#xff0c;SQ-Hub&#xff09;并行池化混合器&#xff08;Parallel Pooling Mixer&#xff0c;PPX&#xff09; 实…