零基础学习YOLOv8 水果检测实战:LabelImg 标注 + 模型训练全流程

30 阅读14分钟

一、实战目标

快速掌握 LabelImg 标注工具使用,完成苹果、香蕉、橙子三类水果的数据集标注并使用标注数据训练YOLOv8 模型,实现基础水果检测(目标 mAP50≥0.80)。模型运行环境使用阿里魔塔的 Notebook 免费且有齐全的环境配置。

  • mAP50:IOU 阈值=0.5 时的平均精度均值,衡量模型整体检测能力。
  • 初始合格标准:mAP50≥0.80(背景简单、标注规范场景下),可满足基础检测需求。

二、前期准备

1. 数据集准备

  • 来源: 可百度搜所筛选苹果、香蕉、橙子三类图片。注意图片要清晰,总的数据图片要求 ≥200张

    整理了部分水果图片:

    网盘分享的文件:各类水果照片

    链接: pan.baidu.com/s/1QuJbHe6T… 提取码: busy

  • 文件夹结构:新建 fruit_annotation 主文件夹,按类别创建子文件夹 apple「banana」「orange」,注意文件夹要为英文,分别存放选出的对应类别图片。

注意:选出来的图片,需要修改名字,避免名字重复,名字重复在标注中框会保留在未标注的画面上。文件名中最好有类别名字,这样好分辨,比如苹果的图片 Image_2_apple.jpg 后面找起来也方便。

可以使用代码批量改名,也可以手动改名。

如下代码的含义是给某文件下所有的文件加一段文字(这个可以改,可以是水果名)后缀,加在拓展名前面

import os

def add_banana_to_image_names(folder_path):
    """
    将指定文件夹下的图片文件名添加 "banana" 后缀(在扩展名前)
    
    参数:
        folder_path: 目标文件夹的路径(绝对路径/相对路径均可)
    """
    # 定义常见的图片扩展名(可根据需要增减)
    image_extensions = ('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp')

    # 检查目标文件夹是否存在
    if not os.path.isdir(folder_path):
        print(f"错误:文件夹 {folder_path} 不存在!")
        return

    # 遍历文件夹中的所有文件
    for filename in os.listdir(folder_path):
        # 获取文件完整路径
        old_path = os.path.join(folder_path, filename)

        # 跳过文件夹(只处理文件)
        if os.path.isdir(old_path):
            continue

        # 拆分文件名和扩展名(例如 "cat.png" 拆分为 ("cat", ".png"))
        file_name, file_ext = os.path.splitext(filename)

        # 只处理图片文件
        if file_ext.lower() in image_extensions:
            # 构造新文件名(格式:原名称_banana.扩展名)
            new_filename = f"{file_name}_apple{file_ext}"
            new_path = os.path.join(folder_path, new_filename)

            # 避免重复重命名(如果已存在带banana的文件则跳过)
            if os.path.exists(new_path):
                print(f"跳过:{new_filename} 已存在")
                continue

            # 执行重命名
            try:
                os.rename(old_path, new_path)
                print(f"成功:{filename}{new_filename}")
            except Exception as e:
                print(f"失败:{filename} → 原因:{str(e)}")

# ===================== 核心配置 =====================
# 替换为你的图片文件夹路径(示例:Windows路径用双反斜杠,Mac/Linux用斜杠)
TARGET_FOLDER = r"/mnt/workspace/fruit_annotation"  # Windows示例
# TARGET_FOLDER = "/Users/你的用户名/Desktop/图片文件夹"  # Mac/Linux示例

# 执行重命名操作
if __name__ == "__main__":
    add_banana_to_image_names(TARGET_FOLDER)

可以改这个,在这个改 apple

f"{file_name}_apple{file_ext}"

还需要修改:图片文件夹路径

TARGET_FOLDER = r"/mnt/workspace/fruit_annotation"

使用 LabelImg 对数据进行画框。

labelimg安装参考如下

Anaconda3+labelimg零失败安装教程:新手6步搞定数据标注工具搭建

如是参照上边安装,第二次启动输入如下命令

# 激活指定名称的 conda 虚拟环境,
conda activate labelimg

#运行 labelimg
labelimg

三、LabelImg 标注流程(核心步骤)

1. 标注前设置(关键适配 YOLOv8)

  1. 打开 LabelImg,点击「Open Dir」导入 fruit_annotation 主文件夹或单个类别子文件夹。

  1. 格式选择:点击顶部「Save」旁的下拉框,必须选择 YOLO 格式(禁用 PascalVOC), YOLO格式标注后输出的数据是以txt后缀名文件保存。

  1. 保存路径:点击「Change Save Dir」,选择与图片文件夹一致的路径(确保标注 txt 与图片同名同路径)。

  1. 标注下一个文件夹中的图片时需要重复 1,3步骤

2. 标注规范与技巧

  • 标注标准:IOU≥0.9,矩形框紧贴水果边缘;相邻水果允许 10%-30% 轻微重叠,超过 50% 重叠且有明显边界的也可以框,禁止超过80%的重叠。

IOU 的全称是Intersection over Union(交并比),是目标检测标注 / 检测中,衡量两个矩形框重叠程度的核心指标 , IOU≥0.9 = 给水果画框,紧贴边缘、少漏少包,肉眼看着 “框得准、没多余” 就达标了。

LabelImg 只能画矩形框,而水果边缘是曲线 / 不规则形状,这是工具的正常限制,也是目标检测行业的通用标注方式,不用纠结是否完全贴合曲线边缘。

具体操作方法(以你这张橙子图为例)

  1. 整果橙子:画一个刚好包裹住整个橙子的矩形,框的四条边紧贴橙子的外轮廓,只留 1-2 像素的空白(比如橙子顶部的弧形,框的上边缘对齐橙子最顶端,下边缘对齐最底端,左右同理)。
  2. 半切 / 切片橙子:同样画最小包围矩形,比如半切橙子的弧形边缘,框的上边缘对齐切片最顶端,下边缘对齐最底端,左右对齐切片的两侧,不用管中间的曲线。
  • 效率技巧:按类别批量标注(先标完一类再换下一类);全程使用快捷键(W 画框、D 下一张、A 上一张、Ctrl+S 保存、Delete 删错框)。

3. 正式标注操作(单张图流程)

  1. 按 W 键调出矩形框工具(或点击「Create RectBox」),拖动鼠标绘制最小包围矩形,紧贴水果边缘(允许 1-5 像素偏差,无遗漏、不超出主体)。

  1. 弹出类别框时,严格输入小写英文:苹果填 apple、香蕉填 banana、橙子填 orange(禁用中文/大写/自定义名称)。

  1. 按 Ctrl+S 保存或者点击Save按钮(自动生成同名 txt 文件),按 D 键切换下一张图也可以点击左右箭头按钮,然后每张图片重复上述标注操作。

四、标注数据验收(必做)

  1. 抽检比例≥10%(如 200 张图至少抽检 20 张),重点检查:边界框完整性、类别准确性、是否生成同名 txt 文件。
  2. 修正要求:标注准确率需≥98%,及时修正错标、漏标、框选偏差过大的情况。
  3. 最终清理:删除文件夹内无对应标注 txt 的图片。

标注完成后,文件夹中有一个 classes.txt 。

classes.txt 会记录你标注时用的所有类别名称(比如 applebananaorange),并且类别顺序就是标注 txt 文件里的类别索引(比如第一行apple对应索引 0,第二行banana对应索引 1,第三行orange对应索引 2)。

现在 txt 文件中的索引大概率是错误的,因为刚刚是一个类型的图片放在文件夹,如果类别没输入错误现在的索引都是 0

在数据整理时,需要将数据 txt 中的索引改为与类别对应的索引。

五、数据整理(适配 YOLOv8 训练)

1. 环境配置

阿里魔塔的官网链接:www.modelscope.cn/

阿里魔塔 Notebook 有 免费的CPU 可用,每天10小时,足够简单学习了。

启动按钮就能启动

魔搭 Notebook 的运行环境是临时容器 / 实例 ,如果不是安装在 /mnt/workspace 目录下的软件都需要每次都需要重新安装。

不用做复杂配置,每次启动,都重新下载依赖就行

在 /mnt/workspace 目录下有 100 G 的免费缓存,如果长时间不使用会将储存释放。

2. 搭建固定文件夹结构

新建一个文件 fruit_dataset , 并根据下图建立对应的子目录,需要注意要为英文路径

fruit_dataset/
├─ train/
│  ├─ images/ (训练集图片)
│  └─ labels/ (训练集标注 txt)
├─ val/
│  ├─ images/ (测试集图片)
│  └─ labels/ (测试集标注 txt)
└─ fruit.yaml (数据集配置文件)

3. 拆分训练集与测试集(4:1 比例)

  1. 每类随机选 10-15 张图片(总计约 40 张),连同对应 txt 文件复制到 val/imagesval/labels
  2. 剩余图片(约 160 张)连同 txt 文件复制到 train/imagestrain/labels
  3. 校验:确保 train/val 文件夹内图片与标注 txt 一一对应,无缺失、无错配。

将标注好的数据分类好后,压缩上传到 Notebook 将压缩拖到窗口就传上去了。

上传后,解压文件。

现在类别按照 applebananaorange,之前按照一个文件放一类图片标注后txt文件索引大概率是错的,需要修改 txt 索引。按照这个类别顺序对应的索引应该为,0,1,2。

可以根据文件名找,比如 txt文件名中有 apple 的索引都改为 0,

使用python改索引,可以在 Notebook 中跑。

选着下面这个,有运行按钮可以直接跑代码

如下代码用于修改txt文件索引,代码需要修改3个位置

标注txt文件路径 LABEL_DIR = r"" # 你的标注txt文件夹路径

需要修改的索引 NEW_INDEX = 0 这个索引是类别的排序,后面yaml文件中会配置类别组信息,如果apple排在第一个,索引就是 0

匹配的文件名

import os
import glob

# ======================== 需修改这2行! ========================
LABEL_DIR = r""  # 你的标注txt文件夹路径
NEW_INDEX = 0                                 # 要改成的新索引(比如0)
# =================================================================

# 1. 搜索不同文件时需要修改这里。筛选文件名包含"apple"的txt文件(*表示任意字符,匹配所有含apple的文件名)
txt_files = glob.glob(os.path.join(LABEL_DIR, "*apple*.txt"))
if not txt_files:
    print(f"❌ 错误:在 {LABEL_DIR} 中未找到文件名包含'apple'的txt文件!")
else:
    modified_count = 0  # 统计修改的文件数
    
    # 2. 遍历筛选后的文件批量修改
    for txt_file in txt_files:
        try:
            # 读取文件内容
            with open(txt_file, 'r', encoding='utf-8') as f:
                lines = f.readlines()
            
            new_lines = []
            file_updated = False  # 标记文件是否被修改
            
            # 3. 逐行修改:所有标注行索引直接替换为新索引
            for line in lines:
                line = line.strip()
                if not line:  # 跳过空行
                    new_lines.append("")
                    continue
                
                # 拆分标注行(索引 + 坐标)
                parts = line.split()
                if len(parts) == 5:  # 仅处理格式正确的标注行
                    # 替换第一个元素(原索引)为新索引,保留坐标
                    new_line = f"{NEW_INDEX} {' '.join(parts[1:])}"
                    new_lines.append(new_line)
                    file_updated = True
                else:  # 格式错误的行,原样保留
                    new_lines.append(line)
            
            # 4. 保存修改后的内容
            if file_updated:
                with open(txt_file, 'w', encoding='utf-8') as f:
                    f.write('\n'.join(new_lines))
                modified_count += 1
                print(f"✅ 已修改(文件名含apple):{txt_file}")
            else:
                print(f"ℹ️ 无修改:{txt_file}(无有效标注行)")
        
        except Exception as e:
            print(f"❌ 处理失败:{txt_file} → 错误:{str(e)}")
    
    # 5. 输出最终统计
    print(f"\n📊 批量修改完成!共找到 {len(txt_files)} 个文件名含'apple'的txt文件,成功修改 {modified_count} 个")

3. 配置 fruit.yaml 文件

新建文本文档并改后缀为 .yaml,内容如下(类别顺序需与前面的更改的索引值完全一致):

# 数据集路径(根据你的实际路径修改,建议用绝对路径)
path: /mnt/workspace/annotation/fruit_yolov8  # 你的项目根目录(包含train/val文件夹)
train: /mnt/workspace/annotation/fruit_yolov8/train/images    # 训练集图片路径(相对path的路径)
val: /mnt/workspace/annotation/fruit_yolov8/val/images        # 测试集图片路径(相对path的路径)

# 类别配置(核心:从classes.txt复制)
nc: 3                  # 类别数量(苹果/香蕉/橙子共3类)
names: ['apple', 'banana', 'orange']  # 类别名称,顺序必须和classes.txt一致

需要将这个文件移动到 notebook 中。

需要将数据集路径改为你本地的路径。

六、模型训练与验证

1. 阿里魔塔环境配置

  1. 切换工作目录到 /mnt/workspace/(持久化存储,避免文件丢失):cd /mnt/workspace/
  2. 安装依赖并下载 YOLOv8 预训练权重(yolov8n.pt),若下载中断需删除残留文件后重新下载。
# 安装ultralytics(YOLOv8官方库) -i xxx 代表的是使用阿里云镜像下载 
pip install -U ultralytics 

# 验证安装
yolo check

显示如上,表示安装成功。

每次关闭notebook在从新打开时需要重新安装依赖,因为上面的命令依赖并不是安装在持久化文件夹内。

2. 基础训练代码

完成上边步骤后,编写代码训练模型

如下为简单训练代码,可使用如下代码训练模型,也是在 notebook 上跑。

第一次运行会下载 yolov8n.pt 预训练权重,注意不要中断下载,不然下次运行时会报错。

下面代码需要将 fruit.yaml 改为自己文件的路径

from ultralytics import YOLO

# 1. 加载YOLOv8预训练模型(轻量化n版,适配CPU),如没有会自行下载预训练权重文件
# 文件存储路径可改为自己的路径,如果先在了 yolov8n.pt 改为 yolov8n.pt文件的路径
model = YOLO("/mnt/workspace/annotation/fruit_yolov8/yolov8n.pt")  

# 2. 执行训练(8核32G CPU最优参数,移除无效参数)
results = model.train(
    data="/mnt/workspace/annotation/fruit_yolov8/fruit.yaml",  # 数据集配置文件路径
    epochs=20,                              # 先测试20轮(5-10分钟),稳定后调100轮
    batch=8,                                # 8核32G CPU最优batch值(避免OOM)
    imgsz=640,                              # YOLOv8默认尺寸,适配CPU
    device="cpu",                           # 强制CPU训练
    lr0=0.01,                               # 初始学习率(CPU无需调整)
    workers=4,                              # 8核CPU设4更稳定(避免线程冲突)
    save=True,                              # 保存训练好的模型
    project="/mnt/workspace/annotation/fruit_yolov8/yolov8_train/",  # 结果保存路径
    name="fruit_model_8core32G",            # 改名更贴合水果检测场景(原helmet是头盔,易混淆)
    exist_ok=True,                          # 覆盖已有目录,避免报错
    augment=True,                           #  启用数据增强
)

# 3. 验证模型精度(自动适配CPU)
metrics = model.val()  
print(f"验证集mAP50: {metrics.box.map50:.2f}")

也可使用如下命令下载预训练文件

# 下载文件
wget https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8n.pt

下载后需要配置,加载YOLOv8预训练模型的路径。

代码执行完成及训练好了模型,如果图片标注得标准且数据集使用200张,大概率会输出 验证集mAP50:0.8

如果想要再次提升模型识别准确率可以,参考下面 七、模型优化方案

训练结束后会在 /mnt/workspace/annotation/fruit_yolov8/yolov8_train/ 路径下输出训练好的模型文件,这个输出路径可以修改。

3. 核心指标解读(mAP50)

  • mAP50:IOU 阈值=0.5 时的平均精度均值,衡量模型整体检测能力。
  • 初始合格标准:mAP50≥0.80(背景简单、标注规范场景下),可满足基础检测需求。

4.训练完成使用如下代码识别图片

使用如下图片

123.jpg

from ultralytics import YOLO
import os

# 1. 加载训练好的模型(替换为你的best.pt路径)
model = YOLO("/mnt/workspace/annotation/fruit_yolov8/yolov8_train/fruit_model_8core32G/weights/best.pt")

# 2. 待检测的图片路径(替换为你的水果图片路径)
img_path = "/mnt/workspace/annotation/fruit_yolov8/test/123.jpg"  # 示例路径
# 检测结果保存目录(自动创建)
save_dir = "/mnt/workspace/annotation/fruit_yolov8/predict_results"
os.makedirs(save_dir, exist_ok=True)

# 3. 执行检测(关键参数:conf=0.5 过滤低置信度结果)
results = model(
    source=img_path,       # 待检测图片
    conf=0.5,              # 置信度阈值(只保留≥50%置信度的检测框)
    iou=0.5,               # 框重叠阈值
    save=True,             # 保存标注后的图片
    save_txt=True,         # 可选:保存检测结果到txt文件(坐标+类别+置信度)
    project=save_dir,      # 结果保存目录
    name="single_img",     # 结果子目录名
    exist_ok=True          # 覆盖已有目录
)

# 4. 解析检测结果(新手可选看)
#for result in results:
#    boxes = result.boxes  # 检测框信息
#    for box in boxes:
#        cls = box.cls  # 类别索引(0=apple,1=banana,2=orange)
#        conf = box.conf  # 置信度
#        xyxy = box.xyxy  # 检测框坐标(左上x,左上y,右下x,右下y)
#        print(f"检测到:{model.names[int(cls)]},置信度:{conf:.2f},坐标:{xyxy}")

print(f"✅ 检测完成!标注后的图片保存在:{save_dir}/single_img")

输出的图片效果

七、模型优化方案(提升 mAP50 至≥0.85)

  1. 增加训练轮数:将 epochs 调整为 50-100 轮,让模型充分学习特征。
  2. 启用自动数据增强:在 model.train() 中添加 augment=True,自动实现图片翻转、缩放、亮度调整。
  3. 微调学习率:将 lr0 降至 0.001,避免学习过快导致模型欠拟合。
  4. 二次校验标注质量:确认标注框 IOU≥0.9、类别索引无错、验证集数据无缺失。

调整 1、2、3 点后模型训练时间会变长,但mAP50会提升。