)
目标检测数据集 第059期-基于yolo标注格式的水果李子检测数据集(含免费分享)做目标检测的朋友应该都有体会训练一套能用的模型最难的不是模型本身而是数据。去年我自己做农业场景的检测项目时光是整理果园里的水果数据就折腾了快两周白天拍图、晚上标注眼睛都快看花了。后来我就想着既然自己已经踩过一遍坑不如把整理好的数据集按系列分享出来既能方便同行直接拿去用也能顺便聊聊数据集背后那些文档里不会写的细节。这一期是第059期主角是李子标注格式用的就是目标检测里最常见的YOLO格式。这套数据集解决的核心问题很明确给需要做水果检测、农业自动化采摘、果园产量估算或者商品分拣的朋友提供一份拿来就能训练的现成数据。每张图都是实拍的果园场景包含不同成熟度的李子标注框覆盖了密集排列、枝叶遮挡、光照变化这些真实存在的难点。你可以直接拿去做YOLOv5、YOLOv8甚至YOLOv11的训练也可以作为学习YOLO标注格式的参考样例。无论你是刚接触目标检测的学生还是已经在做落地项目的工程师这套数据都能帮你省掉大量采集和标注的时间。1. 数据集整体设计与采集思路拆解1.1 为什么选择YOLO标注格式现在主流的目标检测标注格式无非就是三种COCO的JSON格式、VOC的XML格式、YOLO的TXT格式。我做这个系列的数据集时毫不犹豫选了YOLO格式原因很现实。首先YOLO系列的迭代版本是目前工业界和学术界应用最广的目标检测框架之一从YOLOv5开始到现在的YOLOv8、YOLOv11GitHub上随便一搜就是上万个项目的训练记录。选YOLO格式意味着这套数据能被最大范围的人直接使用不需要做格式转换。虽然COCO和VOC格式也有各自的生态但如果你用了YOLO框架最终训练前还是得把JSON或XML转成TXT与其让使用者多一步转换不如直接在源头就用最通用的格式。其次YOLO格式本身极其简洁。一个标注文件就是一行一个目标每行五个字段类别ID、归一化后的中心点x坐标、中心点y坐标、归一化后的宽、归一化后的高。没有嵌套的JSON结构没有复杂的XML节点用记事本都能打开检查。这对数据校验和排错来说非常友好。注意YOLO格式的坐标全部是相对于图片宽度和高度的比例值取值在0到1之间不是像素绝对值。很多人第一次接触时容易在这里踩坑后面我会详细讲。1.2 李子目标的特点与采集难点李子这个目标检测起来其实比想象中要麻烦。它不像苹果那么规整也不像橙子那样颜色统一。李子的品种很多常见的有黑布林、红李、青李成熟度不同颜色差异巨大从青绿色到紫红色都有。这意味着模型不能只靠颜色特征来识别必须学习到果实的轮廓纹理和形态特征。我在采集图像时重点考虑了以下几个场景变量。第一是光照条件。果园里的拍摄时间和天气直接影响图像质量。晴天正午的强光会在李子表面形成高光反射让果实边缘变得模糊傍晚的低照度环境又会让暗色李子和背景融为一体。所以数据集里既有上午九十点的顺光拍摄也有下午四五点的侧光、逆光场景甚至包含了几十张阴天条件下拍摄的图像。第二是遮挡问题。李子树的结果方式是一串一串的果实之间互相紧挨着还有大量叶片和枝条遮挡。很多刚接触目标检测的初学者不理解觉得标注图片就该把每个目标都标得干干净净但实际情况是遮挡目标恰恰是模型训练里最需要关注的样本。如果一个数据集里全部是完美无遮挡的目标训练出来的模型一到真实场景就会失效。第三是密集小目标。李子的果实直径在图片里往往只占几十个像素特别是挂在树冠高处的果实从地面拍摄时非常小。这种小目标检测本身就是目标检测领域的难点需要模型有较强的特征提取能力。1.3 数据集构成与标注统计整个数据集我按系列编号整理为第059期共包含图片1100张标注目标总数约42000个平均每张图约38个目标。单张图中目标数量最多的超过80个最少的也有5个左右。我专门保证了一个细节训练集、验证集、测试集三个子集之间图片没有任何重叠。很多偷懒的数据集直接把图片随机分配导致同一次拍摄的连拍图片同时出现在训练集和验证集中评估出来的mAP虚高一到真实场景就原形毕露。我这套数据在做划分时是按拍摄场景来切的也就是说同一棵树、同一时间段的照片会被划分到同一个子集中避免数据泄露的问题。另外标注时我用了统一的边界框标准框必须紧贴果实的可见部分如果果实被遮挡超过70%则该目标不标注。如果遮挡在30%到70%之间按可见部分的最小外接矩形来标。这里面的判断标准我在后面会展开讲讲。2. 标注格式详解与YOLO格式核心要点2.1 TXT标注文件的字段含义YOLO格式的标注文件是和图片同名的TXT文件比如图片名叫img_001.jpg对应的标注文件就是img_001.txt。每一行代表图片中的一个目标对象五个字段用空格分隔。0 0.492188 0.581250 0.120500 0.081250这一行表示第一个字段0是类别ID因为数据集里只有李子这一种目标所以统一是0第二个字段0.492188是目标中心点的x坐标除以图片宽度后的归一化值第三个字段0.581250是中心点的y坐标除以图片高度后的归一化值第四个字段0.120500是目标框宽度除以图片宽度第五个字段0.081250是目标框高度除以图片高度。计算方式也很简单。假设图片宽度是640一个目标框的左上角像素坐标是(260, 350)右下角像素坐标是(340, 400)那么框的像素宽度340 - 260 80框的像素高度400 - 350 50中心点x像素坐标260 80 / 2 300中心点y像素坐标350 50 / 2 375归一化中心点x300 / 640 0.46875归一化中心点y375 / 800 0.46875假设图片高800用公式表示就是x_center_norm (x_min x_max) / 2 / img_width y_center_norm (y_min y_max) / 2 / img_height width_norm (x_max - x_min) / img_width height_norm (y_max - y_min) / img_height2.2 坐标系与格式版本的区别这里要特别提醒一下YOLO格式其实有细微的版本差异。早期YOLO框架用的是中心点坐标加宽高的格式也就是上面说的这种。但是YOLOv5官方仓库里提供的数据集在labels目录下被读取时也是同样的格式。你只要记住这个通用的五字段格式就不会出错。另外还有一点容易混淆YOLO格式的类别ID是从0开始计数的不是从1开始。如果你只有一类目标那就是0不是1。我见过不少新手训练时报错说class id out of range一查发现是自己把类别ID写成了1而数据集的类别配置里只有下标0。标注文件的路径和图片路径的对应关系也是一坑。在YOLO框架里常见的目录结构是这样的dataset/ ├── images/ │ ├── train/ │ │ ├── img_001.jpg │ │ └── ... │ └── val/ │ ├── img_101.jpg │ └── ... └── labels/ ├── train/ │ ├── img_001.txt │ └── ... └── val/ ├── img_101.txt └── ...图片文件的组织方式就是按train和val两个目录来放标注文件也必须按照相同的子目录结构放在labels文件夹下。框架在训练时会自动根据图片路径去对应的labels目录找同名的TXT文件。2.3 标注质量的可视化校验方法标注完之后最怕的就是坐标出错。YOLO格式因为是归一化坐标人眼直接看数字很难发现问题。我的习惯是写一个脚本把标注框画到图片上快速扫一遍。import cv2 def draw_yolo_boxes(image_path, label_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(label_path, r, encodingutf-8) as f: lines f.readlines() for line in lines: parts line.strip().split() cls_id int(parts[0]) x_c float(parts[1]) * w y_c float(parts[2]) * h bw float(parts[3]) * w bh float(parts[4]) * h x_min int(x_c - bw / 2) y_min int(y_c - bh / 2) x_max int(x_c bw / 2) y_max int(y_c bh / 2) cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2) cv2.putText(img, class_names[cls_id], (x_min, y_min - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) return img # 使用示例 img draw_yolo_boxes(img_001.jpg, img_001.txt, [plum]) cv2.imwrite(check_img_001.jpg, img)每次标注完一批图片不管有多累我都会抽出大概30张做可视化检查。重点看三类问题框是否偏移、框是否过大包含太多背景、框是否过小只框住了果实的一部分。可视化检查虽然简单枯燥但它是最能保证标注质量的手段比任何统计脚本都靠谱。3. 用这个数据集训练模型的实操全流程3.1 环境准备与基础依赖要拿这套数据去训练第一步是把Python和PyTorch环境搭好。我的建议是用Python 3.9以上版本PyTorch的版本根据你的显卡CUDA版本来定。目前Ultralytics的YOLOv8对环境的兼容性做得比较好直接安装即可。pip install ultralytics如果你的机器有NVIDIA显卡建议装GPU版PyTorch训练速度会快很多。安装完Ultralytics之后框架会自动带上来所有需要用到的依赖比如OpenCV、NumPy、Pandas这些。我一般还会额外装一个matplotlib方便训练完成后直接看损失曲线和混淆矩阵。3.2 数据集目录的整理与转换拿到我分享的数据集压缩包之后解压出来的结构是这样的plum_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ ├── data.yaml ├── classes.txt └── README.md其中data.yaml是训练时必须要用到的配置文件。你可以打开看一下内容大致如下# data.yaml train: ./plum_dataset/images/train val: ./plum_dataset/images/val nc: 1 names: [plum]train和val填写图片目录的路径注意这里指到images下的训练和验证子目录即可框架会自动去对应的labels目录找标注。nc是类别数量number of classes这里填1。names是类别名称列表注意列表的下标要和标注文件里的类别ID对应。这里names[0]是plum标注文件里的0就指向它。如果你要自己扩展这个数据集加一个新的类别比如想同时检测李子和苹果那就把标注文件里李子的类别ID保持为0苹果的ID标为1然后把nc改成2names改成[plum, apple]。注意修改data.yaml里的路径时建议用相对路径并且确保运行训练命令时的工作目录在数据集的上层目录。不然换台机器跑绝对路径对不上就会报找不到图片文件的错。3.3 YOLOv8训练命令与关键参数选择整理好目录结构之后训练的命令非常简洁YOLOv8把大部分功能都集成到了命令行工具里。yolo train dataplum_dataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0这条命令的意思是用yolov8n.pt作为预训练权重基于plum_dataset数据集训练100轮输入图片尺寸缩放为640x640批次大小16使用第0张显卡训练。但如果你是第一次跑我建议不要直接抄这条命令而是先跑一个50轮的快速版本把训练集切一小部分出来做验证确认数据集没有问题再正式开始。去年我帮朋友跑一个数据集就是没做小验证直接开全量训练跑到第30轮才发现数据集的标签有问题白白浪费了一天时间。几个关键参数我展开说一下。模型选择YOLOv8有n、s、m、l、x五个尺寸从nano到extra large。李子检测属于相对简单的单类别目标检测任务我用yolov8n或yolov8s就足够了。nano模型参数量只有3.2M文件大小约6MB无论是在GPU还是CPU上跑推理都非常快。如果你的目标是做高精度统计再换yolov8m也不迟。imgsz输入图片尺寸。数据集中原始图片是1080P的训练时统一缩放到640x640。这个值不是越大越好因为显存有限图片尺寸增大会占用大量显存空间而且小目标在缩放到640之后如果标注时没有处理好小目标框反而会造成精度下降。epochs训练轮数。我建议起步设100轮然后观察训练曲线是否收敛。一般来说当验证集损失不再下降时就可以考虑提前终止不需要盲目加轮数。batch批次大小取决于显卡显存。8GB显存跑yolov8n用 batch16没问题如果是yolov8m建议降到8。device设备ID0表示第一张显卡CPU训练则填cpu。CPU不是不能训练但要训练到可用状态时间大概比GPU慢20倍以上强烈建议至少用一个入门级的GPU。3.4 训练过程监控与结果评估训练开始后终端会实时输出每一轮的损失值、精度、召回率、mAP50和mAP50-95等指标。这里我解释一下这些指标的含义。precision精度预测出来的目标中真正是李子的比例。精度高代表误检少。recall召回率图片中真正的李子被模型找出来的比例。召回率高代表漏检少。mAP50IoU阈值设为0.5时所有类别的平均精确率这是最常用也最直观的评价指标。mAP50-95IoU阈值从0.5到0.95每隔0.05取一个值计算平均值。这个指标更严格反映模型在不同重叠度要求下的综合表现。用我分享的这套数据集做训练正常情况下单类别的mAP50是能跑到95以上的。如果你的结果明显低于这个值大概率是数据使用环节出了问题不要急着调模型参数。训练完成后在runs/detect/train目录下会生成一堆结果文件。这里我重点推荐看三样东西。第一是confusion_matrix.png看混淆矩阵。单类别任务里主要就是看background那一栏的误检严重不严重如果背景被误检的比例太高说明模型学到了很多无关特征。第二是results.png这里面画了训练过程的损失曲线和指标变化曲线。重点看val/box_loss这条曲线如果它在训练后期还在持续下降说明模型还能继续学可以适当增加轮数。第三是val_batch0_pred.jpg这是模型在验证集上的预测可视化图。直接看图最直观框是不是紧贴果实、有没有漏检、有没有重复框一眼就看出来了。4. 常见问题与排查技巧实录4.1 训练损失不下降指标一直很低这种情况是最让人崩溃的。我遇到的90%的损失不下降问题根源都不在模型参数而在数据本身。先检查标注文件的类别ID是否越界。YOLO框架会读取data.yaml里的names列表长度来判断类别数量如果你的标注文件里出现了1而names只有[plum]一项训练会直接报错。如果框架出于兼容性没有报警而是默默忽略掉异常块那损失就会卡在一个高位掉不下去。再检查图片路径是否和标注路径对应。常见错误是图片在images/train但标注文件被误放到了labels/val导致框架在训练时找不到与之匹配的TXT文件。这种问题框架往往不会提示它只会默默地把没有标注的图片当作背景样本用来训练。一张图片没有标注输入网络后就等于告诉模型这里没有任何目标如果这样的图片数量一大模型就会倾向于输出空预测指标自然上不去。还有一个容易忽略的问题是图片格式。YOLO框架支持jpg、png和bmp格式但如果你从网上下载的数据集里混入了webp格式的图片OpenCV在读取时可能会失败训练进程会跳过这些图片。我用脚本统计过数据集的图片可读性发现有个别图片在采集复制过程中文件损坏了不处理就会白折腾。4.2 标注框过大或过小影响模型精度标注框的质量直接决定模型学习的质量。如果框过大把李子和旁边的叶子一起框进去了模型学习到的特征就会附带大量背景信息导致检测框预测出来偏大。如果框过小没有完整框住果实模型又会学到不完整的果实特征导致检测框偏小。我整理标注规范时的经验如下果实全露且无遮挡标注框紧贴果实轮廓边缘留1到2个像素的余量即可。果实部分被叶子遮挡标注可见部分的最小外接框不要尝试去补全被遮挡的区域。果实重叠在一起每个果实单独标注即使边界有交叠也没关系只要每个框内主要目标是该果实就行。果实小于图片宽度的3%这种极小目标如果数量不多建议直接不标注因为即使标注了在缩放到640后目标只有十几个像素模型很难学到有效特征反而会干扰训练。4.3 类别不平衡与单类数据集的特殊处理我这里分享的数据集是单类别的所以不存在类别不平衡的经典问题。但如果你打算在这个数据集基础上扩展成多类别那就得提前注意到这一点。比如你想把检测范围扩大到多个水果品种每种水果的数量就必须大致相当。如果李子有4000个目标苹果只有200个目标模型在训练时会严重偏向李子苹果几乎学不到有效的特征。解决办法有几个一是增加苹果图片的采集和标注二是用数据增强工具对苹果图片做复制粘贴式的增强让苹果在每张图中的出现频率接近李子三是在训练时给不同类别配置不同的损失权重。数据增强是我自己用得比较多的手段。Ultralytics框架内置了丰富的增强策略比如随机翻转、旋转、缩放、HSV色域变换、马赛克拼接等。训练时默认开启的增强效果已经不错如果发现模型对光照变化不敏感可以调大HSV增强的参数让模型看到更多样的颜色变化。李子在不同成熟度阶段颜色差异大适当的颜色增强能帮助模型学到更鲁棒的特征。4.4 目标太小漏检严重在果园场景里小目标检测是最头疼的问题之一。很多李子在树冠高处相机离得远成像后目标区域只有20x20像素左右。碰上小目标漏检我的处理顺序是先看标注的最小目标尺寸分布统计一下数据集中宽度小于32像素的标注框占比。如果这个占比超过20%说明小目标本身很多光靠换大模型不一定能解决。常用的改进思路有两个方向。第一个方向是在训练时把输入图片尺寸调大。imgsz640时一个20x20像素的目标在缩放后仍然是20像素左右但如果把imgsz调到960目标在特征图上的尺寸会变大模型更容易提取到特征。代价是训练速度变慢、显存占用增加。第二个方向是使用多尺度训练。Ultralytics在训练时默认会以一定概率在imgsz*0.5到imgsz*1.5之间随机缩放输入尺寸这能在一定程度上增强模型对不同尺度目标的适应能力。如果你想强化小目标检测可以把增强比例适当调高。4.5 常见问题速查表问题现象可能原因排查与解决训练报错 class id out of range标注类别ID与names列表不匹配打开TXT文件核对类别ID从0开始计数损失不下降mAP始终低于0.5训练集图片缺少对应标注文件核对images与labels目录对应关系训练指标很高真实场景检测效果差数据划分存在数据泄露确保同一场景的图片不跨训练/验证集检测框整体偏大标注时框进了过多背景重新标注收紧框边界检测框整体偏小标注时只框住了部分果实重新标注完整覆盖果实可见区域小目标漏检明显目标尺寸过小或数量不足调大imgsz或增加小目标样本数量训练速度极慢没有用GPU或batch过大检查NVIDIA驱动确认CUDA可用5. 数据集的扩展应用与进阶方向5.1 从检测到分割的扩展思路这套李子数据集虽然是检测标注格式但它完全有能力扩展成实例分割数据集。YOLOv8本身就支持实例分割任务Ultralytics也提供了一些半自动标注工具可以在检测框的基础上用SAM模型分割出精细的果实轮廓再导出为分割标注格式。到了这一步你能做的事情就更多了。检测只能告诉你哪里有几个李子分割能告诉你李子的形状和大小。用分割结果算果实直径、估算产量都是很自然的延伸。5.2 用这个数据集做模型评估对比另外一个很好的用法是把这套数据当作基准数据集用来评估不同目标检测模型在同一批数据上的表现。我在整理这个系列时每期数据集都会用YOLOv8n和YOLOv8s跑一遍基准实验记录mAP50、mAP50-95、推理速度、参数量等指标。这样一来后续你在自己的数据集上做模型选型时就有了可比较的参照系。表格里是我用这套李子数据跑出来的基准数据模型参数量推理速度(ms)mAP50mAP50-95YOLOv8n3.2M1.20.9430.786YOLOv8s11.2M1.80.9570.812这个结果说明单类别的水果检测任务小模型已经能取得相当不错的效果。如果你部署的设备算力有限选nano版本完全可行如果有余量s版本在mAP50-95上的提升还是比较明显的。5.3 踩坑记录夜间和强反光场景最后分享一个我在采集时踩过的坑。第一次采集时我特意拍了一批夜间果园的照片想着夜间采摘也是实际应用场景多一种光线条件能让模型更鲁棒。结果训练完之后夜间照片的检测效果极差。分析之后发现夜间为了拍清果实必须开闪光灯闪光灯拍出来的李子和自然光下拍摄的李子在颜色分布和纹理细节上差异非常大模型很难跨域泛化。后来我调整了策略要么彻底不包含夜间样本让模型专注于白天场景要么专门采集大量夜间样本单独训练出一个夜间模型。两边兼顾的结果通常是两边都做不好。这个经验让我认识到数据集不是越杂越好关键是要和应用场景匹配。如果你用这套数据做产品原型验证最好在部署前再采集一批目标场景的真实图像做测试确认模型在你的光照条件下依然稳定。6. 获取方式与使用须知这份第059期李子检测数据集我是完全免费分享的。包含1100张实拍图片、对应的YOLO格式标注文件、数据配置文件以及这份详细的说明文档。获取方式是将回复发至我的公众号回复关键词数据集059即可得到下载链接。使用前请留意以下几点数据仅供学习研究使用如需商用建议自行补充采集一批目标场景的数据再做微调。解压后先用可视化脚本检查标注质量确认没问题再开始训练。训练时如果显存不足优先降低batch其次再考虑降低imgsz。提示分享数据的初衷是帮助大家少走弯路如果这套数据对你的项目有帮助欢迎转发给有需要的朋友。也欢迎在评论区留言分享你的训练结果互相交流参数调优的经验。7. 我的一点心里话做数据集分享这几十期下来我最大的感受是目标检测项目真正难的从来不是跑通一个模型而是让模型在你自己的场景里稳定可靠。一套干净的、标注规范的数据集能让整个训练过程变得顺畅无比而一份充满脏数据的垃圾数据集无论你模型调得再好最终效果也是天花板很低。我自己在标注这1100张李子图片时前后花了差不多五个晚上标注完还要做可视化校验、修正、再校验最后才敢把数据放出来。我不敢说这套数据的标注质量是全网最高的但我可以保证每一张图片的标注框都是人工逐张检查过的不是用自动标注工具草草生成的。自动标注工具用来预标注省时间没问题但一定要人工复核尤其是像李子这样密集排列、互相遮挡的目标自动标注的结果基本都不太能用。如果你正在做水果检测、农业自动化或者类似的视觉项目希望这份数据集能帮你省下宝贵的准备时间。后续这个系列我还会继续更新其他水果和农作物的检测数据集大家有特别需要的目标类别也可以留言告诉我。