用YOLOv8模型实现目标检测、旋转边界框检测、姿势识别、图像分割及视频跟踪

简介

YOLO(you only look once)是一阶段目标检测模型的开山之作,在图像目标检测领域一向以响应速度快著称,它同是兼顾了模型的准确性,在速度与准确性之间做到很好的平衡。经过多版本迭代,到YOLOv8,是一个功能强大,受到广大开发者欢迎与喜爱的目标检测模型,另外,在同一套代码中,它可以分别实现图像分类、目标检测、旋转边界框检测、姿势识别、图像分割,并且在目标检测、旋转边界框检测、姿势识别、图像分割模型基础上实现视频跟踪功能。通过在超参数指定如下参数:

task: segment  可选项:detect, obb, segment, classify, pose,指定任务目标类型

mode: train  可选项:train, val, predict, export, track, benchmark 指定模式

model: # (str, optional) path to model file, i.e. yolov8n.pt, yolov8n.yaml 模型文件路径或模型配置文件路径

data: # (str, optional) path to data file, i.e. coco128.yaml 数据文件路径或数据配置文件路径

YOLOv8网络结构

上图为架构图,图最上面从左到右,包含Backbone(主干), Neck(颈部), Head(头部)三大部分.

Backbone由5个卷积模块,4个C2f模块, 1个SPPF模块组成,激活函数为SiLU。

整个卷积模块的作用为:

1 降采样:每个卷积模块中的卷积层都采用步长为2的卷积核进行降采样操作,以减少特征图的尺寸并增加通道数

2 非线性表示:每个卷积层之后都添加了batch normalization(批标准化)层和激活函数,以增强模型的非线性表示能力

SiLU(Sigmoid-weighted Linear Unit)函数的定义为f(x) = x * sigmoid(x),其中sigmoid(x)表示对x进行sigmoid运算。它是一个将输入值映射到0到1之间的非线性函数,且具有平滑和连续性质。

与ReLU相比,SiLU在保持非线性特性的同时,具有类似于Sigmoid函数的非饱和性、平滑性、梯度饱和性较低等优点。这些特性使得SiLU函数能够更好地处理梯度问题,并且在某些深度学习任务中可以取得更好的性能。在一些实验中,SiLU被证明可以提供更高的模型准确性和更快的收敛速度。

batch normalization的基本思想是:对每个小批量数据进行标准化,使得每个特征的均值为0,方差为1,然后再通过一个可学习的缩放因子和平移因子来调整数据的分布,从而使得神经网络更容易训练。

在YOLOv8的网络结构中C2f模块算是YOLOv8的一个较大改变,与YOLOv5的C3模块相比,C2f模块具有更少的参数量和更优秀的特征提取能力。下图为C2f结构图:

在C2f模块中我们可以看到,输入首先经过一个k=1,s=1, p=0, c=c_out的卷积模块进行了处理,然后经过一个split处理(在这里split和后面的concat的组成其实就是所谓的残差模块处理)经过数量为n的DarknetBottleneck模块处理以后将残差模块和主干模块的结果进行Concat拼接在经过一个卷积模块处理进行输出。

在其中提到的残差连接(residual connections)是一种用于构建深层神经网络的技术,它的核心思想是通过跳过层级连接来传递残差或误差。

在传统的神经网络中,信息流通过一层层的网络层,每一层都通过非线性激活函数进行转换和提取特征,然而,随着神经网络的加深,可能会出现“梯度消失”或“梯度爆炸”的问题,导致网络收敛困难或性能下降

残差连接通过引入跨层级的连接,将输入的原始信息直接传递到后续层级,以解决梯度消失和爆炸问题。具体而言,它将网络的输入与中间层的输出相加,形成了一个“捷径”或“跳跃连接”,从而允许梯度更容易地传播。

数学上,假设我们有一个输入x,通过多个网络层进行处理后得到预测值H(x),那么残差连接的表达式为:

F(x)=H(x)+x

其中,F(x)为残差块的输出, H(x)为经过一系列网络层处理后得到的特征表示,x为输入直接连接到残差块中的跳跃连接。

通过残差连接,网络可以更容易地学习残差或误差,从而使网络更深层次的特征表达更准确,这对于训练深层神经网络非常有用,可以提高网络的性能和收敛速度。

在C2f模块中用到的DarknetBottleneck模块其中使用多个3x3卷积核进行卷积操作,提取特征信息,同时其具有add是否进行残差链接的选项

其实整个C2f模块就是一个改良版本的Darknet

1首先,使用1x1卷积核将输入通道减少到原来的1/2,以减少计算量和内存消耗

2 然后,使用多个3x3卷积核进行卷积操作,提取特征信息

3 接着,使用残差链接,将输入直接加到输出中,从而形成了一条跨层连接

4 接着,再次使用1x1卷积核恢复特征图的通道数。

Neck部分的整体功能的详细分析如下:

1Neck的作用:

Neck部分在YOLOv8模型中负责对来自Backbone的特征进行进一步处理和融合,以提高目标检测的准确性和鲁棒性,它通过引入不同的结构和技术,将多尺度的特征图进行融合,以便更好地捕捉不同尺度目标的信息。

2 特征金字塔网络(Feature Pyramid Network, FPN):

3 特征融合(Feature Fusion):

4 上采样和下采样

YOLOv8的Neck部分通过特征金字塔网络和特征融合等操作,有效地提取和融合多尺度的特征,从而提高了目标检测的性能和鲁棒性,这使得模型能够更好地适应不同尺度和大小的目标,并在复杂场景下取得更准确的检测结果

PAN-FPN(具有特征金字塔网络的路径聚合网络)是一种用于计算机视觉中对象检测的神经网络架构。它将特征金字塔网络(FPN)与路径聚合网络(PAN)相结合,以提高目标检测的准确性和效率。

FPN用于从不同比例的图像中提取特征,而PAN用于跨网络的不同层聚合这些特征,这允许网络检测不同大小和分辨率的对象,并处理具有多个对象的复杂场景。

Head

如果Backone和Neck部分可以理解为准备工作,那么Head部分就是收获的部分,经过前面的准备工作我们得到了Neck部分的输出T1、T2、T3分别代表不同层级的特征图,Head部分就是对这三个特征图进行处理以产生模型的输出结果的一个过程。

在YOLOv8的Head部分,体现了最核心的改动-解耦头(Decoupled-Head),顾名思义就是将原先的一个检测头分解成两个部分。

在Head部分的三个解耦头分别对应着Neck部分的特征图输出T1、T2、T3.

解耦头的工作流程是

将网络得到的特征图T1、T2、T3分别输入解耦头进行,检测头的结构其中包含4个3x3卷积与2个1x1卷积,同时在检测头的回归分支中添加WIOU损失函数,回归头部需要计算预测框与真实框之间的位置偏移量,然后将偏移量送入回归头部进行损失计算,然后输出一个四维向量,分别表示目标框左上角坐标x y和右下角坐标x y.

分类头部针对每个anchor free提取的候选框对其进行Rol Pooling和卷积操作得到一个分类器输出张量每个位置上的值表示该候选框属于每个类别的概率,在最后通过非极大值抑制方式筛选出最终的检测结果。

本机训练、预测

1 训练:

代码如下:

from ultralytics import YOLO

# Load a model

model = YOLO("yolov8n.yaml")  # build a new model from YAML

model = YOLO("yolov8n.pt")  # load a pretrained model (recommended for training)

model = YOLO("yolov8n.yaml").load("yolov8n.pt")  # build from YAML and transfer weights

# Train the model

results = model.train(data="coco8.yaml", epochs=100, imgsz=640)

在上述训练代码中,构建模型方式有三种:用模型配置文件、用模型文件或用模型配置文件加模型文件。在训练的时候指定数据配置文件。

在多GPU情况下,上面训练行代码可改用下面代码指定GPU:

# Train the model with 2 GPUs

results = model.train(data="coco8.yaml", epochs=100, imgsz=640, device=[0, 1])

如果训练任务是检测姿势关键点位置,在这里的results中会返回关键点坐标,当需要模型自动确认关键点坐标指明的是什么动作,在提示标注训练数据的时候,图像不仅要标注关键点坐标,还要标注同一个目标的关键点对应的动作名称,在获得results 返回后,需要用一个图像分类模型,以关键点坐标及标注的动作名称作为训练集进行动作分类训练,就是要训练姿势识别与动作分类两个模型。

  1. 推理:

代码如下:

from ultralytics import YOLO

# Load a model

model = YOLO("yolov8n.pt")  # pretrained YOLOv8n model

# Run batched inference on a list of images

results = model(["im1.jpg", "im2.jpg"], stream=True)  # return a generator of Results objects

# Process results generator

for result in results:

    boxes = result.boxes  # Boxes object for bounding box outputs

    masks = result.masks  # Masks object for segmentation masks outputs

    keypoints = result.keypoints  # Keypoints object for pose outputs

    probs = result.probs  # Probs object for classification outputs

    obb = result.obb  # Oriented boxes object for OBB outputs

    result.show()  # display to screen

result.save(filename="result.jpg")  # save to disk

在这里,预测结果在results中返回,包含:检测框点的坐标、图像分割掩码、姿势识别关键点坐标、目标所属分类置信度、旋转边界框检测结果等。如果要在图片上标注预测结果信息,可以用如下代码:

from ultralytics import YOLO

# Load a pretrained YOLOv8n model

model = YOLO("yolov8n.pt")

# Run inference on 'bus.jpg' with arguments

model.predict("bus.jpg", save=True, imgsz=320, conf=0.5)

如果训练任务是检测姿势关键点位置,在上面获取到目标的关键点坐标数据后,还要以这些数据作为测试集,调用前面提到的动作分类模型,以识别姿势分类。

  1. 导出指定格式

YOLO模型训练默认保存为.pt格式,可以通过导出成指定格式文件。常用的导出文件格式有:ONNX:全称为Open Neural Network Exchange,主要目的是促进不同深度学习框架之间的互操作性,使得AI模型能够在不同的环境和平台之间无缝迁移和部署。格式参数:onnx, 其他参数:imgsz, half, dynamic, simplify, opset, batch

TensorRT:用于在推理时候用TensorRT引擎加速,格式参数:engine, 其他参数:imgsz, half, dynamic, simplify, workspace, int8, batch

CoreML:用于IOS移动端应用,格式参数:coreml, 其他参数:imgsz, half, int8, nms, batch

TF Lite:用于安卓移动端应用,格式参数:tflite, 其他参数:imgsz, half, int8, batch

导出代码如下(ONNX):

from ultralytics import YOLO

# Load a model

model = YOLO("yolov8n.pt")  # load an official model

model = YOLO("path/to/best.pt")  # load a custom trained model

# Export the model

model.export(format="onnx", int8=True)

  1. 视频跟踪

代码如下:

from ultralytics import YOLO

# Load an official or custom model

model = YOLO("yolov8n.pt")  # Load an official Detect model

model = YOLO("yolov8n-seg.pt")  # Load an official Segment model

model = YOLO("yolov8n-pose.pt")  # Load an official Pose model

model = YOLO("path/to/best.pt")  # Load a custom trained model

# Perform tracking with the model

results = model.track("https://youtu.be/LNwODJXcvt4", show=True)  # Tracking with default tracker

results = model.track("https://youtu.be/LNwODJXcvt4", show=True, tracker="bytetrack.yaml")  # with ByteTrack

在上面,需要选择自己的模型文件构建模型。在跟踪时候,需要指定视频文件地址,还可以指定跟踪配置文件,有两种目标跟踪算法:botsort, bytetrack,默认是botsort。

botsort:一种基于Boosting的目标跟踪算法。它首先对每个帧进行目标检测,然后通过一个基于Boosting的目标跟踪器来跟踪目标。BoT-SORT的目标跟踪器采用了一个新的目标级联框架,可以有效地解决目标丢失问题。同时,BoT-SORT还提出了一种新的目标级联分配策略,可以在目标丢失的情况下快速重新分配目标。此外,BoT-SORT还采用了一个新的目标级联更新策略,可以实时地更新目标级联,从而提高跟踪精度。

bytetrack:一种基于tracking-by-detection范式的目标跟踪算法。它首先在视频中检测出目标对象,然后通过关联和重定位技术来跟踪目标对象。ByteTrack通过引入一个新的目标级联框架,将目标检测和跟踪问题转化为一个目标级联问题,从而有效地解决了目标跟踪中的目标丢失问题。同时,ByteTrack还提出了一种新的目标级联分配策略,可以在目标丢失的情况下快速重新分配目标。

ByteTrack和BoT-SORT都采用了目标级联框架来解决目标丢失问题,但ByteTrack采用的是目标级联分配策略,而BoT-SORT采用的是目标级联更新策略。两者都取得了很好的效果,并在许多实际应用中得到了验证。

model.track()函数可以指定检测框最大置信度(conf)、过滤重复检测框交并比(iou),如下:

results = model.track(source="https://youtu.be/LNwODJXcvt4", conf=0.3, iou=0.5, show=True,racker="bytetrack.yaml")

model.track()函数返回一个列表,列表中每个元素中包含boxs列表属性,boxs元素中有id,是目标跟踪id,用于在不同帧之间确定是否相同的目标。

详情可参考YOLOv8官方操作文档:https://docs.ultralytics.com/usage/python/

基于YOLOv8进行动作识别的步骤如下: 1. 准备数据集:收集包含不同动作的视频或图像序列,并进行标注,标注每个动作的起始和结束帧。 2. 数据预处理:将视频或图像序列转换为适合YOLOv8模型输入的格式。可以使用OpenCV等库进行视频帧的提取和图像的预处理,例如调整大小、裁剪等。 3. 训练YOLOv8模型:使用标注好的数据集训练YOLOv8模型。可以使用已有的YOLOv8实现,如YOLOv5,或自己实现YOLOv8模型。 4. 模型调优:根据实际情况,对训练好的模型进行调优,例如调整超参数、增加训练数据等。 5. 动作识别:使用训练好的YOLOv8模型进行动作识别。将视频或图像序列输入模型模型会输出每个帧中检测到的动作类别和位置。 6. 后处理:根据需要,对模型输出进行后处理,例如滤除重复的检测结果、根据动作的起始和结束帧进行动作的识别等。 7. 可视化结果:将识别结果可视化,可以在视频或图像上标注出检测到的动作。 下面是一个基于YOLOv8进行动作识别的示例代码: ```python # 导入相关库 import cv2 import numpy as np # 加载YOLOv8模型 net = cv2.dnn.readNetFromDarknet('yolov8.cfg', 'yolov8.weights') # 加载类别标签 classes = [] with open('coco.names', 'r') as f: classes = [line.strip() for line in f.readlines()] # 加载视频 cap = cv2.VideoCapture('video.mp4') while True: # 读取视频帧 ret, frame = cap.read() if not ret: break # 将帧转换为blob格式 blob = cv2.dnn.blobFromImage(frame, 1/255, (416, 416), (0, 0, 0), True, crop=False) # 设置模型输入 net.setInput(blob) # 前向传播 outs = net.forward() # 解析模型输出 class_ids = [] confidences = [] boxes = [] for out in outs: for detection in out: scores = detection[5:] class_id = np.argmax(scores) confidence = scores[class_id] if confidence > 0.5: center_x = int(detection[0] * frame.shape[1]) center_y = int(detection[1] * frame.shape[0]) width = int(detection[2] * frame.shape[1]) height = int(detection[3] * frame.shape[0]) left = int(center_x - width / 2) top = int(center_y - height / 2) class_ids.append(class_id) confidences.append(float(confidence)) boxes.append([left, top, width, height]) # 非最大抑制 indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4) # 绘制检测结果 for i in indices: i = i[0] box = boxes[i] left = box[0] top = box[1] width = box[2] height = box[3] cv2.rectangle(frame, (left, top), (left + width, top + height), (0, 255, 0), 2) cv2.putText(frame, classes[class_ids[i]], (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) # 显示结果 cv2.imshow('Action Recognition', frame) if cv2.waitKey(1) == ord('q'): break # 释放资源 cap.release() cv2.destroyAllWindows() ``` 请注意,上述代码仅为示例,实际使用时需要根据自己的数据集和模型进行相应的修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值