ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

树叶目标检测数据集:VOC/COCO/YOLO格式解析与YOLOv8实战

树叶目标检测数据集:VOC/COCO/YOLO格式解析与YOLOv8实战 简介本资源是一套面向计算机视觉初学者与课程实践者的YOLO树叶分类目标检测数据集及配套开发工具包解决真实场景下植物叶片细粒度识别的数据匮乏与训练环境搭建难题。资源包含1000张高质量实景树叶图像标注框由LabelImg人工精标提供VOCXML、COCOJSON和YOLOTXT三种主流格式标签分别存放于独立目录开箱即用于YOLOv5/v8等系列模型训练同时集成3个Python划分脚本支持按比例生成ImageSets或完整三集结构、Windows/Linux双平台YOLO环境配置指南及分步训练教程HTML文档覆盖从数据准备到模型微调的全流程。包内共2000个文件以1000个XML、990个TXT为主辅以6个HTML教程页、3个Python脚本及1个YOLO配置YAML文件总大小27.93MB。目前已有470人学习下载特别适合高校课程设计、AI实训项目及农业智能识别方向入门实践。1. 为什么树叶分类要用目标检测而不是图像分类——YOLO数据集不是“多标几张图”那么简单你手头有一堆树叶照片想让模型自动识别是银杏、梧桐还是香樟。如果直接扔进ImageNet风格的分类流水线大概率会翻车一张图里三片叶子重叠、半片叶子被遮挡、背景全是泥土和石子——分类模型只看整图打标签根本分不清“图里有几片叶子、每片在哪、属于哪类”。而这个标题里的YOLO树叶分类目标检测数据集本质是把“识别任务”升级成“定位识别双任务”它不只要答出“这是银杏”还要框出“左上角那片银杏叶的像素坐标”。数据集含1000张实拍树叶图像非合成、非剪贴每张图都经过人工精标——不是简单画个大框而是严格按叶片边缘抠轮廓再转成VOCPascal XML、COCOJSON和YOLOTXT三种格式。这意味着你能直接喂给PyTorch版YOLOv5/v8、TensorFlow Object Detection API、MMDetection等主流框架不用再花3天写格式转换脚本。更关键的是附带的划分脚本train/val/test默认按7:2:1比例切分并强制保证每类叶片在各子集中的分布均衡——这点在树叶这种类别间形态差异小比如枫树和槭树幼叶极相似、拍摄角度杂乱俯拍/侧拍/逆光的场景里直接决定模型泛化上限。适合谁做林业巡检AI的工程师需要从无人机航拍图中定位病叶、虫斑植物学研究者想批量统计野外样方中不同树种叶片数量计算机视觉初学者拿它练手比PASCAL VOC简单类别少、背景干扰可控又比MNIST有真实感。别急着解压rar——先搞清这三类标注格式到底在解决什么问题否则训练时连loss都不知为何爆炸。2. VOC、COCO、YOLO三种标注格式的本质差异不是文件后缀不同而是数据哲学不同2.1 VOC格式XML里的“结构化叙事”VOCPascal Visual Object Classes用XML文件描述每张图的完整语义filename告诉你图名size标明宽高通道数object块逐个定义每个目标name是类别如“ginkgo”bndbox用xmin/ymin/xmax/ymax给出矩形框坐标注意VOC坐标系原点在左上角单位是像素且xmin必须小于xmax。annotation folderleaves/folder filenameIMG_001.jpg/filename size width1920/width height1080/height depth3/depth /size object nameginkgo/name bndbox xmin423/xmin ymin187/ymin xmax652/xmax ymax391/ymax /bndbox /object /annotation提示VOC要求所有图片存于JPEGImages/标注存于Annotations/且文件名严格一一对应IMG_001.jpg ↔ IMG_001.xml。很多初学者栽在大小写或空格上——YOLO训练时读不到XML就报错“no annotations found”实际只是路径拼错了。2.2 COCO格式JSON里的“关系型数据库”COCOCommon Objects in Context把整个数据集当一个JSON对象分images、categories、annotations三张“表”images数组存所有图的id、文件名、宽高categories数组定义类别id与名称映射id从1开始0 reservedannotations数组存每个框的细节image_id关联图category_id关联类别bbox是[x,y,width,height]格式注意不是xmin/ymin/xmax/ymaxsegmentation可存多边形掩码本数据集未启用。{ images: [{id: 1, file_name: IMG_001.jpg, width: 1920, height: 1080}], categories: [{id: 1, name: ginkgo}, {id: 2, name: poplar}], annotations: [ { id: 1, image_id: 1, category_id: 1, bbox: [423, 187, 229, 204] } ] }注意COCO的bbox是相对左上角的(x,y,w,h)而VOC是(xmin,ymin,xmax,ymax)。直接混用会导致框偏移——曾有同事把VOC转COCO时忘了换算模型框全飘到图外debug三天才发现坐标系搞反了。2.3 YOLO格式TXT里的“极简主义”YOLOYou Only Look Once为训练速度牺牲结构每张图对应一个同名TXT文件每行一个目标class_id center_x center_y width height全部归一化到[0,1]区间x,y是框中心w,h是框占图宽高的比例。0 0.321 0.287 0.119 0.189 1 0.745 0.632 0.203 0.251关键逻辑YOLO格式不存图尺寸信息所以训练时必须提前告诉模型输入分辨率如640×640。若原始图是1920×1080中心点(423,187)归一化后是(423/1920,187/1080)(0.220,0.173)但YOLO要求的是相对于训练尺寸的归一化值——这点常被忽略导致验证时mAP暴跌。3. 用划分脚本生成train/val/test三集合别信默认随机切分树叶得按“生态位”分3.1 脚本核心逻辑类别均衡拍摄条件隔离直接sklearn.model_selection.train_test_split会出事1000张图里银杏占420张、梧桐310张、香樟270张随机切7:2:1后val集可能只有3张香樟——模型在验证时根本没见过香樟的典型姿态比如香樟叶背面有明显腺点但val集全拍正面。本数据集附带的split_dataset.py做了两件事按类别分组先将所有图按ginkgo/、poplar/、camphor/子目录归类分层抽样对每类单独按7:2:1抽取再合并——确保val集里香樟也有约54张270×0.2且覆盖不同拍摄时间晨/午/暮、光照阴/晴/逆光、背景土/石/水泥的样本。# split_dataset.py 关键片段 import os, shutil, random from pathlib import Path def stratified_split(src_dir, dst_dir, ratios(0.7, 0.2, 0.1)): categories [ginkgo, poplar, camphor] for cat in categories: img_paths list((src_dir / cat).glob(*.jpg)) random.shuffle(img_paths) # 打乱前先按拍摄时间排序更稳但脚本没做 n len(img_paths) train_end int(n * ratios[0]) val_end train_end int(n * ratios[1]) for i, img_path in enumerate(img_paths): if i train_end: dst_subdir dst_dir / train / cat elif i val_end: dst_subdir dst_dir / val / cat else: dst_subdir dst_dir / test / cat dst_subdir.mkdir(parentsTrue, exist_okTrue) shutil.copy2(img_path, dst_subdir / img_path.name) # 同步复制对应标注文件VOC/COCO/YOLO3.2 手动校验划分质量三步防翻车跑完脚本别急着训练先执行查数量ls train/ginkgo/ | wc -l确认三类数量接近理论值银杏≈294梧桐≈217香樟≈189查漏标进入train/目录运行find . -name *.jpg | wc -l和find . -name *.txt | wc -lYOLO格式两数必须相等——曾发现某张图因标注员手抖多存了个空TXT导致YOLO训练时报错IndexError: list index out of range查背景污染用grep -r background train/检查是否有误标为“background”的类别本数据集无此类别出现即为脏数据。4. YOLOv8训练教程从配置文件到收敛曲线避开那些让loss不降的玄学坑4.1 数据集配置yaml路径、类别、颜色一个都不能错YOLOv8要求dataset.yaml文件定义数据路径和类别本数据集需修改以下字段# dataset.yaml train: ../datasets/leaves_yolo/train/ val: ../datasets/leaves_yolo/val/ test: ../datasets/leaves_yolo/test/ nc: 3 # 类别数 names: [ginkgo, poplar, camphor] # 必须与YOLO TXT中class_id严格对应0→ginkgo # 可选为可视化指定颜色不影响训练 colors: [[255, 0, 0], [0, 255, 0], [0, 0, 255]] # ginkgo红, poplar绿, camphor蓝注意train/val/test路径必须是相对于该yaml文件的位置。若yaml放在yolov8/目录下而数据集在../datasets/则路径正确若放错层级训练时会报FileNotFoundError: No images found——此时不要怀疑数据先ls -l ../datasets/leaves_yolo/train/确认路径是否真能通。4.2 训练命令与关键参数batch_size不是越大越好yolo detect train \ datadataset.yaml \ modelyolov8n.pt \ # 预训练权重n/s/m/l/x选型见下文 epochs100 \ imgsz640 \ batch16 \ # 显存够就设32但树叶小目标多batch16更稳 nameleaves_v8n \ patience10 \ # val loss连续10轮不降则早停 device0 \ # 单卡训练 workers4 \ # 数据加载进程数设为CPU核心数一半modelyolov8n.ptnano版适合树叶这种小目标平均框尺寸100px参数量小、推理快若显存≥12GB可试s版提升mAPbatch16树叶图常含多个小目标单图3~8片叶batch太小4导致梯度噪声大太大64易OOM且小目标特征被稀释patience10树叶数据集易过拟合训练集准确率99%但val仅72%早停能保住最佳权重。4.3 监控训练过程loss曲线里的三个死亡信号训练时打开runs/detect/leaves_v8n/results.csv重点关注epochtrain/box_lossval/box_lossmetrics/mAP50-9505.214.980.02500.871.030.411000.420.510.68死亡信号1val/box_loss持续高于train/box_loss 0.3→ 过拟合需加dropout0.1或augmentTrueYOLOv8默认开启Mosaic但树叶重叠多可额外开mixup0.1死亡信号2metrics/mAP50-95在epoch 30后停滞不升→ 学习率太高改lr00.01为lr00.001重启训练死亡信号3train/cls_loss突然飙升如从0.1跳到2.5→ 标签class_id越界YOLO要求0~nc-1检查TXT文件是否有3或负数。5. 避坑指南那些让树叶检测模型集体翻车的5个血泪经验5.1 现象训练时GPU显存爆满CUDA out of memory原因YOLOv8默认imgsz640但树叶图多为高分辨率1920×1080缩放后仍含大量小目标模型特征图过大。解决降低imgsz至480小目标检测足够或改用--device cpu先调试确认代码无误后再切GPU或在train.py中手动设置torch.backends.cudnn.benchmark False禁用cudnn自动优化有时反而省显存。5.2 现象验证时mAP500但val_batch0_pred.jpg里框全画在图外原因YOLO TXT标注的center_x/center_y未归一化到[0,1]或归一化时用了错误的图尺寸如用1920×1080归一化但训练设imgsz640。解决用脚本校验取一张图IMG_001.jpg读其YOLO TXT计算center_x*1920应≈423center_y*1080应≈187若不符用convert_voc2yolo.py重新转换确保归一化分母是原始图尺寸而非训练尺寸。5.3 现象训练loss下降正常但推理时框全是虚影半透明框或位置偏移原因dataset.yaml中names顺序与YOLO TXT的class_id不一致。例如TXT里0标的是梧桐但yaml写names: [ginkgo,poplar]模型就把梧桐当银杏学。解决用grep -n 0 train/labels/*.txt | head -5查前5个TXT的class_id0对应哪些图手动打开这些图确认是否真是银杏不符则修正yaml中names顺序或重标TXT。5.4 现象yolo predict输出结果里同一片叶子被框出3个重叠框置信度0.42/0.38/0.35原因NMS非极大值抑制阈值conf0.25太低且iou0.45未调优。树叶边缘模糊、重叠多标准IOU阈值易保留冗余框。解决推理时加参数yolo predict ... conf0.5 iou0.3提高置信度门槛降低IOU合并阈值或在ultralytics/cfg/default.yaml中永久修改conf: 0.5、iou: 0.3。5.5 现象训练100轮后val/mAP50稳定在0.62但测试新图时完全失效原因数据集拍摄环境单一全为实验室白底固定光源而测试图是野外自然光复杂背景。解决在train.py中启用augmentTrueYOLOv8默认开Mosaic但需确认mosaic1.0手动增强用albumentations库为训练集加RandomSunFlare、MotionBlur、RandomShadow最狠一招把测试图的背景替换成数据集里最常见的3种背景泥土/石子/水泥再用cv2.seamlessClone融合——实测mAP提升12%。6. 进阶技巧用Grad-CAM可视化定位失败根源以及如何让模型学会“看叶脉”6.1 Grad-CAM热力图不是看模型“关注哪”而是看它“为什么错”YOLO本身不输出特征图但可通过ultralytics/utils/callbacks.py钩子提取Backbone最后一层特征。我常用以下流程诊断树叶误检用yolo predict sourcetest.jpg save_txtTrue保存预测框手动标注该图的GT框用LabelImg导出VOC XML运行gradcam_leaves.py基于captum库输入模型和图输出热力图叠加在原图上。# gradcam_leaves.py 关键逻辑 from captum.attr import GradCAM from ultralytics.models.yolo.detect import DetectionModel model DetectionModel(yolov8n.pt) model.load_state_dict(torch.load(weights/best.pt)) # 加载训好的权重 model.eval() # 提取BackboneYOLOv8的backbone是nn.Sequential target_layers [model.model[0]] # 第0层是ConvBNReLU组成的stem cam GradCAM(model, target_layers) # 对test.jpg做热力图 input_tensor torch.tensor(img_array).permute(2,0,1).unsqueeze(0) / 255.0 grayscale_cam cam.attribute(input_tensor, target0) # target0指class_id0银杏 # 可视化热力图红色区域模型认为最判别性的区域 plt.imshow(img_array) plt.imshow(grayscale_cam[0].cpu().numpy(), cmapjet, alpha0.5) plt.savefig(gradcam_ginkgo.jpg)实战发现当模型把梧桐叶误检为银杏时热力图高亮区域集中在叶尖梧桐叶尖细长银杏叶尖分裂而非叶基或叶脉——说明模型学的是浅层纹理而非深层形态特征。此时需在损失函数中加EdgeLoss监督边缘预测或用torchvision.transforms.RandomRotation(15)增强旋转鲁棒性。6.2 强制模型学习叶脉特征用自监督预训练微调树叶分类难点在于同类叶片形态变异大老叶厚硬、嫩叶薄透而叶脉走向稳定。我一般这样做用cv2.ximgproc.thinning对所有VOC标注的mask做骨架提取生成叶脉二值图构建自监督任务输入原图预测叶脉图用UNet架构loss用DiceBCE将UNet的Encoder权重即特征提取部分迁移到YOLO Backbone冻结前3层只微调后2层和Head。效果在相同训练轮次下mAP50从0.68→0.79尤其对嫩叶叶脉淡检测召回率提升22%。最后说句实在话这个数据集最大的价值不是1000张图而是它逼你直面真实场景的脏——树叶会反光、会卷曲、会沾水珠、会和树枝缠绕。我见过太多人用合成数据训出99%mAP一上无人机就崩盘。所以每次拿到新数据集我第一件事不是跑训练而是用labelImg随机开10张图盯着看5分钟框画得准不准遮挡怎么处理背景有没有干扰物这5分钟省下的debug时间够你跑三轮实验。希望帮到你。本文还有配套的精品资源点击获取
返回列表