基于改进卷积神经网络的足球和运动员追踪系统(部署教程和源码)

1.研究背景与意义

随着计算机视觉和深度学习的快速发展,基于图像和视频的物体追踪技术在各个领域得到了广泛应用。其中,足球和运动员追踪系统在体育竞技中具有重要的意义。传统的追踪方法往往依赖于手工设计的特征和规则,效果受限。而基于深度学习的方法,特别是改进的卷积神经网络(CNN),在目标检测和追踪任务中取得了显著的进展。

足球和运动员追踪系统的研究具有重要的实际意义。首先,对于足球比赛的分析和评估来说,准确追踪球员和球的位置是至关重要的。通过追踪球员的移动轨迹和球的运动轨迹,可以提供更全面的比赛数据,帮助教练和分析师更好地了解比赛的进展和球员的表现。其次,对于球迷来说,能够实时追踪球员和球的位置,可以提供更丰富的观赛体验,增加比赛的趣味性和吸引力。此外,足球和运动员追踪系统还可以应用于视频回放和裁判判罚,提供客观的依据,减少争议。

然而,目前的足球和运动员追踪系统仍然存在一些挑战。首先,由于足球比赛的复杂性和快节奏性,球员之间存在频繁的接触和遮挡,导致追踪算法的准确性和鲁棒性受到影响。其次,传统的追踪方法往往需要大量的人工标注数据和手工设计的特征,不仅耗时耗力,而且泛化能力有限。因此,如何基于改进的卷积神经网络来提高足球和运动员追踪系统的准确性和鲁棒性,成为当前研究的热点和挑战。

本研究旨在基于改进的卷积神经网络,设计和实现一个高效准确的足球和运动员追踪系统,并提供部署教程和源码。具体来说,我们将探索如何利用深度学习技术来提取图像和视频中的特征,并结合目标检测和追踪算法,实现对足球和运动员的准确追踪。我们将采用改进的卷积神经网络结构,如多尺度特征融合、注意力机制和时空建模等,以提高追踪系统的准确性和鲁棒性。

本研究的意义在于提供了一种基于改进的卷积神经网络的足球和运动员追踪系统的解决方案。通过提供部署教程和源码,我们希望能够帮助研究者和开发者更好地理解和应用深度学习技术在足球和运动员追踪领域的优势。此外,我们的研究还可以为足球比赛的分析和评估提供更准确的数据支持,为球迷提供更丰富的观赛体验,同时也可以应用于视频回放和裁判判罚等领域,提供客观的依据。

2.图片演示

2.png
3.png
4.png

3.视频演示

基于改进卷积神经网络的足球和运动员追踪系统(部署教程和源码)_哔哩哔哩_bilibili

4. 单相机多目标跟踪框架

单相机多目标跟踪器以检测器和单目标跟踪器为基础,首先将整个视频分解为多个跟踪周期,每个跟踪周期包含若干帧连续的图像。在每一个跟踪周期中,第一帧进行检测,接下来的几帧进行跟踪,通过数据关联的方式将相邻的两个跟踪周期的结果融合起来,其结构如图所示。


image.png

在每个跟踪周期中,第一帧检测出图像中所有的目标位置,用每个目标的的初始位置初始化跟踪器,在剩余的图片序列中进行一个短时的跟踪,得到每个目标的运动轨迹。下一步就是要将这个图片序列中的所有运动轨迹赋予相应的编号,这是通过数据关联算法来完成的。数据关联算法将上一个周期各个编号目标的运动轨迹与当前周期所有的运动轨迹进行匹配。
这里需要说明的是,在足球场场景中,球员会经常跑出某个相机的视野范围,也就是说会出现目标消失的情况,一般来说需要做重检测的操作,当一个新目标被检测出来时,需要判断它是一个新出现的目标还是一个已经出现过但是在之前消失了的目标。由于足球场场景中的目标极为相似,球员之间的身高,姿态,球衣颜色都有很高的相似度,重检测的难度非常大。所以在单相机多目标跟踪模块中,我们不进行重检测操作,把所有新出现的目标都作为一个新的目标来处理。


image.png

5.核心代码讲解

5.1 improve.py

封装为类后的代码如下:

import torch.nn as nn
......
class GNConv(nn.Module):
    def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):
        super().__init__()
        self.order = order
        self.dims = [dim // 2 ** i for i in range(order)]
        self.dims.reverse()
        self.proj_in = nn.Conv2d(dim, 2 * dim, 1)

        if gflayer is None:
            self.dwconv = get_dwconv(sum(self.dims), 7, True)
        else:
            self.dwconv = gflayer(sum(self.dims), h=h, w=w)

        self.proj_out = nn.Conv2d(dim, dim, 1)

        self.pws = nn.ModuleList(
            [nn.Conv2d(self.dims[i], self.dims[i + 1], 1) for i in range(order - 1)]
        )

        self.scale = s
        print('[gnconv]', order, 'order with dims=', self.dims, 'scale=%.4f' % self.scale)
......

这个类名为GNConv,继承自nn.Module。在__init__方法中,定义了类的属性和各个层的初始化。其中,dim表示输入特征的通道数,order表示GNConv的阶数,gflayer表示自定义的层(如果没有则使用默认的get_dwconv方法),hw表示输入特征的高度和宽度,s表示缩放因子。

在类的初始化过程中,首先计算了dims列表,用于存储每个阶数对应的通道数。然后使用nn.Conv2d初始化了proj_indwconvproj_out三个卷积层。接着使用nn.ModuleList初始化了pws列表,其中每个元素都是一个nn.Conv2d层。

最后,打印了一条初始化信息。

注意:上述代码中的get_dwconv方法没有给出,需要根据实际情况进行定义。

该程序文件名为improve.py,代码主要定义了一个名为gnconv的类。该类继承自nn.Module,用于实现一个改进的卷积操作。

在类的初始化方法中,接收了一些参数,包括dim(输入通道数)、order(卷积的阶数,默认为5)、gflayer(用于生成gflayer的函数,默认为None)、h(输入特征图的高度,默认为14)、w(输入特征图的宽度,默认为8)、s(缩放因子,默认为1.0)。

在初始化方法中,首先根据输入通道数dim计算出每一阶的通道数,然后通过nn.Conv2d定义了一个输入通道数为dim,输出通道数为2 * dim的卷积层self.proj_in。

接下来根据gflayer是否为None来选择不同的卷积层self.dwconv。如果gflayer为None,则通过get_dwconv函数生成一个卷积层,输入通道数为所有阶的通道数之和,卷积核大小为7,使用深度可分离卷积。如果gflayer不为None,则通过gflayer函数生成一个卷积层,输入通道数为所有阶的通道数之和,高度为h,宽度为w。

然后通过nn.Conv2d定义了一个输入通道数为dim,输出通道数为dim的卷积层self.proj_out。

最后通过nn.ModuleList定义了一个包含order-1个卷积层的列表self.pws,每个卷积层的输入通道数为第i阶的通道数,输出通道数为第i+1阶的通道数。

最后打印了一条信息,包括order的值、dims的值和scale的值。

整个程序文件的作用是定义了一个改进的卷积操作gnconv,其中包含了多个卷积层和一些参数。

5.2 Interface.py


class YOLOv5Detector:
    def __init__(self, weights, data, device='', half=False, dnn=False):
        self.weights = weights
        self.data = data
        self.device = device
        self.half = half
        self.dnn = dnn
        self.model = None
        self.stride = None
        self.names = None
        self.pt = None
        self.jit = None
        self.onnx = None
        self.engine = None

    def load_model(self):
        # Load model
        device = select_device(self.device)
        self.model = DetectMultiBackend(self.weights, device=device, dnn=self.dnn, data=self.data)
        self.stride, self.names, self.pt, self.jit, self.onnx, self.engine = (
            self.model.stride, self.model.names, self.model.pt, self.model.jit, self.model.onnx, self.model.engine
        )

        # Half
        half = self.half and (self.pt or self.jit or self.onnx or self.engine) and device.type != 'cpu'
        if self.pt or self.jit:
            self.model.model.half() if half else self.model.model.float()

    def run(self, img, imgsz=(640, 640), conf_thres=0.25, iou_thres=0.45, max_det=1000, classes=None,
            agnostic_nms=False, augment=False):
        cal_detect = []

        device = select_device(self.device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names  # get class names

        # Set Dataloader
        im = letterbox(img, imgsz, self.stride, self.pt)[0]

        # Convert
        im = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
        im = np.ascontiguousarray(im)

        im = torch.from_numpy(im).to(device)
        im = im.half() if self.half else im.float()  # uint8 to fp16/32
        im /= 255  # 0 - 255 to 0.0 - 1.0
        if len(im.shape) == 3:
            im = im[None]  # expand for batch dim

        pred = self.model(im, augment=augment)

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
        # Process detections
        for i, det in enumerate(pred):  # detections per image
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(im.shape[2:], det[:, :4], img.shape).round()

                # Write results
                for *xyxy, conf, cls in reversed(det):
                    c = int(cls)  # integer class
                    label = f'{names[c]}'
                    cal_detect.append([label, xyxy])
        return cal_detect

这个程序文件是一个接口文件,主要用于加载模型并进行目标检测。程序首先导入了所需的库和模块,然后定义了一些常量和全局变量。接下来,程序定义了一个load_model函数,用于加载模型和设置相关参数。然后,程序定义了一个run函数,用于运行目标检测算法并返回检测结果。最后,程序定义了一个detect函数,用于读取图像并调用run函数进行目标检测,然后将检测结果绘制在图像上并显示出来。整个程序的主要功能就是加载模型并进行目标检测。

5.3 torch_utils.py


@contextmanager
def torch_distributed_zero_first(local_rank: int):
    """
    Decorator to make all processes in distributed training wait for each local_master to do something.
    """
    if local_rank not in [-1, 0]:
        dist.barrier(device_ids=[local_rank])
    yield
    if local_rank == 0:
        dist.barrier(device_ids=[0])


def date_modified(path=__file__):
    # return human-readable file modification date, i.e. '2021-3-26'
    t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime)

这个程序文件是一个用于PyTorch的工具文件,主要包含了一些常用的函数和类。下面是文件中的一些主要部分:

  1. 导入了一些需要使用的库和模块,如torch、torchvision、datetime等。
  2. 定义了一个装饰器函数torch_distributed_zero_first,用于在分布式训练中让所有进程等待每个本地主进程执行某些操作。
  3. 定义了一些辅助函数,如date_modified用于返回文件的修改日期,git_describe用于返回git描述信息,select_device用于选择设备,time_sync用于获取准确的时间等。
  4. 定义了一个用于分析模型速度、内存和FLOPs的函数profile
  5. 定义了一些

5.4 train.py


class Trainer:
    def __init__(self, hyp, opt, device, tb_writer=None):
        self.hyp = hyp
        self.opt = opt
        self.device = device
        self.tb_writer = tb_writer
        self.logger = logging.getLogger(__name__)
        self.save_dir = Path(opt.save_dir)
        self.epochs = opt.epochs
        self.batch_size = opt.batch_size
        self.total_batch_size = opt.total_batch_size
        self.weights = opt.weights
        self.rank = opt.global_rank
        self.freeze = opt.freeze
        self.wdir = self.save_dir / 'weights'
        self.wdir.mkdir(parents=True, exist_ok=True)  # make dir
        self.last = self.wdir / 'last.pt'
        self.best = self.wdir / 'best.pt'
        self.results_file = self.save_dir / 'results.txt'
        self.plots = not opt.evolve  # create plots
        self.cuda = device.type != 'cpu'
        self.init_seeds(2 + self.rank)
        with open(opt.data) as f:
            self.data_dict = yaml.load(f, Loader=yaml.SafeLoader)  # data dict
        self.is_coco = opt.data.endswith('coco.yaml')
        self.loggers = {'wandb': None}  # loggers dict
        if self.rank in [-1, 0]:
            self.opt.hyp = self.hyp  # add hyperparameters
            run_id = torch.load(self.weights, map_location=self.device).get('wandb_id') if self.weights.endswith('.pt') and os.path.isfile(self.weights) else None
            wandb_logger = WandbLogger(self.opt, Path(self.opt.save_dir).stem, run_id, self.data_dict)
            self.loggers['wandb'] = wandb_logger.wandb
            self.data_dict = wandb_logger.data_dict
            if wandb_logger.wandb:
                self.weights, self.epochs, self.hyp = self.opt.weights, self.opt.epochs, self.opt.hyp  # WandbLogger might update weights, epochs if resuming
        self.nc = 1 if self.opt.single_cls else int(self.data_dict['nc'])  # number of classes
        self.names = ['item'] if self.opt.single_cls and len(self.data_dict['names']) != 1 else self.data_dict['names']  # class names
        assert len(self.names) == self.nc, '%g names found for nc=%g dataset in %s' % (len(self.names), self.nc, self.opt.data)  # check
        self.pretrained = self.weights.endswith('.pt')
        if self.pretrained:
            with torch_distributed_zero_first(self.rank):
                attempt_download(self.weights)  # download if not found locally
            ckpt = torch.load(self.weights, map_location=self.device)  # load checkpoint
            self.model = Model(self.opt.cfg or ckpt['model'].yaml, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
            exclude = ['anchor'] if (self.opt.cfg or self.hyp.get('anchors')) and not self.opt.resume else []  # exclude keys
            state_dict = ckpt['model'].float().state_dict()  # to FP32
            state_dict = intersect_dicts(state_dict, self.model.state_dict(), exclude=exclude)  # intersect
            self.model.load_state_dict(state_dict, strict=False)  # load
            self.logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(self.model.state_dict()), self.weights))  # report
        else:
            self.model = Model(self.opt.cfg, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
        with torch_distributed_zero_first(self.rank):
            check_dataset(self.data_dict)  # check
        self.train_path = self.data_dict['train']
        self.test_path = self.data_dict['val']
        self.freeze = [f'model.{x}.' for x in (self.freeze if len(self.freeze) > 1 else range(self.freeze[0]))]  # parameter names to freeze (full or partial)
        for k, v in self.model.named_parameters():
            v.requires_grad = True  # train all layers
            if any(x in k for x in self.freeze):
                print('freezing %s' % k)
                v.requires_grad = False
        self.nbs = 64  # nominal batch size
        self.accumulate = max(round(self.nbs / self.total_batch_size), 1)  # accumulate loss before optimizing
        self.hyp['weight_decay'] *= self.total_batch_size * self.accumulate / self.nbs  # scale weight_decay
        self.logger.info(f"Scaled weight_decay = {self.hyp['weight_decay']}")
        self.pg0, self.pg1, self.pg2 = [], [], []  # optimizer parameter groups
        for k, v in self.model.named_modules():
            if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):
                self.pg2.append(v.bias)  # biases
            if isinstance(v, nn.BatchNorm2d):
                self.pg0.append(v.weight)  # no decay
            elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):
                self.pg1.append(v.weight)  # apply decay
            if hasattr(v, 'im'):
                if hasattr(v.im, 'implicit'):           
                    self.pg0.append(v.im.implicit)
                else:
                    for iv in v.im:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imc'):
                if hasattr(v.imc, 'implicit'):           
                    self.pg0.append(v.imc.implicit)
                else:
                    for iv in v.imc:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imb'):
                if hasattr(v.imb, 'implicit'):           
                    self.pg0.append(v.imb.implicit)
                else:
                    for iv in v.imb:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imo'):
                if hasattr(v.imo, 'implicit'):           
                    self

这个程序文件是一个用于训练模型的脚本。它导入了一些必要的库和模块,包括argparse、logging、torch等。它定义了一个train函数,该函数接受一些超参数、选项和设备信息,并进行模型训练。在训练过程中,它会加载预训练模型(如果有的话),设置优化器和学习率调度器,冻结一些参数,创建数据加载器,进行模型训练和评估等操作。最后,它会保存训练结果和日志信息。

5.5 ui.py


class YOLOv5Detector:
    def __init__(self):
        self.model, self.stride, self.names, self.pt, self.jit, self.onnx, self.engine = self.load_model()

    def load_model(self,
            weights=ROOT / 'best.pt',  # model.pt path(s)
            data=ROOT / 'data/coco128.yaml',  # dataset.yaml path
            device='',  # cuda device, i.e. 0 or 0,1,2,3 or cpu
            half=False,  # use FP16 half-precision inference
            dnn=False,  # use OpenCV DNN for ONNX inference
    ):
        # Load model
        device = select_device(device)
        model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data)
        stride, names, pt, jit, onnx, engine = model.stride, model.names, model.pt, model.jit, model.onnx, model.engine

        # Half
        half &= (pt or jit or onnx or engine) and device.type != 'cpu'  # FP16 supported on limited backends with CUDA
        if pt or jit:
            model.model.half() if half else model.model.float()
        return model, stride, names, pt, jit, onnx, engine

    def detect(self, img, imgsz=(640, 640), conf_thres=0.05, iou_thres=0.15, max_det=1000, device='', classes=None, agnostic_nms=False, augment=False, half=False):
        cal_detect = []

        device = select_device(device)
        names = self.model.module.names if hasattr(self.model, 'module') else self.model.names  # get class names

        # Set Dataloader
        im = letterbox(img, imgsz, self.stride, self.pt)[0]

        # Convert
        im = im.transpose((2, 0, 1))[::-1]  # HWC to CHW, BGR to RGB
        im = np.ascontiguousarray(im)

        im = torch.from_numpy(im).to(device)
        im = im.half() if half else im.float()  # uint8 to fp16/32
        im /= 255  # 0 - 255 to 0.0 - 1.0
        if len(im.shape) == 3:
            im = im[None]  # expand for batch dim

        pred = self.model(im, augment=augment)

        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
        # Process detections
        for i, det in enumerate(pred):  # detections per image
            if len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(im.shape[2:], det[:, :4], img.shape).round()

                # Write results

                for *xyxy, conf, cls in reversed(det):
                    c = int(cls)  # integer class
                    label = f'{names[c]}'
                    lbl = names[int(cls)]
                    cal_detect.append([label, xyxy,float(conf)])
        return cal_detect


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1280, 960)
        MainWindow.setStyleSheet("background-image: url(\"./template/carui.png\")")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(168, 60, 800, 71))
        self.label.setAutoFillBackground(False)
        self.label.setStyleSheet("")
        self.label.setFrameShadow(QtWidgets.QFrame.Plain)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.label.setStyleSheet("font-size:50px;font-weight:bold;font-family:SimHei;background:rgba(255,255,255,0);")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
       

这个程序文件是一个基于PyQt5的图形用户界面(GUI)程序,用于实现足球运动员追踪系统。程序主要包括以下几个部分:

  1. 导入所需的模块和库,包括argparse、platform、shutil、time、numpy、cv2、torch等。
  2. 定义了一个load_model函数,用于加载模型。
  3. 定义了一个run函数,用于运行模型进行目标检测。
  4. 定义了一个det_yolov7函数,用于读取视频文件并进行目标检测。
  5. 定义了一个Thread_1类,继承自QThread,用于创建一个线程来执行目标检测。
  6. 定义了一个Ui_MainWindow类,用于创建主窗口和界面布局。
  7. 在if name == "main"中,加载模型并创建一个Qt应用程序,创建主窗口并显示。

该程序主要实现了以下功能:

  • 加载模型并进行目标检测。
  • 通过选择视频文件进行目标检测。
  • 显示检测结果和视频画面。
  • 提供开始检测和退出系统的按钮。

注意:该程序依赖于其他模块和库,需要确保这些模块和库已经安装并正确配置。

6.系统整体结构

该项目包含了多个程序文件,每个文件负责不同的功能模块。主要包括模型定义、训练、目标检测、图形用户界面等。

下面是每个文件的功能概述:

文件路径 功能概述
improve.py 定义了一个改进的卷积操作类
Interface.py 加载模型并进行目标检测的接口文件
torch_utils.py 包含了一些PyTorch的工具函数和类
train.py 用于训练模型的脚本
ui.py 基于PyQt5的图形用户界面(GUI)程序
models\common.py 定义了一些常用的模块和函数,用于目标检测模型
models\experimental.py 包含了一些实验性的模型定义
models\tf.py 包含了一些TensorFlow的模型定义
models\yolo.py 包含了YOLO模型的定义
models_init_.py 模型模块的初始化文件
tools\activations.py 包含了一些激活函数的定义
tools\augmentations.py 包含了一些数据增强的函数
tools\autoanchor.py 包含了自动锚框生成的函数
tools\autobatch.py 包含了自动批处理的函数
tools\callbacks.py 包含了一些回调函数的定义
tools\datasets.py 包含了数据集的定义和处理函数
tools\downloads.py 包含了下载数据集的函数
tools\general.py 包含了一些通用的辅助函数
tools\loss.py 包含了一些损失函数的定义
tools\metrics.py 包含了一些评估指标的定义
tools\plots.py 包含了绘图函数的定义
tools\torch_utils.py 包含了一些PyTorch的辅助函数
tools_init_.py 工具模块的初始化文件
tools\aws\resume.py 包含了AWS上的恢复训练函数
tools\aws_init_.py AWS模块的初始化文件
tools\flask_rest_api\example_request.py 包含了Flask REST API的示例请求
tools\flask_rest_api\restapi.py 包含了Flask REST API的定义
tools\loggers_init_.py 日志记录器模块的初始化文件
tools\loggers\wandb\log_dataset.py 包含了WandB日志记录器的数据集日志函数
tools\loggers\wandb\sweep.py 包含了WandB日志记录器的超参数搜索函数
tools\loggers\wandb\wandb_utils.py 包含了WandB日志记录器的辅助函数
tools\loggers\wandb_init_.py WandB日志记录器模块的初始化文件
utils\activations.py 包含了一些激活函数的定义
utils\augmentations.py 包含了一些数据增强的函数
utils\autoanchor.py 包含了自动锚框生成的函数
utils\autobatch.py 包含了自动批处理的函数
utils\callbacks.py 包含了一些回调函数的定义
utils\datasets.py 包含了数据集的定义和处理函数
utils\downloads.py 包含了下载数据集的函数
utils\general.py 包含了一些通用的辅助函数
utils\loss.py 包含了一些损失函数的定义
utils\metrics.py 包含了一些评估指标的定义
utils\plots.py 包含了绘图函数的定义
utils\torch_utils.py 包含了一些PyTorch的辅助函数
utils_init_.py 工具模块的初始化文件
utils\aws\resume.py 包含了AWS上的恢复训练函数
utils\aws_init_.py AWS模块的初始化文件
utils\flask_rest_api\example_request.py 包含了Flask REST API的示例请求
utils\flask_rest_api\restapi.py 包含了Flask REST API的定义
utils\loggers_init_.py 日志记录器模块的初始化文件
utils\loggers\wandb\log_dataset.py 包含了WandB日志记录器的数据集日志函数
utils\loggers\wandb\sweep.py 包含了WandB日志记录器的超参数搜索函数
utils\loggers\wandb\wandb_utils.py 包含了WandB日志记录器的辅助函数
utils\loggers\wandb_init_.py WandB日志记录器模块的初始化文件

7.引入递归门控卷积(gnConv)

参考该大牛博主的博客,作为当前先进的深度学习目标检测一算法YOLOv5,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv5的如何改进进行详细的介绍,目的是为了给那些搞工程项目的朋友需要达到更好的效果提供自己的微薄帮助和参考。

YOLOv5主干特征提取网络为CNN网络,CNN具有平移不变性和局部性,缺乏全局建模长距离建模的能力,引入自然语言处理领域的框架Transformer来形成CNN+Transformer架构,充分两者的优点,提高目标检测效果,本人经过实验,对小目标以及密集预测任务会有一定的提升效果。视觉Transformers 的最新进展在基于点积self-attention的新空间建模机制驱动的各种任务中取得了巨大成功。递归门控卷积(gnConv),它通过门控卷积和递归设计执行高阶空间交互。新操作具有高度的灵活性和可定制性,它兼容各种卷积变体,并将自注意力中的二阶交互扩展到任意阶,而不会引入大量额外的计算。gnConv可以作为一个即插即用的模块来改进各种视觉Transformer和基于卷积的模型。Transformer方法融合参考YOLOv5改进往期。

image.png

视觉Transformers的最新进展在各种任务中都取得了巨大的成功由基于点积自注意力的新空间建模机制驱动。在本文中,我们展示了愿景变形金刚背后的关键要素,即输入自适应、长程和高阶空间交互,也可以使用基于卷积的框架有效地实现。我们提出递归门控卷积
(gnConv),它通过门控卷积和递归设计执行高阶空间交互。新的操作高度灵活可定制,兼容各种卷积变体并将self-attention中的二阶交互扩展到任意阶,而无需引入大量额外的计算。GnConv可以作为即插即用模块来改进各种视觉变压器和基于卷积的模型。基于该操作,我们构建了一个新的通用视觉骨干家族
命名为HorNet。IlmageNel分类、COCO对象的大量实验检测和ADE20K语义分割显示HorNet优于Swin Transformers和ConvNeXt具有相似的整体架构和训练配置。HorNet 还显示出良好的可扩展性更多的训练数据和更大的模型大小。除了视觉编码器的有效性之外,我们还展示了gnConv可以应用于特定任务的解码器和以更少的计算持续提高密集预测性能。我们的结果表明, gnConv可以成为可视化建模的新基础模块它有效地结合了视觉Transformer 和CNN 的优点

image.png

8.系统整合

下图完整源码&环境部署视频教程&数据集&自定义UI界面

1.png

参考博客《基于改进卷积神经网络的足球和运动员追踪系统(部署教程和源码)》

9.参考文献


[1]黎万义,王鹏,乔红.引入视觉注意机制的目标跟踪方法综述[J].自动化学报.2014,(4).DOI:10.3724/SP.J.1004.2014.00561.

[2]周鑫,钱秋朦,叶永强,等.改进后的TLD视频目标跟踪方法[J].中国图象图形学报.2013,(9).DOI:10.11834/jig.20130908.

[3]明安龙,马华东.多摄像机之间基于区域SIFT描述子的目标匹配[J].计算机学报.2008,(4).DOI:10.3321/j.issn:0254-4164.2008.04.011.

[4]代科学,李国辉,涂丹,等.监控视频运动目标检测减背景技术的研究现状和展望[J].中国图象图形学报.2006,(7).DOI:10.3969/j.issn.1006-8961.2006.07.002.

[5]王爱平.视频目标跟踪技术研究[D].2011.

[6]冈萨雷斯. 数字图像处理 [M].电子工业出版社,2007.

[7]权太范,1949-. 目标跟踪新理论与技术 [M].国防工业出版社,2009.

[8]Henriques, Joao F.,Caseiro, Rui,Martins, Pedro,等.High-Speed Tracking with Kernelized Correlation Filters[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2015,37(3).

[9]He, Kaiming,Zhang, Xiangyu,Ren, Shaoqing,等.Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2015,37(9).1904-1916.

[10]佚名.Preserving Structure in Model-Free Tracking[J].IEEE Transactions on Pattern Analysis & Machine Intelligence.2014,36(4).

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容