简介面向深度学习初学者的苹果缺陷目标检测数据集专为练习目标检测模型训练与评估而整理。整套包含1426个文件其中713张苹果实拍图像各配一个XML标注文件标注遵循PASCAL VOC格式包含边界框坐标、苹果位置与缺陷类别压缩包仅5.67MB便于快速下载与本地实验。图像覆盖不同拍摄角度和果实状态可用于训练YOLO、Faster R-CNN、SSD等常见检测模型也可配合PyTorch、TensorFlow框架做迁移学习。目前已有4550人学习使用口碑和适用性经过验证借助这套数据学习者能完整体验数据加载、XML标注解析、模型训练与mAP指标评估等关键环节直观理解目标检测从数据到模型的全流程。实践过程中可掌握标签解析、数据集划分、模型微调等关键技能为后续更复杂的视觉任务打下基础。1. 苹果缺陷检测数据集为什么是第一个决定成败的环节做苹果缺陷的目标检测很多人第一反应是选模型、调参数实际干过才知道数据集才是那个最容易被低估、又最能决定成败的环节。同一个模型在一份干净、分布合理的数据集上能跑到很高的 mAP换一份采集随意、标注粗糙的数据集精度直接掉十几个点而且你怎么调参都救不回来。这个现象在水果质检这类细粒度缺陷场景里尤其明显——腐烂、碰压伤、褐变、刺伤类别多、外观相似、光照影响大数据稍微不给力模型就分不清。这篇笔记围绕苹果缺陷目标检测数据集展开覆盖数据从哪来、怎么采、怎么标、切分和增强怎么设以及训练阶段最容易踩的坑。适合要给分选线或者质检 Demo 配数据方案的工程师也适合想从公开数据集起步、快速跑通基线的新手。读完你能照着搭出一份可训练的数据集并且知道失败时该看哪里。2. 两条数据路线怎么选公开数据集先跑通自制数据集才有底2.1 公开数据集的价值跑通基线的最短路径做苹果缺陷检测第一步不是急着拍照而是先找现成数据集把流程跑通。公开的苹果缺陷数据集通常包含健康果和若干类缺陷果的标注图片类别少则三四类、多则七八类格式常见为 VOC 或 COCO。它的价值在于标注已经完成、类别定义相对清晰你可以不花一分钱标注成本先把训练、验证、推理整套流程打通拿到一个可复现的基线 mAP。我一般会在这一步做三件事。第一用现成脚本把数据集转换成目标检测框架需要的格式确认图片和标注能正常加载第二直接训练一个轻量模型比如小尺寸的 YOLO 变体看 loss 曲线是否收敛、验证集 mAP 是否落在合理区间第三把训练好的模型拖到几张没见过的图上做推理感受一下它对典型缺陷的反应。这三件事做完你就知道后续自制数据要重点补什么了。但公开数据集有两个绕不开的短板。一是缺陷定义和你的实际场景未必一致——公开数据集里的“腐烂”可能是在白色背景下拍的你产线上是深色传送带光照也完全不同模型迁移过去效果大打折扣。二是数量有限一般几十到几百张的量级撑不起真正要上线的模型。所以公开数据集适合验证流程不适合直接落地。2.2 自制数据集贴着真实工况才有意义真正要部署到分选或质检环节自制数据集几乎不可避免。这里最核心的原则是采集条件必须贴近真实工况。常见做法是在产线或者模拟产线环境里架工业相机用和实际运行一致的光源、角度、背景、输送速度来拍摄。为什么要强调这一点因为模型学的是图像特征不是缺陷本身——你把苹果放在黑绒布上拍出来的特征到了绿色传送带上就全变了。还有两个经常被忽略的点。第一相机分辨率不要盲目求高。500 万像素够用分辨率过高会拖慢训练和推理速度而且对标注精度要求更苛刻。第二景深和拍摄距离要固定。苹果是曲面物体同一个缺陷在果面的不同位置形状和光照反射差异很大如果距离和角度不固定模型会把这些差异当成缺陷特征非常麻烦。至于数据量规划我的经验是每类缺陷最少 300 到 500 个实例这是能训练出可辨识特征的下限如果要达到较好的稳定性建议每类 800 个以上并且每个实例都要覆盖不同大小、不同位置、不同成熟度。2.3 两条路线的选择判断标准公开数据集和自制数据集不是二选一而是先后关系。判断标准可以看三点你的缺陷类别和公开数据集是否一致你的采集环境是否可控你的项目周期是否允许花 1 到 2 周做数据准备。如果你的缺陷类别差异很大——比如公开数据集只有碰压伤和腐烂你的实际场景还有果锈和日灼——那公开数据集只能当辅助主力必须来自自制。如果你的环境可控且分选线还没完全定型我建议先拍一小批试验数据训练一次把采集光照、角度、背景调定了再大规模铺开采集避免几千张图拍完发现背景不对、全部返工。提示数据集是项目的资产不是一次性消耗品。后面每次模型迭代、缺陷增多、产线改动数据都要跟着补所以一开始就建立好目录结构和命名规范能省很多时间。3. 自制苹果缺陷数据集的采集与标注让模型真正学到缺陷的细节3.1 采集条件光照、角度和背景是三个硬指标采集条件不达标后面全部白做。光照是第一优先级的因素苹果表面有蜡质层会产生高光和反光同一个碰压伤在有反光和没反光的情况下视觉特征差异极大。我见过的翻车案例里有个团队用普通日光灯拍摄反光区域被模型学成了“缺陷”推理时把好果误判成次品。常见做法是用环形 LED 光源或者两侧对称光源减少单点强反光让果面亮度均匀。拍摄角度要固定并记录。建议相机正对苹果赤道面距离固定在一个范围内这样缺陷的透视形变可控。背景尽量选低饱和、无纹理的深色材质。需要注意苹果是球体边缘区域会变暗如果背景反光强烈边缘缺陷容易和背景混在一起标注的人想看清边界都难。采集批次要刻意覆盖变化。同一批苹果、同一个时间段拍出来的照片特征分布往往过于集中。我会分多天、多批次、不同成熟度状态拍摄每次调换苹果在画面中的位置和朝向。这样可以避免模型把“某天光照偏暖”学成特征。3.2 缺陷类别定义先把判定标准定死再动手标注之前必须明确类别定义否则不同标注员甚至同一个人标到后面都会飘。以苹果常见缺陷为例我习惯把缺陷分成这几类碰压伤受撞击后果肉变色凹陷表面通常是浅褐色边界模糊 腐烂组织软化变色通常颜色偏深、边界不规则有时伴菌丝 刺伤表皮被尖锐物刺破呈点状或线状伤口边界清晰 褐变切开或氧化导致的果肉变色多在伤口或边缘扩散 果锈表皮局部粗糙呈网纹状褐色区域一般不会深入果肉。类别定义要落到标注规范里。比如碰压伤的边界画在哪里是否需要把轻微的颜色渐变区域框进去腐烂是否要求面积超过某个阈值才算正样本。没有这些约定标注结果的一致性会很差模型训出来也会不稳定。定义好之后建议找一个典型样本做标注基准图标注员开工前先对着基准图校准。3.3 标注操作流程选工具、定规范、做复核标注工具我倾向于用开源工具链常见的是 LabelImg、labelme、CVAT 这一类。LabelImg 简单直接适合单机操作CVAT 支持多人协作适合数据量大的情况。选工具不用纠结关键是团队里大家都用同一个工具和同一个标注规范。标注流程我建议三步走。第一步自动预标注——用已经训练好的模型先跑一遍生成候选框标注员在此基础上修正速度能快一半。第二步人工精标和修正。第三步抽检复核——抽 10% 到 20% 的图由第二个人重新过一遍统计标注框和基准的 IoU 偏差偏差大于 0.5 的图打回重标。这里的核心要点是标注质量比标注速度重要得多。一个苹果表面同时有碰压伤和腐烂你要不要分两个框两个缺陷距离很近是合并还是分开这些都需要在规范里白纸黑字写清楚并在前期复核对齐认知。前面省下的时间后面会在训练效果上加倍还回去。4. 切分、增强与格式转换把原始图片变成能直接喂给模型的训练集4.1 数据集划分按批次切不要乱洗牌很多人在划分训练集、验证集、测试集时直接 random split这在苹果缺陷场景是会出问题的。同一批采集中苹果的摆放位置、光照条件、背景都很相似如果同源图片被同时分进训练集和验证集验证集就失去了「没见过的数据」的意义。你会看到训练和验证 loss 都低mAP 虚高真正上线后模型表现一落千丈。这就是典型的数据泄漏。正确的做法是按采集批次切分。比如你分了 6 批采集拿前 4 批做训练第 5 批做验证第 6 批做测试。这样验证集里的图片和训练集来自不同批次光照和摆放都不同评价结果才可信。具体比例如下数据集建议比例用途关键要求训练集60%-70%模型学习权重覆盖所有类别和缺陷形态验证集15%-20%调参和早停与训练集不同批次测试集15%-20%最终评估只用来测一次不要反复看切分脚本很好写按批次目录过滤即可。Python 脚本只需要做目录扫描和随机抽取但抽取时要加上「批次来源」这个过滤条件不要把同批次的图同时分到两个集合。提示测试集是「后悔药」屏障。如果反复用同一份测试集调参模型会对它过拟合所以测试集只能用一次多看一眼都不划算。4.2 离线增强策略不要破坏缺陷本身的视觉特征数据量不够时增强是最直接的补量手段。苹果缺陷场景里我常用的增强包括亮度扰动、对比度扰动、轻微高斯模糊、HSV 色相偏移、随机裁剪、水平翻转、旋转小角度。这些操作能模拟不同光照、不同拍摄距离和角度变化。但增强不是越多越好有两个典型的翻车点。第一旋转角度不宜过大苹果是近似球体旋转超过 30 度会让外形失真模型学到不真实的形态。第二不要用会让缺陷特征消失的增强——比如极强模糊、极端裁剪把碰压伤的边界糊没了等于教你模型「这类缺陷不存在」。增强的幅度应该让人类还能轻松识别缺陷这是底线。增强策略一般放在训练时动态做而不是提前生成多余图片文件。框架本身就带了增强参数配置即可不需要写额外的脚本。如果类别数量严重不平衡可以对少数类做加权抽样让模型每轮都能稳定看到这些类别。4.3 格式转换脚本从 VOC 到 YOLO 的可靠做法不同工具和框架用的标注格式不同最常见的是 VOC XML 和 YOLO TXT。VOC 存的是归一化前的坐标和类别名YOLO 存的是归一化后的中心点坐标和宽高。我从 LabelImg 导出 VOC 格式后会统一转成 YOLO 格式喂给训练。转换脚本不大但边界条件很多直接贴一个经过反复使用的版本import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size).find(width).text) img_h int(root.find(size).find(height).text) # 读取原图名并构造同名 .txt img_name Path(xml_path).stem txt_path Path(out_dir) / f{img_name}.txt lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue # 跳过不在类别清单里的标注 class_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 裁剪越界坐标防止训练报错 xmin max(0, xmin) ymin max(0, ymin) xmax min(img_w, xmax) ymax min(img_h, ymax) if xmax xmin or ymax ymin: continue # 过滤掉空框 # 转成 YOLO 归一化格式 x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: class_names [bruise, rot, puncture, browning, russet] xml_dir annotations/voc out_dir annotations/yolo os.makedirs(out_dir, exist_okTrue) for xml_file in Path(xml_dir).glob(*.xml): voc_to_yolo(str(xml_file), out_dir, class_names) print(f转换完成共处理 {len(list(Path(xml_dir).glob(*.xml)))} 个标注文件)这段脚本的核心逻辑是解析 XML 中的图片尺寸和每个目标框把左上右下坐标换算成中心点加宽高的归一化表示然后写入与图片同名的 txt 文件。其中越界裁剪是容易漏的坑很多标注框会画出图像边界如果不裁剪训练时框变成负数或超出画幅框架会报警告甚至跳过样本。类别索引以 class_names 列表顺序为准这个顺序必须和训练配置里的类别顺序完全一致否则类别会错位。另外脚本里对空框做了过滤这类样本建议单独清点看看是不是标注失误而不是简单丢弃。5. 苹果缺陷检测训练中的 4 个常见坑从标注噪声到类别失衡的排查记录5.1 坑一标注框里混进了果柄和背景模型学歪了现象训练时 loss 能降但验证集 mAP 一直上不去检查预测结果发现模型经常把果柄区域或背景里的阴影框出来。原因标注时把果柄、叶片或者在苹果边缘的阴影区域也框进缺陷类别里了。果柄在视觉上和碰压伤有一定相似性——都是褐色长条状模型根本分不清。解决重新核对标注规范把果柄、阴影、背景杂物明确列为「非目标」标注时只框病变区域本体。同时检查类别定义是否合理如果「碰压伤」和「果柄」在画面里位置和颜色都接近就要考虑调整拍摄角度让果柄尽量不进入画面。5.2 坑二腐烂样本太少模型完全学不动这一类现象训练结果里碰压伤 AP 有 0.85腐烂 AP 只有 0.2而且怎么调参都不涨。原因这是典型的类别不平衡。腐烂样本数量不足模型每一轮看到腐烂的图片太少梯度贡献被其他类别淹没。解决先数各类别的实例数量确认差距。常见做法是给腐烂这类少数类提高 loss 权重或者做离线复制增强——把腐烂样本做多组亮度、对比度扰动扩到接近其他类别的数量。如果数据实在稀缺可以先用公开数据集里相似类别的预训练权重做迁移学习再在自制的少量样本上微调这样模型至少有一个「见过腐烂」的起点。5.3 坑三增强过度把缺陷「增强没了」现象训练 loss 降得很低测试时对真实图片的表现却很差尤其是碰压伤总是漏检。原因增强参数设置过猛比如旋转角度设到 90 度、对比度拉到极端苹果变成了看不出是苹果的椭圆碰压伤的颜色和边界也完全失真。模型学习到的特征偏离了真实分布。解决把增强参数往回收旋转限制在 ±15 度亮度扰动限制在 ±20%模糊半径控制在 2 像素以内。验证方法很简单把增强后的图片抽几张出来看如果人眼都认不出是苹果、找不到缺陷那就是增强过头了。5.4 坑四同源图片泄漏进验证集mAP 虚高不自知现象训练时验证集 mAP 高达 0.9满怀信心部署到产线测试效果却只有 0.6而且错漏方式完全没有规律。原因划分数据集时用了随机洗牌同批次图片在训练集和验证集里都有。模型记住了这批图片的光照和背景特征验证时「作弊」得分。解决按采集批次重新划分数据集保证验证集和测试集里的所有图片所在的批次和拍摄时间与训练集完全不同。这一步没有补救捷径只能重划分、重训练。6. 用训练结果反向验证数据集错误分析、补数据与迭代闭环数据集做完不是终点训练结果的错误分析才是真正告诉你数据缺什么的镜子。我习惯用两步走。第一步在测试集上跑一次完整推理把漏检和误检图全部导出来按错误类型分组漏检的是小缺陷还是大缺陷误检的是把果柄当缺陷还是把阴影当缺陷。第二步对着分组结果逐一找数据原因。比如漏检集中在暗光图片说明训练集里暗光样本不够误检集中在小面积刺伤说明这类样本标注边界不清晰或者数量不足。这样改数据是有的放矢而不是瞎补。补数据也有优先级。先补模型错得最直接的类别——比如误检率最高的那个缺陷类型再补最容易导致漏检的「难例」——比如小缺陷、暗光下的缺陷、多个缺陷重叠的样本。每次补完后不要混进原训练集直接训而是给新数据单独建目录、做版本标签跑一次完整的训练和验证对比确认 mAP 提升后再并入正式数据集。我给不同批次的图片命名时会带上日期和批次号比如20250611_rot_batch03_001.jpg这样训练记录里能直接追溯到数据集版本排查问题非常方便。最后分享一个习惯每次训练前先把数据集统计打印出来包括类别实例数、每类平均宽高比、图片亮度分布。这个动作只需几十秒但能让你在训练前就发现类别失衡、样本过少这些隐患而不是等训练两天后才怀疑数据有问题。这个习惯帮我避免过不止一次返工也让我逐渐明白数据集的质量决定了模型效果的上限训练调参只是去逼近那个上限。希望这些经验能帮你在苹果缺陷检测的数据准备上少走一些弯路。本文还有配套的精品资源点击获取