ARTICLE DETAIL

资讯详情

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

水果检测数据集实战:VOC/COCO/YOLO格式转换与YOLOv8训练全指南

水果检测数据集实战:VOC/COCO/YOLO格式转换与YOLOv8训练全指南 简介这是一份面向目标检测初学者与算法工程师的YOLO水果检测数据集适用于课程设计、模型训练与算法验证等场景。数据均为真实场景采集的高质量图片场景丰富经labelimg精细标注同时提供voc、coco和yolo三种格式标签可直接接入YOLO系列模型训练。压缩包共约2000个文件以1000个xml标注文件和990个txt标签文件为主另含少量html教程、py划分脚本与yaml配置文件整体约107MB目录结构清晰便于按格式取用。资源附赠环境搭建、训练案例教程及数据集划分脚本可自行划分训练集、验证集与测试集帮助读者快速跑通从数据准备到模型训练的全流程并掌握多格式标签转换与数据集组织方法。目前已有1522人学习下载适合需要现成数据与配套脚本快速上手目标检测的读者。1. 水果检测数据集怎么选从1000张图到三种标签格式的完整链路做过水果分拣、智能秤、采摘机器人的人都遇到过同一个问题网上开源的水果数据集要么类别太少要么标注格式不统一拿到手先得花两天写转换脚本。这个标题指向的资源解决的就是这件事——1000张水果图片同时提供VOC、COCO、YOLO三种格式标签外加划分脚本和训练教程。它适合三类人刚入门目标检测想跑通第一个自定义数据集的、做农业视觉产品需要快速验证原型的、以及带学生做课程设计不想在数据准备上耗时间的。我拿到类似数据集的第一反应从来不是直接训练而是先验证三件事图片质量是否一致、标注是否完整、三种格式之间能否无损转换。这三件事决定了你后面是花三天调模型还是花三周修数据。2. 三种标签格式的差异与转换逻辑VOC、COCO、YOLO到底该用哪个2.1 格式差异不在文件后缀而在坐标体系和字段语义VOC格式用XML存储每个目标一个object节点坐标是绝对像素值xmin,ymin,xmax,ymax。COCO格式用单个JSON文件管理所有图片坐标是[x,y,width,height]绝对像素值外加category_id和image_id做关联。YOLO格式每张图一个TXT文件每行class_id x_center y_center width height全部是归一化到0到1的相对值。这三种格式的转换坑集中在两个地方一是VOC的xmax,ymax是包含边界的转YOLO时宽高计算要用xmax-xmin而不是xmax-xmin1差一个像素在1000张图的规模下会让mAP掉0.5到1个点二是COCO的category_id必须从1开始连续而YOLO的class_id从0开始中间少一个类别就会导致训练时标签越界报错。我一般会先统一用VOC作为中间格式因为XML可读性最好出问题能直接打开看。确认无误后再批量转COCO和YOLO。2.2 用Python脚本完成VOC到YOLO的批量转换import xml.etree.ElementTree as ET import os # 类别列表顺序决定class_id必须与训练时的data.yaml一致 classes [apple, banana, orange, pear, grape] def voc_to_yolo(xml_path, img_w, img_h, output_dir): tree ET.parse(xml_path) root tree.getroot() txt_name os.path.splitext(os.path.basename(xml_path))[0] .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as f: for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue # 跳过未定义类别避免class_id越界 cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并计算中心点 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 裁剪到[0,1]防止标注越界导致训练报错 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) w max(0, min(1, w)) h max(0, min(1, h)) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) # 使用示例遍历所有XML图片尺寸从XML的size节点读取 xml_dir annotations/voc output_dir labels/yolo os.makedirs(output_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) size tree.getroot().find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) voc_to_yolo(os.path.join(xml_dir, xml_file), img_w, img_h, output_dir)这段脚本的关键参数是classes列表它的顺序直接决定YOLO训练时每个类别的编号。如果你后面用YOLOv8训练data.yaml里的names必须和这个列表完全一致否则模型学到的类别会错位。另一个参数是归一化后的裁剪操作我见过太多因为标注框超出图片边界导致训练中途loss变NaN的案例加一行max(0, min(1, ...))能省下大量排查时间。2.3 COCO格式的生成与验证COCO格式不适合手写用pycocotools或自己拼JSON都行。核心结构是三个数组images存图片id和宽高annotations存每个框的image_id、category_id、bbox、areacategories存类别id和名称。转换完必须做一次验证用pycocotools加载后统计每个类别的实例数如果某个类别数量为0说明转换时类别名没对上。from pycocotools.coco import COCO coco COCO(annotations/instances_train.json) for cat_id in coco.getCatIds(): img_ids coco.getImgIds(catIdscat_id) ann_ids coco.getAnnIds(catIdscat_id) print(f类别 {coco.loadCats(cat_id)[0][name]}: {len(ann_ids)} 个标注)如果输出里某个类别标注数为0回去检查VOC的name字段是否和COCO的categories名称完全一致大小写和空格都算差异。3. 数据集划分脚本怎么写训练集、验证集、测试集的比例与随机种子3.1 划分比例不是拍脑袋要看类别分布水果数据集有个特点不同类别的图片数量可能不均衡。苹果可能拍了300张葡萄只有80张。如果直接按8:1:1随机划分葡萄的测试集可能只有8张评估结果波动极大。我一般会先统计每个类别的图片数对少于100张的类别做分层抽样保证每个子集里每个类别至少出现一次。import os import random import shutil from collections import defaultdict def split_dataset(img_dir, label_dir, output_dir, ratios(0.8, 0.1, 0.1), seed42): random.seed(seed) # 固定随机种子保证每次划分结果一致 images [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] # 按主类别分组这里简化处理读取对应YOLO标签的第一个类别作为分组依据 groups defaultdict(list) for img in images: label_path os.path.join(label_dir, os.path.splitext(img)[0] .txt) if os.path.exists(label_path): with open(label_path) as f: first_line f.readline().strip() if first_line: cls_id first_line.split()[0] groups[cls_id].append(img) else: groups[unlabeled].append(img) train, val, test [], [], [] for cls_id, imgs in groups.items(): random.shuffle(imgs) n len(imgs) n_train int(n * ratios[0]) n_val int(n * ratios[1]) train.extend(imgs[:n_train]) val.extend(imgs[n_train:n_train n_val]) test.extend(imgs[n_train n_val:]) # 复制文件到对应目录 for split_name, split_imgs in [(train, train), (val, val), (test, test)]: img_out os.path.join(output_dir, split_name, images) lbl_out os.path.join(output_dir, split_name, labels) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for img in split_imgs: shutil.copy(os.path.join(img_dir, img), os.path.join(img_out, img)) lbl os.path.splitext(img)[0] .txt lbl_src os.path.join(label_dir, lbl) if os.path.exists(lbl_src): shutil.copy(lbl_src, os.path.join(lbl_out, lbl)) print(f训练集: {len(train)}, 验证集: {len(val)}, 测试集: {len(test)}) split_dataset(images, labels/yolo, dataset, ratios(0.8, 0.1, 0.1), seed42)seed42这个参数看起来不起眼但它是你复现实验的后悔药。没有固定种子每次运行划分结果不同你调参时根本分不清是模型改了还是数据变了。ratios参数按类别分层保证小类别在验证集和测试集里也有样本否则评估指标会剧烈跳动。3.2 划分后必须检查的三个文件划分完成后检查dataset/train/images和dataset/train/labels的文件数是否一致。不一致说明有图片没有对应标签训练时YOLO会直接跳过这些图你以为是1000张在训实际可能只有800张。第二个检查是data.yaml的路径配置YOLOv8要求train和val指向包含images子目录的父目录写错一层路径就会报No labels found。第三个检查是随便打开一个TXT标签确认坐标值在0到1之间如果有大于1的值说明转换时没做归一化。4. YOLO训练教程的实操细节从环境配置到第一次推理4.1 环境配置的版本匹配比安装步骤更重要YOLOv8用ultralytics包一条pip install ultralytics就能装好。但真正的坑在PyTorch和CUDA的版本匹配上。如果你的显卡是RTX 30系或40系需要CUDA 11.8以上对应的PyTorch版本是2.0以上。我一般用conda建环境conda create -n fruit_yolo python3.10 -y conda activate fruit_yolo pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics装完后用python -c import torch; print(torch.cuda.is_available())验证输出True才算环境通了。如果输出False先别急着训练检查显卡驱动版本是否支持你装的CUDA版本。这一步翻车的人最多症状是训练时loss正常下降但速度极慢因为实际在用CPU跑。4.2 data.yaml的五个必填字段path: /home/user/fruit_dataset # 数据集根目录 train: train/images # 训练集图片路径相对于path val: val/images # 验证集图片路径 nc: 5 # 类别数必须与classes列表长度一致 names: [apple, banana, orange, pear, grape] # 类别名称顺序即class_idnc和names的长度必须一致不一致会直接报错。path用绝对路径最稳妥相对路径在不同工作目录下运行时容易找不到文件。4.3 训练命令与关键参数yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/fruit \ nameexp1modelyolov8n.pt用的是预训练权重1000张图从零训练容易过拟合用预训练模型微调收敛更快。imgsz640是输入分辨率水果目标通常较大640够用如果检测小目标比如单个葡萄粒可以提到1280但显存占用翻倍。patience20表示20个epoch验证指标没提升就早停防止过拟合。batch16在8GB显存下跑640分辨率刚好显存不够就降到8。训练过程中重点看mAP50和mAP50-95两个指标。mAP50到0.9以上算收敛不错如果卡在0.6上不去先检查标签有没有问题再考虑加数据增强或换更大的模型。4.4 推理验证与置信度门限调整yolo detect predict \ modelruns/fruit/exp1/weights/best.pt \ sourcetest_images/ \ conf0.25 \ saveTrueconf0.25是置信度门限低于这个值的检测框会被过滤。水果检测场景下如果漏检多就降到0.1如果误检多就提到0.5。我一般会先用0.25跑一批测试图看误检和漏检的比例再调整。调整置信度门限不需要重新训练直接改推理命令里的conf参数即可。5. 避坑与排查水果数据集训练中最容易翻车的五个地方5.1 现象训练loss正常下降但mAP始终为0原因data.yaml里的names顺序和YOLO标签里的class_id对不上。比如标签里苹果是0、香蕉是1但names写成了[banana, apple]模型学到的类别完全错位。解决用脚本统计每个class_id对应的图片数和names列表逐一核对。最直接的办法是拿一张训练图用yolo detect predict跑推理看输出的类别名是否和图片内容一致。5.2 现象训练到一半报错NaN loss或lossinf原因标签文件里有坐标值超出0到1范围或者宽高为0。VOC转YOLO时如果xmaxxmin宽就是0归一化后还是0计算loss时除零导致NaN。解决在转换脚本里加过滤宽高小于1个像素的框直接跳过。训练前用脚本扫描所有TXT文件检查每行的后四个值是否都在0到1之间。5.3 现象验证集mAP比训练集低很多差距超过0.3原因训练集和验证集的图片分布差异大。比如训练集全是白底拍摄验证集有大量自然背景模型没学过自然背景下的水果特征。解决检查划分脚本是否真的随机打散了数据。如果数据集本身按拍摄场景分文件夹需要先合并所有图片再随机划分不能按文件夹划分。5.4 现象推理时同一张图每次运行检测框数量不同原因没有设置随机种子或者用了数据增强的推理模式。YOLO默认推理时不做增强但如果augmentTrue每次推理会随机变换输入。解决推理命令里不加augment参数默认就是关闭的。如果还是不稳定检查是否有其他随机因素比如多GPU推理时的批次划分。5.5 现象训练速度极慢GPU利用率不到30%原因数据加载成为瓶颈。1000张图如果放在机械硬盘上每个epoch读取图片的时间可能超过计算时间。解决把数据集复制到SSD或者在训练命令里加workers8增加数据加载进程数。workers设成CPU核心数的70%左右比较合适设太大反而会因为进程切换开销降低效率。6. 从1000张到可落地模型数据增强与模型选择的进阶技巧1000张图训练一个水果检测模型如果直接跑YOLOv8nmAP50大概能到0.85左右。想再往上提最有效的不是换更大的模型而是做针对性的数据增强。水果检测有个特殊之处颜色是核心特征但光照变化会严重干扰颜色判断。我一般会在data.yaml同级目录建一个hyps.yaml覆盖默认增强参数# hyps.yaml 自定义增强参数 hsv_h: 0.015 # 色调抖动模拟不同光照下的颜色偏移 hsv_s: 0.7 # 饱和度抖动水果成熟度不同饱和度差异大 hsv_v: 0.4 # 亮度抖动模拟室内外光照变化 degrees: 15.0 # 旋转角度水果在传送带上姿态随机 translate: 0.1 # 平移模拟水果在画面中的位置变化 scale: 0.5 # 缩放模拟不同拍摄距离 flipud: 0.0 # 上下翻转关闭水果不会倒置 fliplr: 0.5 # 左右翻转开启水果左右对称 mosaic: 1.0 # 马赛克增强四张图拼接对小目标检测有效hsv_h设0.015是保守值设太大会让苹果变成香蕉的颜色模型学不到正确特征。degrees15比默认的0更符合水果在分拣线上的实际姿态。flipud0是因为水果检测场景下上下翻转没有物理意义开了反而引入噪声。用这个增强配置重新训练mAP50通常能提升2到3个点。如果还想再提可以试试YOLOv8s参数量从3M涨到11M推理速度在RTX 3060上从2ms涨到5ms精度能再提1到2个点。但如果是边缘设备部署比如RK3588或Jetson Nano老老实实用YOLOv8n精度够用速度才是硬指标。验证模型是否真的可用我习惯用一批没参与训练的实拍图跑推理统计漏检率和误检率。漏检率高于10%就加数据误检率高于15%就提高置信度门限或加负样本。别只看mAP那个数字在真实场景里经常骗人。我自己的习惯是每做完一个数据集就写一个check_dataset.py把图片数、标签数、类别分布、坐标范围全部打印一遍。这个脚本花十分钟写能省下后面十个小时的排查时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表