YOLOv8目标检测

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


提示:以下是本篇文章正文内容,下面案例可供参考

一、准备工作

1.新建一个文件夹yolov8(可以自定义命名),在文件夹下再创一个dataset文件夹

2.在dataset下新建两个文件夹 labels 以及 images

images:用于存放要标注的图片(jpg格式)

labels :用于存放标注图片后产生的内容(这里采用YOLO格式)

dataset(文件名可自定义)
–images
----train(训练集)
----val(验证集)
–labels
----train(训练集标签文件)
----val(存验证集标签文件)

标签文件和训练用的图片名称一一对应。

3.准备一个视频chezi.mp4

1)图片类型数据:可以直接使用
2)视频类型数据:利用opencv进行视频抽帧

import cv2
import os

#此删除文件夹内容的函数来源于网上
def del_file(filepath):
    """
    删除某一目录下的所有文件或文件夹
    :param filepath: 路径
    :return:
    """
    del_list = os.listdir(filepath)
    for f in del_list:
        file_path = os.path.join(filepath, f)
        if os.path.isfile(file_path):
            os.remove(file_path)

def video_to_images(fps,path):
  cv = cv2.VideoCapture(path)
  if(not cv.isOpened()):
    print("\n打开视频失败!请检查视频路径是否正确\n")
    exit(0)
  if not os.path.exists("images2/"):
    os.mkdir("images2/") # 创建文件夹
  else:
    del_file('images2/') # 清空文件夹
  order = 0   #序号
  h = 0
  while True:
    h=h+1
    rval, frame = cv.read()
    if h == fps:
      h = 0
      order = order + 1
      if rval:
        cv2.imwrite('./images2/' + str(order) + '.jpg', frame) #图片保存位置以及命名方式
        cv2.waitKey(1)
      else:
        break
  cv.release()
  print('\nsave success!\n')

# 参数设置
fps = 6   # 隔多少帧取一张图  1表示全部取
path="chezi.mp4" # 视频路径 

if __name__ == '__main__':
  video_to_images(fps,path)
  

代码可以直接复制但是要修改目录地址

运行完是这样的,我们可以修改代码的fps的值来修改多少帧取一张图,这样可以决定张数,我这边是两百多张,全部复制粘贴到dataset/images/train目录下方便我们标注


二、使用labelImg标注图片

1. 安装labellmg

labelImg下载:在终端pip install labelimg下载就行

也可以去网上下载别人打包好的,网上有人打包好了此软件,可以自行去下载。

2. 使用labellmg

打开labelimg直接在终端输入labelimg然后回车

下载了别人打包好的软件也可以去labelimg的目录栏进入cmd输入

python labelImg.py   #运行软件

进入labelimg之后点击左上角的View勾选 auto save mode 自动保存

打开的目录选择我们刚刚用代码截取的图片位置images/train

存放目录选择labels/train

格式选择YOLO格式


三、训练模型

1.准备工作

打开我们创建的yolov5文件夹

在文件夹下再创一个data文件夹,并且在文件夹下创一个coco128.yaml文件

打开文件输入

train: C:\Users\XDL\Desktop\yolov5\dataset\images\train 
val: C:\Users\XDL\Desktop\yolov5\dataset\images\val 
# Classes
nc: 17
names: ['dog', 'person', 'cat', 'tv', 'car', 'meatballs', 'marinara sauce', 'tomato soup', 'chicken noodle soup', 'french onion soup', 'chicken breast', 'ribs', 'pulled pork', 'hamburger', 'cavity', 'car', 'people']

看一下图片具体怎么操作的。

2.训练模型代码

在yolov5目录下创建demo.py文件具体代码如下:

import os
from ultralytics import YOLO

def list_files(directory, file_extension):
    return [f for f in os.listdir(directory) if f.endswith(file_extension)]

def check_empty_labels(path):
    empty_files = []
    for file in os.listdir(path):
        if file.endswith('.txt'):
            file_path = os.path.join(path, file)
            if os.path.getsize(file_path) == 0:
                empty_files.append(file)
    return empty_files

# 删除缓存文件
cache_train = r'C:\Users\XDL\Desktop\yolov5\dataset\labels\train.cache'
cache_val = r'C:\Users\XDL\Desktop\yolov5\dataset\labels\val.cache'

if os.path.exists(cache_train):
    os.remove(cache_train)
if os.path.exists(cache_val):
    os.remove(cache_val)

# 打印数据集配置以确认加载
data_config = r'C:/Users/XDL/Desktop/yolov5/data/coco128.yaml'
print(f"使用的数据集配置文件: {data_config}")

# 确认数据集文件存在
train_images_path = r'C:\Users\XDL\Desktop\yolov5\dataset\images\train'
val_images_path = r'C:\Users\XDL\Desktop\yolov5\dataset\images\val'
train_labels_path = r'C:\Users\XDL\Desktop\yolov5\dataset\labels\train'
val_labels_path = r'C:\Users\XDL\Desktop\yolov5\dataset\labels\val'

print(f"训练图像目录内容: {list_files(train_images_path, '.jpg')[:5]} ...")
print(f"验证图像目录内容: {list_files(val_images_path, '.jpg')[:5]} ...")
print(f"训练标签目录内容: {list_files(train_labels_path, '.txt')[:5]} ...")
print(f"验证标签目录内容: {list_files(val_labels_path, '.txt')[:5]} ...")

# 检查是否存在空标签文件
train_empty_labels = check_empty_labels(train_labels_path)
val_empty_labels = check_empty_labels(val_labels_path)

if train_empty_labels:
    print(f"训练集中的空标签文件: {train_empty_labels}")
if val_empty_labels:
    print(f"验证集中的空标签文件: {val_empty_labels}")

# 进一步检查标签文件内容
def check_label_file_content(path):
    for file in os.listdir(path):
        if file.endswith('.txt'):
            file_path = os.path.join(path, file)
            with open(file_path, 'r') as f:
                content = f.read().strip()
                if content:
                    lines = content.split('\n')
                    for line in lines:
                        parts = line.split()
                        if len(parts) != 5:
                            print(f"{file} 格式不正确: {line}")

print("检查训练集标签文件内容...")
check_label_file_content(train_labels_path)
print("检查验证集标签文件内容...")
check_label_file_content(val_labels_path)

# 确认数据集配置文件内容
with open(data_config, 'r') as f:
    config_content = f.read()
    print(f"数据集配置文件内容:\n{config_content}")

# 加载模型
model = YOLO('yolov5su.pt')

# 训练模型
print("开始训练模型...")
try:
    model.train(data=data_config, epochs=100)
    print("模型训练完成。")
except Exception as e:
    print(f"模型训练过程中出错: {e}")

注意文件夹的目录位置改成自己的目录位置不然报错。

经过了高达十个小时的训练时间也是终于训练好了属于自己的模型!

训练得到了一个runs的文件我们的训练模型在runs/detect/train/weights/best.pt


四、YOLOv8 目标追踪

1、代码解析

第一步

导入模块部分
  • 导入了与 PySide6 相关的模块用于界面开发,以及 cv2 用于图像处理,time 等其他相关模块。
from PySide6 import QtWidgets, QtCore, QtGui
import cv2, os, time
from threading import Thread
from PySide6.QtWidgets import QMainWindow, QFileDialog

# 不然每次运行都会打印一些信息
os.environ['YOLO_VERBOSE'] = 'False'
from ultralytics import YOLO
定义 MWindow 类部分
  • __init__ 方法:进行界面的初始化设置,包括创建各种控件、布局,以及加载模型、设置定时器等操作。
  1. 定义了界面的整体布局,包括图像展示区域和按钮区域。
  2. 启动了处理视频帧的独立线程。
  3. 定义了与摄像头和视频文件相关的操作和定时器。

代码加载YOLO模型的部分就是用到了我们自己训练的训练模型!!

 def __init__(self):
        super().__init__()

        # 设置界面
        self.UI()

        # 视频按钮的点击 
        self.sx.clicked.connect(self.sx_clicked)
        self.tz.clicked.connect(self.stop)
        self.sp.clicked.connect(self.sp_button)

        # 定义定时器,用于控制显示视频的帧率
        self.timer_camera = QtCore.QTimer()
        # 定时到了,回调self.show_camera()函数
        self.timer_camera.timeout.connect(self.show_camera)

        #加载 YOLO nano 模型
        self.model = YOLO('best.pt')

        # 要处理的视频帧图片队列,目前就放1帧图片
        self.frameToAnalyze = []

        #启动处理视频帧独立线程
        Thread(target=self.frameAnalyeThreadFunc,daemon=True).start()
        
        # 定义定时器,用于控制显示视频文件的帧率
        self.timer_videoFile = QtCore.QTimer()
        
        # 定时到了,回调 self.show_camera
        self.timer_videoFile.timeout.connect(self.show_videoFile)

        # 当前要播放的视频帧号
        self.vframeIdx = 0

        # cv2.VideoCapture 实例
        self.cap = None

        self.stopFlag = False
  • UI 方法:具体构建界面的布局和控件。
def UI(self):
        self.resize(1000, 800)
        self.setWindowTitle('yolov8 目标追踪')

        # central Widget
        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)

        # central Widget 里面的 主 layout
        mainLayout = QtWidgets.QVBoxLayout(centralWidget)

        # 界面的上半部分 : 图像展示部分
        topLayout = QtWidgets.QHBoxLayout()# QHBoxLayout:水平布局 QVBoxLayout:垂直布局
        self.label_ori_video = QtWidgets.QLabel(self)
        self.label_treated = QtWidgets.QLabel(self)
        self.label_ori_video.setMinimumSize(700, 700)
        self.label_treated.setMinimumSize(700, 700)
        self.label_ori_video.setStyleSheet('border:1px solid #1d649c')
        self.label_treated.setStyleSheet('border:1px solid #1d649c')

        # 保持原始分辨率
        self.label_ori_video.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
        self.label_ori_video.setScaledContents(True)
        self.label_treated.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
        self.label_treated.setScaledContents(True)
        
        topLayout.addWidget(self.label_ori_video)
        topLayout.addWidget(self.label_treated)

        mainLayout.addLayout(topLayout)

        # 界面下半部分:按钮
        groupBox = QtWidgets.QGroupBox('按钮')
        bottomLayout = QtWidgets.QHBoxLayout(groupBox)
        mainLayout.addWidget(groupBox)

        btnLayout = QtWidgets.QHBoxLayout()# 按钮垂直布局
        self.sp = QtWidgets.QPushButton('🎞️视频文件')
        self.sx = QtWidgets.QPushButton('📹摄像头')
        self.tz = QtWidgets.QPushButton('🛑停止')
        btnLayout.addWidget(self.sp)
        btnLayout.addWidget(self.sx)
        btnLayout.addWidget(self.tz)
        
        bottomLayout.addLayout(btnLayout)
  • sx_clicked 方法:处理摄像头按钮的点击事件,打开摄像头并启动相关定时器。
# 摄像头按钮
    def sx_clicked(self):
        self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        if not self.cap.isOpened():
            print('1号摄像头打开失败')
            return
        if self.timer_camera.isActive() == False:# 如果定时器未启动
            self.timer_camera.start(30)  # 启动定时器,计时时间是16ms,约为60帧每秒
            self.stopFlag = False
  • show_camera 方法:显示从摄像头读取的视频帧。
 def show_camera(self):
        ret, frame = self.cap.read() # 从视频中读取
        if not ret:
            return

        self.setFrameToOriLabel(frame)
  • setFrameToOriLabel 方法:将视频帧转换为合适的格式并显示在相应的标签上。
 def setFrameToOriLabel(self,frame):

        # 视频色彩转换回RGB,OpenCV images as BGR
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        qImage = QtGui.QImage(frame.data, frame.shape[1], frame.shape[0], 
                              QtGui.QImage.Format_RGB888)# 变成QImage格式
        # 往显示视频的Label里显示QImage
        self.label_ori_video.setPixmap(QtGui.QPixmap.fromImage(qImage))# 显示视频

        # 如果当前没有处理任务
        if not self.frameToAnalyze:
            self.frameToAnalyze.append(frame)
    
  • frameAnalyeThreadFunc 方法:在独立线程中处理视频帧的分析任务。
 def frameAnalyeThreadFunc(self):
        while True:
            if not self.frameToAnalyze: 
                continue
            frame = self.frameToAnalyze.pop(0)

            results = self.model(frame)[0]

            img = results.plot(line_width=1)
            # img = results.plot(line_width=1, font='')

            qImage = QtGui.QImage(img.data, img.shape[1], img.shape[0], 
                                QtGui.QImage.Format_RGB888)# 变成QImage格式
            
            self.label_treated.setPixmap(QtGui.QPixmap.fromImage(qImage))# 往显示Label里显示QImage
  • stop 方法:停止相关操作,释放资源。
 def stop(self,):
        self.stopFlag = True      # 让 frameAnalyzeThreadFunc 不要再设置 label_treated
        self.timer_camera.stop()  # 关闭定时器
        self.timer_videoFile.stop()  # 关闭定时器

        if self.cap:
            self.cap.release()  # 释放视频流

        # 清空视频显示区域 
        self.label_ori_video.clear()        
        self.label_treated.clear()

        # # 延时500ms清除,有的定时器处理任务可能会在当前时间点后处理完最后一帧
        # QtCore.QTimer.singleShot(500, clearLabels)
  • sp_button 方法:处理选择视频文件的按钮点击事件。
def sp_button(self):

        # 先关闭原来打开的
        self.stop()

        videoPath, _  = QtWidgets.QFileDialog.getOpenFileName(
            self,             # 父窗口对象
            "选择视频文件",        # 标题
            "../../作业/图片标注/图片标注6",               # 起始目录
            "视频文件 (*.mp4 *.avi)" # 选择类型过滤项,过滤内容在括号中
        )

        print('videoPath is', videoPath)
        if not videoPath:
            return

        self.cap = cv2.VideoCapture(videoPath)
        if not self.cap.isOpened():
            print("打开文件失败")
            return

        self.timer_videoFile.start(30)  # 设置时间间隔为16ms,约为60帧每秒
        self.stopFlag = False

        print("ok")
  • show_videoFile 方法:显示视频文件中的视频帧。
 def show_videoFile(self):
        # 选取视频帧位置,
        self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.vframeIdx)  
        self.vframeIdx += 1
        ret, frame = self.cap.read()  # 从视频流中读取

        # 读取失败,应该是视频播放结束了
        if not ret: 
            self.stop()
            return

        self.setFrameToOriLabel(frame)
主程序部分
  • 创建应用程序实例,创建 MWindow 对象并显示窗口,最后执行应用程序的主循环。
app = QtWidgets.QApplication()
window = MWindow()
window.show()
app.exec()
2、全部代码
from PySide6 import QtWidgets, QtCore, QtGui
import cv2, os, time
from threading import Thread
from PySide6.QtWidgets import QMainWindow, QFileDialog

# 不然每次运行都会打印一些信息
os.environ['YOLO_VERBOSE'] = 'False'
from ultralytics import YOLO

class MWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # 设置界面
        self.UI()

        # 视频按钮的点击 
        self.sx.clicked.connect(self.sx_clicked)
        self.tz.clicked.connect(self.stop)
        self.sp.clicked.connect(self.sp_button)

        # 定义定时器,用于控制显示视频的帧率
        self.timer_camera = QtCore.QTimer()
        # 定时到了,回调self.show_camera()函数
        self.timer_camera.timeout.connect(self.show_camera)

        #加载 YOLO nano 模型
        self.model = YOLO('best.pt')

        # 要处理的视频帧图片队列,目前就放1帧图片
        self.frameToAnalyze = []

        #启动处理视频帧独立线程
        Thread(target=self.frameAnalyeThreadFunc,daemon=True).start()
        
        # 定义定时器,用于控制显示视频文件的帧率
        self.timer_videoFile = QtCore.QTimer()
        
        # 定时到了,回调 self.show_camera
        self.timer_videoFile.timeout.connect(self.show_videoFile)

        # 当前要播放的视频帧号
        self.vframeIdx = 0

        # cv2.VideoCapture 实例
        self.cap = None

        self.stopFlag = False

    def UI(self):
        self.resize(1000, 800)
        self.setWindowTitle('yolov8 目标追踪')

        # central Widget
        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)

        # central Widget 里面的 主 layout
        mainLayout = QtWidgets.QVBoxLayout(centralWidget)

        # 界面的上半部分 : 图像展示部分
        topLayout = QtWidgets.QHBoxLayout()# QHBoxLayout:水平布局 QVBoxLayout:垂直布局
        self.label_ori_video = QtWidgets.QLabel(self)
        self.label_treated = QtWidgets.QLabel(self)
        self.label_ori_video.setMinimumSize(700, 700)
        self.label_treated.setMinimumSize(700, 700)
        self.label_ori_video.setStyleSheet('border:1px solid #1d649c')
        self.label_treated.setStyleSheet('border:1px solid #1d649c')

        # 保持原始分辨率
        self.label_ori_video.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
        self.label_ori_video.setScaledContents(True)
        self.label_treated.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
        self.label_treated.setScaledContents(True)
        
        topLayout.addWidget(self.label_ori_video)
        topLayout.addWidget(self.label_treated)

        mainLayout.addLayout(topLayout)

        # 界面下半部分:按钮
        groupBox = QtWidgets.QGroupBox('按钮')
        bottomLayout = QtWidgets.QHBoxLayout(groupBox)
        mainLayout.addWidget(groupBox)

        btnLayout = QtWidgets.QHBoxLayout()# 按钮垂直布局
        self.sp = QtWidgets.QPushButton('🎞️视频文件')
        self.sx = QtWidgets.QPushButton('📹摄像头')
        self.tz = QtWidgets.QPushButton('🛑停止')
        btnLayout.addWidget(self.sp)
        btnLayout.addWidget(self.sx)
        btnLayout.addWidget(self.tz)
        
        bottomLayout.addLayout(btnLayout)

    # 摄像头按钮
    def sx_clicked(self):
        self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        if not self.cap.isOpened():
            print('1号摄像头打开失败')
            return
        if self.timer_camera.isActive() == False:# 如果定时器未启动
            self.timer_camera.start(30)  # 启动定时器,计时时间是16ms,约为60帧每秒
            self.stopFlag = False

    def show_camera(self):
        ret, frame = self.cap.read() # 从视频中读取
        if not ret:
            return

        self.setFrameToOriLabel(frame)

    def setFrameToOriLabel(self,frame):

        # 视频色彩转换回RGB,OpenCV images as BGR
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        qImage = QtGui.QImage(frame.data, frame.shape[1], frame.shape[0], 
                              QtGui.QImage.Format_RGB888)# 变成QImage格式
        # 往显示视频的Label里显示QImage
        self.label_ori_video.setPixmap(QtGui.QPixmap.fromImage(qImage))# 显示视频

        # 如果当前没有处理任务
        if not self.frameToAnalyze:
            self.frameToAnalyze.append(frame)
    
    def frameAnalyeThreadFunc(self):
        while True:
            if not self.frameToAnalyze: 
                continue
            frame = self.frameToAnalyze.pop(0)

            results = self.model(frame)[0]

            img = results.plot(line_width=1)
            # img = results.plot(line_width=1, font='')

            qImage = QtGui.QImage(img.data, img.shape[1], img.shape[0], 
                                QtGui.QImage.Format_RGB888)# 变成QImage格式
            
            self.label_treated.setPixmap(QtGui.QPixmap.fromImage(qImage))# 往显示Label里显示QImage
    
    def stop(self,):
        self.stopFlag = True      # 让 frameAnalyzeThreadFunc 不要再设置 label_treated
        self.timer_camera.stop()  # 关闭定时器
        self.timer_videoFile.stop()  # 关闭定时器

        if self.cap:
            self.cap.release()  # 释放视频流

        # 清空视频显示区域 
        self.label_ori_video.clear()        
        self.label_treated.clear()

        # # 延时500ms清除,有的定时器处理任务可能会在当前时间点后处理完最后一帧
        # QtCore.QTimer.singleShot(500, clearLabels)

    def sp_button(self):

        # 先关闭原来打开的
        self.stop()

        videoPath, _  = QtWidgets.QFileDialog.getOpenFileName(
            self,             # 父窗口对象
            "选择视频文件",        # 标题
            "../../作业/图片标注/图片标注6",               # 起始目录
            "视频文件 (*.mp4 *.avi)" # 选择类型过滤项,过滤内容在括号中
        )

        print('videoPath is', videoPath)
        if not videoPath:
            return

        self.cap = cv2.VideoCapture(videoPath)
        if not self.cap.isOpened():
            print("打开文件失败")
            return

        self.timer_videoFile.start(30)  # 设置时间间隔为16ms,约为60帧每秒
        self.stopFlag = False

        print("ok")

    def show_videoFile(self):
        # 选取视频帧位置,
        self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.vframeIdx)  
        self.vframeIdx += 1
        ret, frame = self.cap.read()  # 从视频流中读取

        # 读取失败,应该是视频播放结束了
        if not ret: 
            self.stop()
            return

        self.setFrameToOriLabel(frame)

app = QtWidgets.QApplication()
window = MWindow()
window.show()
app.exec()
3、结果呈现

运行代码后可以看到我们的前端界面是这样的

试着打开一个视频试试看


总结

YOLOv5目标检测-CSDN博客

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值