yolov8学习笔记(2)

第7周学*进度:

经过一周对yolov8基础知识的学*,现在根据项目进行练*,*一步加深理解能力:

学*目标:

1.1周内跑通YOLOv8官方检测/分类Demo,理解核心概念,搭建稳定的开发环境。

2能标注自己的数据集,训练自定义模型(如“安全帽检测”“水果分类”),并通过调参提升精度,会训练、能调参。

3.

1.Ultralytics提供了“开箱即用”的API,需掌握3个核心操作:加载模型、执行推理、解析结果

以“目标检测”为例,Jupyter完整代码(复制就能跑):

# 1. 导入库
from ultralytics import YOLO
import cv2
import matplotlib.pyplot as plt

# 2. 加载预训练模型(检测模型,自动下载)
model = YOLO("yolov8s.pt")  # s=small,平衡速度与精度

# 3. 执行推理(用官方测试图)
results = model.predict(
    source="https://ultralytics.com/images/bus.jpg",  # 输入图片URL
    conf=0.25,  # 置信度阈值(只保留>0.25的目标)
    imgsz=640   # 输入图像尺寸
)

# 4. 解析结果(打印检测到的目标)
result = results[0]  # 单张图的结果
print(f"检测到 {len(result.boxes)} 个目标:")
for box in result.boxes:
    cls_name = model.names[box.cls[0].item()]  # 类别名
    conf = box.conf[0].item()  # 置信度
    xyxy = box.xyxy[0].tolist()  # 目标框坐标
    print(f"类别:{cls_name},置信度:{conf:.2f},坐标:{xyxy}")

# 5. 显示结果
img = cv2.imread(result.path)  # 读取图片
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # 转RGB(matplotlib用)
plt.figure(figsize=(10, 8))
plt.imshow(img_rgb)
plt.axis("off")
plt.title("YOLOv8 检测结果")
plt.show()

概念理解:

 1. 导入库

  • ultralytics.YOLO:Ultralytics 库的核心类,封装了 YOLO 模型的加载、训练、推理等功能。
  • cv2:OpenCV 是计算机视觉领域常用的库,用于读取、处理图像 / 视频。
  • matplotlib.pyplot:用于在 Python 中可视化图像(尤其适合 Jupyter 环境)。

2. 加载预训练模型(检测模型,自动下载)

  • YOLO("yolov8s.pt"):创建 YOLO 模型实例,参数为预训练权重文件路径。
  • yolov8s.pt:YOLOv8 的 "small" 版本模型,预训练于 COCO 数据集(包含 80 个常见类别,如人、车、动物等)。

首次运行时会自动下载权重文件(约 21MB),其他版本可替换为yolov8n.pt(nano,最快)、yolov8m.pt(medium,更精准)。

model:加载后的模型对象,后续可调用predict()方法执行推理。

 3. 执行推理(用官方测试图)

  • model.predict():模型推理的核心方法,对输入的图像 / 视频进行目标检测。
  • source:输入源,可以是本地图片路径(如"test.jpg")、网络图片 URL、视频文件或摄像头 ID(如0表示默认摄像头)。这里使用官方测试图(一辆公交车的图片)。
  • conf=0.25:置信度阈值,过滤掉置信度低于 0.25 的检测结果(减少误检)。
  • imgsz=640:输入图像的尺寸(宽 × 高),模型会自动将输入图像缩放至 640×640 后进行处理。
  • results:推理结果的列表(即使只有一张图,也会包装成列表),每个元素对应一个输入源的检测结果。

 4. 解析结果(打印检测到的目标)

  • result = results[0]:由于输入是单张图片,results列表只有一个元素,即该图片的检测结果。
  • result.boxes:存储所有检测到的目标框信息(每个目标对应一个box对象)。
  • len(result.boxes):统计检测到的目标数量。
  • 循环解析每个目标的信息:
  • box.cls:目标的类别索引(张量格式),box.cls[0].item()将张量转为 Python 数值(如 “人” 对应索引 0,“公交车” 对应索引 5)。
  • model.names:模型预定义的类别名称字典(键为索引,值为类别名),通过类别索引获取具体名称(如model.names[5]为 “bus”)。
  • box.conf:目标的置信度(张量格式),box.conf[0].item()转为 0~1 之间的数值(越接* 1 越可信)。
  • box.xyxy:目标框的坐标(张量格式,格式为[x1, y1, x2, y2],即左上角 x、左上角 y、右下角 x、右下角 y),tolist()转为 Python 列表便于查看。

5.显示结果

  • cv2.imread(result.path):通过result.path获取输入图片的路径,用 OpenCV 读取图像(注意:OpenCV 默认读取为 BGR 通道格式)。
  • cv2.cvtColor(img, cv2.COLOR_BGR2RGB):将 BGR 格式转为 RGB 格式,因为 Matplotlib 显示图像时默认使用 RGB 通道,不转换会导致颜色失真(如蓝色变红色)。
  • plt.figure(figsize=(10, 8)):创建一个 10×8 英寸的画布。
  • plt.imshow(img_rgb):在画布上显示转换后的 RGB 图像。
  • plt.axis("off"):隐藏坐标轴,使图像显示更简洁。
  • plt.title(...):为图像添加标题。
  • plt.show():显示最终的图像(包含检测结果的标注,YOLO 会自动在图像上绘制目标框和类别名)

运算结果:

          image

                  image

2.对图片进行识别与分类:

from ultralytics import YOLO
if __name__ == '__main__':
    model = YOLO(r"yolo11n.pt")
    model.train(
        data=r"coco8.yaml",
        epochs=30,imgsz=640,
        batch=2,
        cache=False,
        workers=0,
        val=False,

    )

1.data=r"coco8.yaml"

指定数据集配置文件的路径。coco8.yaml是 Ultralytics 提供的一个小型 COCO 数据集示例(仅包含 8 张图片),用于快速测试训练流程。

配置文件中定义了:训练集 / 验证集的路径、类别数量(nc)、类别名称(names)等信息。实际应用中需替换为自定义数据集的配置文件。

2.epochs=30

训练的总轮数(即整个数据集被模型学*的次数)。30 表示模型会对训练集迭代 30 次。

轮数越多,模型可能拟合越好,但也可能过拟合(需根据验证集效果调整)。

3.imgsz=640

输入图像的尺寸(宽 × 高),模型会自动将输入图像缩放为 640×640 像素后进行训练。

YOLO 系列通常推荐 640 或 1280,需根据硬件性能和精度需求调整。

4.batch=2

批次大小:每次模型参数更新时使用的样本数量。这里设置为 2,表示每次输入 2 张图片计算损失并更新权重。

批次大小受 GPU 显存限制:显存小则设小(如 2、4),显存大则可设大(如 16、32),更大的批次通常训练更稳定。

5.cache=False

是否缓存数据集到内存或磁盘。False表示不缓存,适合小数据集(如coco8)或内存有限的情况;True则会提前加载数据到缓存,加速后续训练(适合大数据集)。

6.workers=0

数据加载的工作进程数量。0表示在主进程中加载数据(不启用多进程),适用于 Windows 系统(避免多进程路径问题);Linux/Mac 可设为大于 0 的数(如 4,根据 CPU 核心数调整),加速数据加载。

7.val=False

是否在训练过程中关闭验证步骤。默认情况下,YOLO 会在每个 epoch 结束后用验证集评估模型性能(如 mAP 指标),val=False会跳过验证,适用于快速测试训练流程(不关心模型精度时)。

训练输出

             image

内容分析:

  • 训练完成情况:60 个 epochs 的训练在 0.012 小时内完成,优化器从 runs\detect\train3\weights 路径下的 last.pt 和 best.pt 中剥离,两个文件均为 5.5MB。
  • 验证环境:使用 Ultralytics 8.3.163、Python-3.11.13、torch-2.5.0+cpu,运行在 13th Gen Intel Core (TM) i5-13500H CPU 上。
  • 模型结构:YOLO11n(融合模式),包含 100 层,2,616,248 个参数,0 个梯度,6.5 GFLOPs。
  • 验证指标(针对 runs\detect\train3\weights\best.pt):
    • 整体(all):4 张图片,17 个实例,Box (P) 为 0.859,R 为 0.648,mAP50 为 0.874,mAP50-95 为 0.642。
    • 各分类:
      • person:3 张图片,10 个实例,Box (P) 为 1,R 为 0.386,mAP50 为 0.668,mAP50-95 为 0.332。
      • dog:1 张图片,1 个实例,Box (P) 为 0.695,R 为 1,mAP50 为 0.995,mAP50-95 为 0.796。
      • horse:1 张图片,2 个实例,Box (P) 为 0.976,R 为 1,mAP50 为 0.995,mAP50-95 为 0.65。
      • elephant:1 张图片,2 个实例,Box (P) 为 0.782,R 为 0.5,mAP50 为 0.595,mAP50-95 为 0.28。
      • umbrella:1 张图片,1 个实例,Box (P) 为 0.698,R 为 1,mAP50 为 0.995,mAP50-95 为 0.895。
      • potted plant:1 张图片,1 个实例,Box (P) 为 1,R 为 0,mAP50 为 0.995,mAP50-95 为 0.895。
  • 速度:每张图片预处理 0.8ms,推理 67.6ms,损失计算 0.0ms,后处理 1.4ms。
  • 结果保存:结果保存至 runs\detect\train3 路径,进程已结束,退出代码为 0。

3.对车牌进行识别与分类:

1. main.py:项目的核心入口
main.py 作为整个项目的主入口,负责整体流程的控制。该模块的核心功能包括加载YOLO模型、读取输入视频、进行图像处理以及输出检测结果。

加载模型
在项目开始时,首先导入必要的库和模块,如 OpenCV、YOLO 和自定义的工具模块。接着,使用 YOLO 模型加载函数载入预训练的模型文件。这一步骤至关重要,因为它为后续的车辆和车牌检测提供了必要的网络结构和参数。

  1. 基础库:torch(PyTorch 深度学*框架)、cv2(OpenCV 计算机视觉库)、numpy(数值计算库)、argparse(命令行参数解析)、copy(对象复制)、time(时间处理)、os(操作系统交互)
  2. 自定义模块:
    • ultralytics.nn.tasks中的attempt_load_weights:可能用于加载 YOLO 系列模型的权重
    • plate_recognition.plate_rec中的get_plate_result(获取车牌识别结果)、init_model(初始化模型)、cv_imread(图像读取函数)
    • plate_recognition.double_plate_split_merge中的get_split_merge:可能用于处理双层车牌的分割与合并
    • fonts.cv_puttext中的cv2ImgAddText:可能是一个支持中文的图像文字添加函数(解决 OpenCV 默认不支持中文的问题)
import torch
import cv2
import numpy as np
import argparse
import copy
import time
import os
from ultralytics.nn.tasks import  attempt_load_weights
from plate_recognition.plate_rec import get_plate_result,init_model,cv_imread
from plate_recognition.double_plate_split_merge import get_split_merge
from fonts.cv_puttext import cv2ImgAddText

 

2.读取视频/文件导入

接下来,使用 OpenCV 读取输入视频并逐帧进行处理。每帧的处理包括检测车辆和车牌的过程。

# 加载视频
cap = cv2.VideoCapture('./sample.mp4')
# 初始化帧计数器
frame\_nmr = -1
ret = True
while ret:
    frame\_nmr += 1
    ret, frame = cap.read()
    if ret:
        results[frame\_nmr] = {}
        ...
def allFilePath(rootPath, allFileList):  # 读取文件夹内的所有文件路径,存储到列表中
    fileList = os.listdir(rootPath)  # 获取当前目录下的所有文件和文件夹名
    for temp in fileList:  # 遍历每个文件/文件夹
        # 判断是否为文件
        if os.path.isfile(os.path.join(rootPath, temp)):
            # 若是文件则拼接完整路径并添加到列表
            allFileList.append(os.path.join(rootPath, temp))
        else:
            # 若是文件夹则递归调用自身继续遍历
            allFilePath(os.path.join(rootPath, temp), allFileList)
 

3.检测车辆

对于每帧图像,首先使用 YOLO 模型检测车辆。检测结果包含每个车辆的边界框信息及其置信度分数。通过过滤车辆类别,只保留主要关心的车辆(如轿车、SUV等)。

# 检测车辆
detections = coco\_model(frame)[0]
detections\_ = []
for detection in detections.boxes.data.tolist():
    x1, y1, x2, y2, score, class\_id = detection
    if int(class\_id) in vehicles:
        detections\_.append([x1, y1, x2, y2, score])

4.裁剪和处理车牌

成功分配车牌后,裁剪出车牌区域,并对其进行灰度转换和二值化处理,以便于后续的字符识别。

if car\_id != -1:
    # 裁剪车牌图像
    license\_plate\_crop = frame[int(y1):int(y2), int(x1): int(x2), :]
    # 处理车牌图像
    license\_plate\_crop\_gray = cv2.cvtColor(license\_plate\_crop, cv2.COLOR\_BGR2GRAY)
    \_, license\_plate\_crop\_thresh = cv2.threshold(license\_plate\_crop\_gray, 64, 255, cv2.THRESH\_BINARY\_INV)
    # 读取车牌号码
    license\_plate\_text, license\_plate\_text\_score = read\_license\_plate(license\_plate\_crop\_thresh)
    if license\_plate\_text is not None:
        results[frame\_nmr][car\_id] = {'car': {'bbox': [xcar1, ycar1, xcar2, ycar2]},
                                      'license\_plate': {'bbox': [x1, y1, x2, y2],
                                                        'text': license\_plate\_text,
                                                        'bbox\_score': score,
                                                        'text\_score': license\_plate\_text\_score}}

5.写入结果

最后,将处理后的检测结果写入 CSV 文件,以便后续的数据分析和处理。

# 写入结果
write\_csv(results, './test.csv')

visualize.py:结果可视化模块

visualize.py 模块的主要功能是将车牌识别的结果以可视化的形式展示在视频中。这不仅可以帮助开发者直观地理解识别系统的表现,还能用于展示最终的产品效果,增强用户体验。

导入所需库

首先需要导入一些必要的库:

  • cv2:用于图像和视频处理。
  • numpy:用于数值计算和数组操作。
  • pandas:用于数据处理和分析。
import ast
import cv2
import numpy as np
import pandas as pd

绘制边框的函数

draw\_border 函数负责在图像上绘制车辆和车牌的边框。通过这种可视化,可以清晰地看到识别的区域,帮助分析模型的准确性。

def draw\_border(img, top\_left, bottom\_right, color=(0, 255, 0), thickness=10, line\_length\_x=200, line\_length\_y=200):
    x1, y1 = top\_left
    x2, y2 = bottom\_right
    # 绘制左上角边框
    cv2.line(img, (x1, y1), (x1, y1 + line\_length\_y), color, thickness)  # 左侧
    cv2.line(img, (x1, y1), (x1 + line\_length\_x, y1), color, thickness)  # 上侧
    # 绘制左下角边框
    cv2.line(img, (x1, y2), (x1, y2 - line\_length\_y), color, thickness)  # 左侧
    cv2.line(img, (x1, y2), (x1 + line\_length\_x, y2), color, thickness)  # 下侧
    # 绘制右上角边框
    cv2.line(img, (x2, y1), (x2 - line\_length\_x, y1), color, thickness)  # 上侧
    cv2.line(img, (x2, y1), (x2, y1 + line\_length\_y), color, thickness)  # 右侧
    # 绘制右下角边框
    cv2.line(img, (x2, y2), (x2, y2 - line\_length\_y), color, thickness)  # 右侧
    cv2.line(img, (x2, y2), (x2 - line\_length\_x, y2), color, thickness)  # 下侧
    return img

6.取识别结果数据

通过 Pandas 读取 CSV 文件中的识别结果,这些结果是模型处理视频后生成的,包括每个车牌的置信度和位置信息。

# 加载视频
video\_path = 'sample.mp4'
cap = cv2.VideoCapture(video\_path)  # 创建视频捕获对象
# 指定视频编码和帧率
fourcc = cv2.VideoWriter\_fourcc(\*'mp4v')
fps = cap.get(cv2.CAP\_PROP\_FPS)  # 获取原视频的帧率
width = int(cap.get(cv2.CAP\_PROP\_FRAME\_WIDTH))  # 获取视频宽度
height = int(cap.get(cv2.CAP\_PROP\_FRAME\_HEIGHT))  # 获取视频高度
out = cv2.VideoWriter('./out.mp4', fourcc, fps, (width, height))  # 创建输出视频文件

7.初始化车牌信息字典

为每个车辆提取最大置信度的车牌信息,并存储对应的车牌图像。这样做的目的是在后续绘制过程中,能够快速访问每辆车的识别结果

license\_plate = {}
for car\_id in np.unique(results['car\_id']):  # 遍历所有唯一的车ID
    max\_ = np.amax(results[results['car\_id'] == car\_id]['license\_number\_score'])  # 找到最大置信度
    license\_plate[car\_id] = {
        'license\_crop': None,  # 初始化车牌裁剪图像
        'license\_plate\_number': results[(results['car\_id'] == car\_id) &
                                         (results['license\_number\_score'] == max\_)]['license\_number'].iloc[0]  # 存储车牌号
    }
    # 设置视频帧的位置
    cap.set(cv2.CAP\_PROP\_POS\_FRAMES, results[(results['car\_id'] == car\_id) &
                                            (results['license\_number\_score'] == max\_)]['frame\_nmr'].iloc[0])
    ret, frame = cap.read()  # 读取该帧
    # 获取车牌的边界框坐标
    x1, y1, x2, y2 = ast.literal\_eval(results[(results['car\_id'] == car\_id) &

                                              (results['license\_number\_score'] == max\_)]['license\_plate\_bbox'].iloc[0].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))
    # 裁剪车牌图像并调整大小
    license\_crop = frame[int(y1):int(y2), int(x1):int(x2), :]
    license\_crop = cv2.resize(license\_crop, (int((x2 - x1) \* 400 / (y2 - y1)), 400))  # 调整裁剪图像的大小
    license\_plate[car\_id]['license\_crop'] = license\_crop  # 保存裁剪的车牌图像

 

8逐帧读取视频并绘制识别结果

在这一部分,逐帧读取视频,并根据识别结果在每帧上绘制车辆和车牌的边界框。通过这种方式,用户可以直观地看到模型的识别效果,并评估其准确性和可靠性。

 

frame\_nmr = -1  # 帧计数器
cap.set(cv2.CAP\_PROP\_POS\_FRAMES, 0)  # 重置视频到开头
# 读取帧
ret = True
while ret:
    ret, frame = cap.read()  # 读取一帧
    frame\_nmr += 1  # 增加帧计数
    if ret:
        df\_ = results[results['frame\_nmr'] == frame\_nmr]  # 获取当前帧的结果
        for row\_indx in range(len(df\_)):
            # 绘制车辆边界框
            car\_x1, car\_y1, car\_x2, car\_y2 = ast.literal\_eval(df\_.iloc[row\_indx]['car\_bbox'].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))
            draw\_border(frame, (int(car\_x1), int(car\_y1)), (int(car\_x2), int(car\_y2)), (0, 255, 0), 25,line\_length\_x=200, line\_length\_y=200)
            # 绘制车牌边界框
            x1, y1, x2, y2 = ast.literal\_eval(df\_.iloc[row\_indx]['license\_plate\_bbox'].replace('[ ', '[').replace('   ', ' ').replace('  ', ' ').replace(' ', ','))
            cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 12)  # 绘制车牌的矩形框
            # 获取并显示车牌裁剪图像
            license\_crop = license\_plate[df\_.iloc[row\_indx]['car\_id']]['license\_crop']  # 获取车牌裁剪图像
            H. W, \_ = license\_crop.shape  # 获取车牌裁剪图像的高度和宽度
            try:
                # 在车辆上方插入车牌图像
                frame[int(car\_y1) - H - 100:int(car\_y1) - 100,
                      int((car\_x2 + car\_x1 - W) / 2):int((car\_x2 + car\_x1 + W) / 2), :] = license\_cro
                # 在车牌上方添加白色背景
                frame[int(car\_y1) - H - 400:int(car\_y1) - H - 100,
                      int((car\_x2 + car\_x1 - W) / 2):int((car\_x2 + car\_x1 + W) / 2), :] = (255, 255, 255)
                # 获取文本的尺寸
                (text\_width, text\_height), \_ = cv2.getTextSize( license\_plate[df\_.iloc[row\_indx]['car\_id']]['license\_plate\_number'],
                    cv2.FONT\_HERSHEY\_SIMPLEX, 4.3, 17)                                 
                # 在帧中绘制车牌号
                cv2.putText(frame,   license\_plate[df\_.iloc[row\_indx]['car\_id']]['license\_plate\_number'],
    (int((car\_x2 + car\_x1 - text\_width) / 2), int(car\_y1 - H - 250 + (text\_height / 2))), cv2.FONT\_HERSHEY\_SIMPLEX, 4.3, (0, 0, 0),  17)
                                                                                                    
 except:                                                               
         pass  # 忽略可能出现的错误
        out.write(frame)  # 将处理后的帧写入输出视频
        frame = cv2.resize(frame, (1280, 720))  # 调整输出帧的尺寸
        out.release()  # 释放视频写入对象
        cap.release()  # 释放视频捕获对象

图片展示:

       image      

输出结果:

           imageimage

                     image

 

4.

 

posted @ 2025-10-26 23:47  Zwy4321  阅读(44)  评论(0)    收藏  举报