一、实战目标
快速掌握 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)
- 打开 LabelImg,点击「Open Dir」导入
fruit_annotation主文件夹或单个类别子文件夹。
- 格式选择:点击顶部「Save」旁的下拉框,必须选择 YOLO 格式(禁用 PascalVOC), YOLO格式标注后输出的数据是以txt后缀名文件保存。
- 保存路径:点击「Change Save Dir」,选择与图片文件夹一致的路径(确保标注 txt 与图片同名同路径)。
- 标注下一个文件夹中的图片时需要重复 1,3步骤
2. 标注规范与技巧
- 标注标准:IOU≥0.9,矩形框紧贴水果边缘;相邻水果允许 10%-30% 轻微重叠,超过 50% 重叠且有明显边界的也可以框,禁止超过80%的重叠。
IOU 的全称是Intersection over Union(交并比),是目标检测标注 / 检测中,衡量两个矩形框重叠程度的核心指标 , IOU≥0.9 = 给水果画框,紧贴边缘、少漏少包,肉眼看着 “框得准、没多余” 就达标了。
LabelImg 只能画矩形框,而水果边缘是曲线 / 不规则形状,这是工具的正常限制,也是目标检测行业的通用标注方式,不用纠结是否完全贴合曲线边缘。
具体操作方法(以你这张橙子图为例)
- 整果橙子:画一个刚好包裹住整个橙子的矩形,框的四条边紧贴橙子的外轮廓,只留 1-2 像素的空白(比如橙子顶部的弧形,框的上边缘对齐橙子最顶端,下边缘对齐最底端,左右同理)。
- 半切 / 切片橙子:同样画最小包围矩形,比如半切橙子的弧形边缘,框的上边缘对齐切片最顶端,下边缘对齐最底端,左右对齐切片的两侧,不用管中间的曲线。
- 效率技巧:按类别批量标注(先标完一类再换下一类);全程使用快捷键(W 画框、D 下一张、A 上一张、Ctrl+S 保存、Delete 删错框)。
3. 正式标注操作(单张图流程)
- 按 W 键调出矩形框工具(或点击「Create RectBox」),拖动鼠标绘制最小包围矩形,紧贴水果边缘(允许 1-5 像素偏差,无遗漏、不超出主体)。
- 弹出类别框时,严格输入小写英文:苹果填
apple、香蕉填banana、橙子填orange(禁用中文/大写/自定义名称)。
- 按 Ctrl+S 保存或者点击Save按钮(自动生成同名 txt 文件),按 D 键切换下一张图也可以点击左右箭头按钮,然后每张图片重复上述标注操作。
四、标注数据验收(必做)
- 抽检比例≥10%(如 200 张图至少抽检 20 张),重点检查:边界框完整性、类别准确性、是否生成同名 txt 文件。
- 修正要求:标注准确率需≥98%,及时修正错标、漏标、框选偏差过大的情况。
- 最终清理:删除文件夹内无对应标注 txt 的图片。
标注完成后,文件夹中有一个 classes.txt 。
classes.txt 会记录你标注时用的所有类别名称(比如 apple、banana、orange),并且类别顺序就是标注 txt 文件里的类别索引(比如第一行apple对应索引 0,第二行banana对应索引 1,第三行orange对应索引 2)。
现在 txt 文件中的索引大概率是错误的,因为刚刚是一个类型的图片放在文件夹,如果类别没输入错误现在的索引都是 0
在数据整理时,需要将数据 txt 中的索引改为与类别对应的索引。
五、数据整理(适配 YOLOv8 训练)
1. 环境配置
- 训练环境:阿里魔塔 Notebook(参考文档:modelscope.cn/docs/intro/…
阿里魔塔的官网链接: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 比例)
- 每类随机选 10-15 张图片(总计约 40 张),连同对应 txt 文件复制到
val/images和val/labels。 - 剩余图片(约 160 张)连同 txt 文件复制到
train/images和train/labels。 - 校验:确保 train/val 文件夹内图片与标注 txt 一一对应,无缺失、无错配。
将标注好的数据分类好后,压缩上传到 Notebook 将压缩拖到窗口就传上去了。
上传后,解压文件。
现在类别按照 apple、banana、orange,之前按照一个文件放一类图片标注后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. 阿里魔塔环境配置
- 切换工作目录到
/mnt/workspace/(持久化存储,避免文件丢失):cd /mnt/workspace/。 - 安装依赖并下载 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.训练完成使用如下代码识别图片
使用如下图片
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)
- 增加训练轮数:将
epochs调整为 50-100 轮,让模型充分学习特征。 - 启用自动数据增强:在
model.train()中添加augment=True,自动实现图片翻转、缩放、亮度调整。 - 微调学习率:将
lr0降至 0.001,避免学习过快导致模型欠拟合。 - 二次校验标注质量:确认标注框 IOU≥0.9、类别索引无错、验证集数据无缺失。
调整 1、2、3 点后模型训练时间会变长,但mAP50会提升。