
简介目标检测是计算机视觉的核心任务其模型性能高度依赖训练数据的质量与标注规范。在智能农业等真实场景中公开数据集往往难以覆盖复杂光照、遮挡等实际条件自制数据集成为提升模型泛化能力的关键路径。通过Labelme等标注工具对图像进行精准的多边形标注能够为目标检测模型提供更贴合物体轮廓的监督信息。随后将标注格式转换为YOLO等主流框架所需的标签格式经过数据划分和模型训练即可实现针对特定目标的可靠检测。本文以苹果果实检测为例完整展示了从数据采集、标注标准制定到YOLOv8训练落地的全流程实践。 做目标检测的朋友应该都有同感很多时候决定模型上限的并不是网络结构而是你手里的数据。我去年接到一个果园智能监测的项目目标很明确——在复杂田间环境下检测苹果果实为后续的测产和自动采摘提供视觉基础。模型选型倒是好办YOLO系列一上难点瞬间转移到数据集这边网上公开的苹果数据集要么背景单一要么标注框粗糙跟实际果园场景差距太大。咬牙决定自己标项目标题写着苹果果目标检测-labelme-4430其实就是这个过程的产物4430张真实果园图片用Labelme逐张手工标注最终训练出能在遮挡、逆光、密集场景下稳定工作的苹果检测模型。这篇就把我从采集筛选、标注规范、格式转换到YOLOv8训练的全过程拆开讲清楚踩过的坑、标废的图、调参的教训都整理在下面给正准备自己造数据集的朋友一份可以照着抄的作业。1. 数据集项目整体拆解目标、难点与方案选型1.1 项目需求与标注对象的定义先说需求。果园智能化项目里苹果检测看似简单实际训练时你会发现它比通用目标检测要刁钻得多。苹果果实有几个天然难点第一果实之间互相遮挡有时候只能看到一半甚至三分之一第二苹果颜色和树枝、树叶在某些光照下接近前景背景对比度很低第三挂在树梢上的果实离相机远像素占比小属于典型的小目标第四一天之内光照变化剧烈顺光和逆光下同一个果实的视觉特征差异很大。所以我拿到这个需求后第一件事不是急着标注而是把所有参与标注的人叫到一起定了三条规定。第一条检测对象是果实不是果树区域。一张图里有5个苹果就标5个框有20个就标20个哪怕被树叶挡住70%但轮廓可辨也要标出来。第二条所有标注必须用多边形不能用矩形。原因后面细说但这里可以先给结论苹果这种近圆形物体用多边形贴合训练出来的边框比矩形精准得多而且对边缘遮挡的判定更友好。第三条凡是我们自己人都无法确认是不是苹果的区域一律不标。宁缺毋滥否则就是在给模型喂噪声。1.2 数据集规模4430张图的构成逻辑很多人看到4430这个数字第一反应是问够不够。我先说结论对单类别检测任务来说训练集有3500张以上、每张平均1到8个目标基本够用但前提是场景足够多样。我把4430张分成了三组训练集3980张、验证集250张、测试集200张。关键不在总数而在分布。我的图片来源不是单一摄像机而是三台不同设备在不同果园采集的。第一台是手机上用的普通摄像头取景范围广相邻果实间距大第二台是果园固定监控视野远果实在画面里普遍偏小专门用来锻炼小目标检测能力第三台是采摘机器人上的近距离相机果实填满视野边缘大、纹理清楚。三种源头的图交替混入训练集模型就能学到不同尺度下苹果的通用特征而不是只认某一台相机的画质。还有一个细节9月和10月的苹果状态完全不一样。9月青果多颜色偏绿10月红果多颜色偏红。如果数据集全部是红果模型在青果期的检测就直接报废。我在采集时特意按6比4的比例混合了红果期和青果期图片让模型不至于对某个成熟度过拟合。1.3 为什么选Labelme而不是其他标注工具目标检测的数据标注工具主流有几款LabelImg、Labelme、CVAT、Roboflow、X-AnyLabeling。项目里我选了Labelme原因其实很实际。LabelImg支持矩形框标注操作最轻量但它只能出矩形。苹果果实密集时矩形框会大量重叠一个框里经常混进两个目标训练时NMS一压小果实直接被吞掉。Labelme则是老牌的图像标注工具核心支持多边形、圆形、矩形、线、点五种标注类型数据格式直接保存成JSON能把每个标注对象精确贴合轮廓。物体边缘被树叶遮得像锯齿一样你用多边形绕着可见部分走一圈模型学到的就不是完整矩形内的红色特征而是和背景天然分离的果实边界特征算法辨识度高很多。另外Labelme的JSON格式非常开放几乎可以无损转成任何训练框架需要的格式。你可能今天用YOLOv8明天想换Detectron2后天又想试试MMDetection这些框架的标签格式各不相同但Labelme的JSON就像一个通用中间层转换脚本一写全平台通吃。这种自由度在项目开发期尤其宝贵因为模型选型往往不是一次定死的。2. 环境准备与Labelme安装实操2.1 安装步骤与Python环境安装Labelme本身不难但如果你对Python环境不熟这里还是有几个坑。我当时的操作步骤如下。先确认Python版本。Labelme官方建议Python 3.7到3.9我实测Python 3.10也能正常跑但有网友反馈3.12以后某些依赖版本会冲突。如果电脑里装了多个Python我强烈建议单独建一个虚拟环境不要直接怼到base环境里。# 创建独立虚拟环境 conda create -n labelme python3.8 conda activate labelme # 安装Labelme pip install labelme安装完成后命令行输入labelme就能启动。如果走的是conda环境有些系统需要先装pyqt依赖但pip安装会帮你自动带上一般不用额外处理。我遇到过的情况是第一次装好后点击标注工具没反应后来发现是PyQt5的版本和系统图形库冲突直接用pip install labelme[all]会强制安装一套经过测试的pyqt依赖组合这个坑就没了。所以如果你在比较干净的环境上装建议直接pip install labelme[all]2.2 常用功能配置与界面速览Labelme启动后默认界面是英文的。界面左边是图像预览区右边是文件列表和标注图层区。标注的入口藏在顶部菜单Edit里面快捷键一览也很直接。我标了四千多张图之后最常用的操作其实是这几个CtrlN新建标注文件CtrlS保存当前标注CtrlD复制当前标注并应用CtrlZ撤销上一步菜单Edit-Create Polygons开始多边形标注菜单Edit-Create Circle标圆形区域一个比较好用的隐藏功能是自动保存。在命令行启动时加一个--autosave参数标注完一张图切到下一张系统自动把JSON保存到图片同目录不用每张手动按CtrlS。批量标注时这个功能能省不少时间也防止你漏存文件。labelme --autosave注意--autosave只会自动保存标注数据不会自动生成下一张图你得自己切换图片。如果只想标注某几个文件夹的图片可以进去后点左边Open Dir选择图片目录右侧文件列表里会列出所有图片点文件名切换。2.3 安装和启动中的常见报错与规避关于安装和启动我整理过一张问题速查表这里直接放出来。现象常见原因解决办法启动后界面空白PyQt图形库加载失败重装PyQt5pip install PyQt55.15.9打开图片时闪退图片路径有中文或空格把图片和JSON目录统一改成英文路径多边形画到一半消失没有连续点击误碰了Esc重新画记得每个锚点都要单击确认JSON保存不了目录没有写权限以管理员方式启动终端或换个目录标注很卡、CPU飙高图片分辨率过大先压缩到1920边长以内再标注这里多说一句如果图片过大4K原图直接喂进Labelme拖动时CPU经常满载而且保存的JSON里坐标是像素绝对值超高清图反而会让训练时图像缩放比例失真。我当时定的标准是把所有图片统一缩放到长边1440像素再标既能看清细节又不至于让标注体验崩溃。3. 苹果果实标注实操全流程3.1 标注流程分步解析标注这个环节是整个数据集成败的核心比后面训练调参重要得多。我把它拆成五个步骤每一步都形成了固定的肌肉记忆。先创建类别。在Labelme里点击左边Edit下的Create Polygons弹窗会让你输入标签名称。这里我用的是英文apple不设第二个类别。类别少时建议保持简洁千万别一会儿填apple一会儿填苹果同一个目标出现两种标签转格式时定位到不同类别模型直接就混乱了。接着标注果实。鼠标左键在果实边缘依序打点每点一下生成一个锚点系统会把锚点连成多边形。锚点数量控制在12到20个之间比较合适太少形状失真太多锚点连成锯齿训练时反而给模型增加噪音。苹果是圆形沿着边缘顺时针打点一般14个点左右就够。然后标遮挡果实。这是手工活里最耗心力的部分。多个果实叠在一起时注意每颗果实的可见边缘都要尽量贴合肉眼可见的轮廓线不可见部分用直线连接不要脑补看不见的弧线。我踩过的坑是一开始为了追求接住全部面积把被遮挡的部分也画成一个很大的圆结果那个框实际包含了前一个果实的一半区域训练时模型根本分不清两个目标的分界。标完就保存。保存出来的JSON文件里包含图片名、图片尺寸、每个标注对象的label和points坐标。每次保存前再扫一遍图片有没有漏标、错位、标签不对的确认无误再切下一张。我和团队成员约定了一个铁律任何情况下都不允许先保存后补标。3.2 标注难点与标准制定这个部分我想重点讲讲标注标准怎么明细化。标准不只是画个框这么简单比画框更重要的是什么情况下算一个目标。苹果果实检测的边界情况比想象中多。有些果实只露出一个角肉眼能确定这是苹果但露出的面积不到10%有些果实被大面积树叶覆盖只漏出一条红色缝隙还有掉在地上的苹果和挂在树上的苹果混在一起你要不要都标这些如果不在开工前定调标出来的数据一定五花八门。我和团队最终定的标准是这个版本果实可见面积超过30%且能辨认出完整轮廓标。果实可见面积在15%到30%之间但轮廓可辨标。果实可见面积低于15%只看到一团红色不标。掉在地上的苹果只要不是腐烂严重依然标为apple。两张图片有同一颗果实重叠出现各自独立标注不做跨图去重。坦白说这个标准肯定有主观成分但数据集标注本来就是主观一致性比绝对正确更重要。只要所有人按同一套标准操作模型学到的是统一的边界定义就不会出大问题。为了验证标准执行效果我做了个抽检动作每完成100张随机抽10张让另一个人重新标注一遍再计算两次标注的IoU重合度。IoU大于0.7就算合格。这个流程听起来简单实际操作中非常有效它能筛掉漫不经心的标注、漏标和锚点错位问题。3.3 标注质量检查与修正经验标注完成后的质量检查不能完全依赖肉眼扫建议写脚本统计JSON文件里的关键信息。我做的第一轮自动检查是解析所有JSON文件检查有没有空标注文件、标签名错漏、坐标超出图片边界。import json import os label_dir labels error_files [] for file in os.listdir(label_dir): if not file.endswith(.json): continue path os.path.join(label_dir, file) with open(path, r, encodingutf-8) as f: data json.load(f) if len(data[shapes]) 0: error_files.append((file, empty annotation)) continue img_w data[imageWidth] img_h data[imageHeight] for shape in data[shapes]: if shape[label].strip() ! apple: error_files.append((file, wrong label: shape[label])) points shape[points] for point in points: if not (0 point[0] img_w and 0 point[1] img_h): error_files.append((file, point out of range)) break print(发现问题文件数:, len(error_files)) for item in error_files: print(item)这一轮脚本能扫出大半低级错误。剩下的高一级错误比如漏标、锚点偏离就只能靠抽样人工复查。我的复查频率是随机抽5%的图人工快速浏览一遍标注框贴合度不合格就退回重标。注意标注阶段宁可多花5天也不可节省这步检查因为数据集中若有5%的脏标注模型训练结果的mAP大概会掉3到6个点这个损失靠调参是补不回来的。4. Labelme格式转YOLO数据格式4.1 理解两种数据格式的本质区别Labelme保存的JSON格式记录的是像素坐标下的多边形顶点它描述的是几何信息不关心目标类别编号。YOLO训练需要的txt格式则完全不同它记录的是一句话类别id x_center y_center width height后面四个数字全部是归一化到0到1之间的小数代表目标中心点和宽高相对于整张图片的比例。举个例子一张宽1920高1080的图上有一个苹果矩形边界是左上角(300, 200)到右下角(600, 500)那YOLO的标注就应该是0 0.234375 0.324074 0.156250 0.277778计算过程x_center (300 600) / 2 / 1920 0.234375 y_center (200 500) / 2 / 1080 0.324074 width (600 - 300) / 1920 0.156250 height (500 - 200) / 1080 0.277778Labelme的JSON里存的是多边形的点你在转换时要么把多边形的最小外接矩形作为最终目标框要么继续用多边形做分割训练。对于苹果检测项目我用最小外接矩形方式因为最后跑的是YOLO检测不是实例分割。需要注意的一点是Labelme的JSON里每个shape的points是一个数组坐标顺序是[[x1,y1], [x2,y2], ...]转换脚本要先把这些点拆出所有x和所有y再分别求最小值和最大值确保矩形框正好包住多边形。4.2 转换脚本实现与逐行解读我在项目里写的转换脚本不算复杂但有几个细节值得逐行说清楚。import json import os from pathlib import Path def labelme_to_yolo(json_path, output_dir, class_list): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w int(data[imageWidth]) img_h int(data[imageHeight]) out_lines [] for shape in data[shapes]: label shape[label] if label not in class_list: continue class_id class_list.index(label) points shape[points] all_x [p[0] for p in points] all_y [p[1] for p in points] min_x, max_x min(all_x), max(all_x) min_y, max_y min(all_y), max(all_y) x_center (min_x max_x) / 2 / img_w y_center (min_y max_y) / 2 / img_h box_w (max_x - min_x) / img_w box_h (max_y - min_y) / img_h out_lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) output_path Path(output_dir) / (Path(json_path).stem .txt) with open(output_path, w, encodingutf-8) as f: f.write(\n.join(out_lines))这个脚本的核心逻辑不复杂先读JSON取出图片尺寸遍历所有标注shape对每个shape用多边形顶点求外接矩形再把外接矩形的中心点和宽高归一化最后拼成YOLO格式的一行字符串写进txt文件。实际使用中我加了一个保护逻辑如果某个坐标归一化后小于0或大于1说明坐标越界脚本会立即报告避免脏数据混进训练集。批量转换时外层套一个遍历目录的循环就行。import os from pathlib import Path json_dir labelme_json txt_dir yolo_labels os.makedirs(txt_dir, exist_okTrue) class_list [apple] for file in os.listdir(json_dir): if file.endswith(.json): labelme_to_yolo( str(Path(json_dir) / file), txt_dir, class_list )单类别时class_list只需要一个apple代表类别id 0。如果有多个类别顺序一定要固定比如[apple, leaf, branch]以后训练和推理都得沿用这个顺序换顺序等于换模型词汇表之前训练的全部作废。4.3 数据集划分与目录组织数据集目录组织这块很多人不太当回事直接一个文件夹里扔几千张图片和txt最后训练时YOLO框架也能跑但对管理和复现非常不利。我按YOLO官方推荐的目录结构来组织dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml图片和标签必须一一对应名字相同后缀不同。划分时用脚本随机划分但要注意同一个时间序列拍摄的图片比如同一个相机同一分钟连拍的十几张相近图片划分时必须放进同一个集合里不能一半进train一半进val。否则验证集和训练集高度相似模型验证指标虚高一上真实场景立刻掉点。我的划分脚本简单粗暴按文件名hash取模分组但哈希结果稳定的前提下同前缀的文件大概率会被分到不同组。后来我改成直接按文件名前缀group再随机分确保同一个采集批次不割裂。这个做法我推荐你直接照抄。import os import random import shutil from collections import defaultdict random.seed(42) image_dir all_images label_dir all_labels train_img_dir dataset/images/train val_img_dir dataset/images/val train_lbl_dir dataset/labels/train val_lbl_dir dataset/labels/val os.makedirs(train_img_dir, exist_okTrue) os.makedirs(val_img_dir, exist_okTrue) os.makedirs(train_lbl_dir, exist_okTrue) os.makedirs(val_lbl_dir, exist_okTrue) images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] # 按文件名前缀分组同一批次的图片不会拆散 groups defaultdict(list) for img in images: prefix img.split(_)[0] groups[prefix].append(img) group_keys list(groups.keys()) random.shuffle(group_keys) split_idx int(len(group_keys) * 0.9) train_groups set(group_keys[:split_idx]) val_groups set(group_keys[split_idx:]) for img in images: prefix img.split(_)[0] src_img os.path.join(image_dir, img) src_lbl os.path.join(label_dir, img.replace(.jpg, .txt)) if prefix in train_groups: shutil.copy(src_img, train_img_dir) shutil.copy(src_lbl, train_lbl_dir) else: shutil.copy(src_img, val_img_dir) shutil.copy(src_lbl, val_lbl_dir)5. 用YOLOv8训练苹果检测模型5.1 数据配置与环境准备YOLOv8是Ultralytics维护的检测框架训练自己数据集时需要写一个data.yaml文件指向训练集、验证集的图片目录路径。文件内容如下path: /home/user/dataset train: images/train val: images/val names: 0: apple这里有个坑path写绝对路径还是相对路径取决于你从哪个目录启动训练。如果从项目根目录启动path可以直接写dataset相对路径如果换机器跑绝对路径记得改成新机器的路径。我建议把这个data.yaml文件放到数据集根目录随数据集一起拷贝迁移换机器时改一行path就行。安装YOLOv8只需要一条命令pip install ultralytics如果你有GPU确保CUDA和pytorch版本匹配。我自己的机器是RTX 3090用的pytorch是官方cu118版本训练速度比CPU快几十倍。没有GPU也能训练但4430张图、600多轮训练CPU可能要跑到三天三夜GPU只要两三个小时。5.2 打开Labelme与基础界面训练命令可以直接用CLI方式yolo detect train data/path/to/data.yaml modelyolov8s.pt epochs300 imgsz640 batch16 device0也可以用Python脚本跑方便调参和扩展from ultralytics import YOLO model YOLO(yolov8s.pt) model.train( data/path/to/data.yaml, epochs300, imgsz640, batch16, device0, patience50, nameapple_yolov8s )几个关键参数我根据自己的经验解释一下方便你调参时心里有数。imgsz是训练分辨率我这边用的是640。苹果果实尺寸在画面中占比变化很大远距离小目标在640下只有十几个像素模型能学但效果一般。如果你手中的图片里小目标占比高建议imgsz改成960甚至1280但显存消耗会直线上升。RTX 3090的24GB显存batch设为8imgsz960基本就到顶了。batch是每次迭代喂给模型的图片数。显存相同的情况下imgsz越大batch就要越小。如果显存不足训练会直接报错OOM最简单的办法是batch降到4或者2。epochs不是越大越好我建议设300配合patience50做早停。如果验证集mAP连续50轮不再提升训练自动终止取之前最优的模型权重避免过拟合。5.3 训练结果评估与调优训练结束后我关注的核心指标有三个mAP50、mAP50-95和Precision/Recall。在我这个苹果检测项目上第一次训练得到的指标大概是mAP500.92、mAP50-950.78、Precision0.89、Recall0.93。这个水平在检测任务里已经算合格但recall偏高precision偏低说明模型倾向于多出框也就是会有不少误报——把圆形的树叶、水滴误判成苹果。这个在果园场景里不可接受因为误判会导致自动采摘机对着树叶工作。我的调优方向有两个第一加数据增强。YOLOv8默认开启了mosaic增强但果园场景的遮挡关系复杂我又额外把HSV变换的饱和度增强调大了一点点从默认0.7改到了0.9让模型更适应红绿颜色比例的变化。第二提高置信度阈值。推理时把默认的conf-thres从0.25提高到0.45能过滤大量低置信度误检。yolo detect predict modelbest.pt sourcetest_images/ imgsz640 conf0.45这样调完precision能到0.93左右recall回落到0.91比之前均衡不少。如果你想进一步压误检也可以尝试在训练数据里混合部分负样本——只有树叶和树枝、没有苹果的图片标注为空文件。我后期混了50张纯背景负样本虽然数量不多但对降低误报有奇效。6. 常见问题排查与提升建议6.1 标注与转换阶段的高频问题这个部分我把项目过程中实际遇到的高频问题整理成了一张速查表每个坑后面附了解决方法。问题原因解决方案转换后txt全空JSON里shapes为空检查标注时是否漏存重新标注目标框偏移严重多边形点顺序混乱统一按顺时针方向画点类别ID混乱不同批次的class_list顺序不一致训练前固定一个classes.txt转换时逐张核对训练时Loss不降图片和标签错位txt内容对不上图用脚本随机抽10张图显示detector的预测框验证小目标完全检不到imgsz太小或图片缩放过度提高imgsz到960或采用切图训练验证集mAP虚高但现场拉垮同批次图片被拆进train和val按时间/设备批次分组划分数据集保证同批次不进不同集合这里有个容易忽略的细节Labelme画多边形时锚点默认连成开放路径还是闭合路径取决于你最后怎么结束。标多边形时最后必须回到起点附近双击系统才会闭合图形。如果不闭合转换脚本可能只取到几个孤立的点外接矩形完全错误。我写了转换脚本后额外加了一步检查每个点集的点数少于3就直接报错这样至少保证多边形是闭合的。6.2 训练阶段的高频报错与调参方向YOLOv8训练时如果是GPU显存不足通常报的是CUDA out of memory这时候你不需要加显存先把batch从16改成8再改4直到不报错。如果batch小于4还爆显存说明imgsz太大改成640。另一个常见问题是训练到一半loss变成nan一般是因为学习率设置过高导致的梯度爆炸或者数据里有一张异常图。YOLOv8默认的学习率对大多数数据集是适配的但如果你换了较大的batch可以适当把学习率同步降低。最简单的办法是改模型参数把lr0从默认0.01降到0.005基本能解决。如果你在训练时发现val loss一直下跌但train loss已经收敛到一个平台这说明模型过拟合趋势明显优先考虑增加数据增强、加dropout或者把训练epoch减少。如果train loss还在降但val loss开始回升这就是典型的过拟合信号直接早停取mAP最高的权重就好。6.3 模型效果提升的进阶思路当你的baseline已经到mAP500.9以上后数据集的边际收益会越来越低想再往上走就得换思路。我的建议分三步按优先级排列。优先做难例挖掘。跑一遍推理把模型漏检或误检的样本挑出来单独建一个hard examples文件夹。这些样本不是拿来直接训练的而是人工分析漏检原因。我观察到的规律是九成漏检发生在果实被严重遮挡的场景以及逆光导致果实和背景融为一体的时候。针对这两个场景我补采了一批专门在早晚侧光下拍的图片重新标注后加入训练集mAP50-95立刻涨了1.5个点左右。其次考虑多尺度训练。YOLOv8支持在参数里配置multi_scaleTrue训练时每10个iteration随机从一个尺寸区间里选一个训练分辨率。这相当于用同一批数据人为制造了不同尺度的训练样本对苹果这种尺度变化大的目标是实打实的提升。代价是训练速度变慢15%左右但效果好于只用一个固定分辨率。然后再谈数据增强策略。除了YOLOv8内置的mosaic、random_flip之外我还试过给图片加随机亮度扰动、随机旋转、轻微模糊。果园场景光线变化大亮度扰动对提升鲁棒性很有帮助。但需要注意旋转角度不要超过30度不然果实会变形得不像苹果了。6.4 Labelme标注效率提升技巧最后补充几个标注效率的技巧这是我在标了上千张以后总结出来的。第一善用Labelme的CtrlD复制上一张图的标注只对新图做微调。如果你的图片是连续帧视频抽帧这种操作能把时间缩短一半。第二打开Labelme的Edit-Create Circle做圆形标注苹果近圆形圆形标注比多边形快很多但仔细程度略低。如果你是高精度需求还是老老实实画多边形但可以先画一个圆再微调。第三批量启动多个Labelme进程把不同目录分给不同标注员最后汇总时用脚本合并。标注工具本身不提供多人实时协作但你可以用最简单的共享网盘把待标注图片同步给团队成员各标各的每完成一批就上传JSON。汇总时注意重名问题统一加人员前缀避免覆盖。还有一个很实用的小技巧标注完成后把其中任一张图的JSON文件打开看里面的shapes数组长度。如果某张图里苹果很多数组长度很大模型训练时这张图的权重影响会更高。正常情况下果实密集图占10%-15%就可以不要超过30%否则模型会在密集场景过拟合稀疏场景找不到目标。7. 从数据集到模型这次项目的最终心得这个苹果检测数据集从0到1做完我最深的体会是目标检测项目里最费时间的部分压根不是训练而是数据。4430张图听起来不多但每张图平均要标5到8个果实整批下来接近3万个多边形标注框。一个人纯手工标每天最多标300张得干两周以上。所以如果你准备开启类似项目我建议团队至少两个人一起标一个人标图一个人抽检效率能提升一倍质量还更有保障。数据集的真正价值不只是数量更是标准统一和场景覆盖。哪怕你只有3000张图只要覆盖了不同光照、不同成熟度、不同遮挡程度效果会超过10000张单一场景的图。我的原则是宁可用更少但更高质量的图片也不要盲目堆数量。果农用手机拍一张照片就能跑出好结果这个项目才算真正落地。如果你正准备给自己的检测任务做数据集我的建议是不要先纠结框架和模型先把labelme打开把第一张图标完把转换脚本跑通把第一个yaml文件配好。整个过程里最关键的决策窗口往往就是你在标第一张图时定的那个标准。标准对了后面的一切都会顺理成章。本文还有配套的精品资源点击获取