☰
卡达巴香蕉成熟度识别:702张labelme分割数据集构建与实战
2026/10/21 5:15:19 网站建设 项目流程

去年我跟着项目组去某香蕉主产区做智慧农业调研,站在一片卡达巴香蕉林里,收购商指着一挂刚砍下来的蕉说:这串现在卖没人要,放三天就是抢手货。我当时一愣,后来才明白,卡达巴这个品种的成熟节奏又快又不均匀,判断“能出手的黄金窗口期”基本靠老师傅用眼睛估。人工估的问题很直接:不同人标准不一致,同一串青黄交界处的果实,两个人能吵半天;到了收购旺季,人手紧张,估错一挂就是真金白银的损失。那次调研回来,我们启动了这个卡达巴香蕉成熟度识别分割项目——目标是做一个能落到分选线上的数据底子,也就是你现在看到的这份labelme格式、702张、3类别的分割数据集。这篇文章就把整个数据集的来龙去脉、标注细节、训练实测和踩过的坑一次讲透,给同样在折腾农产品视觉识别的团队当个参考。

1. 卡达巴香蕉的“成熟度”为什么靠机器判断比人靠谱

1.1 从人工眼看到机器视觉:一个收购场景的冲击

卡达巴香蕉在产区里的地位不低,但它有个让收购商头疼的特点:皮厚,转色期长,明明整串看起来还是青的,切开后果肉甜度已经上来了;反过来,表面黄了,可能又已经开始发软、不耐储运。老师傅的判断方式其实很朴素——看果皮底色、看果棱是否饱满、顺手捏一下。这些经验有用,但没法标准化,更没法复制到一套自动化分选设备上。

我们在调研时做过一次记录:同一串香蕉,请三位有经验的评级人员分别给出成熟度判断,结果只有两位一致,对“能不能当天发车”这个关键判断的分歧率接近三成。这个数字直接说服了客户——机器要做的不是比人更“懂”香蕉,而是把人的经验尺子量化成一个稳定、可复现的输出。这也是我们坚持做像素级分割而不是简单分类的原因之一。

1.2 为什么成熟度识别要用“分割”而不是分类或检测

先说说一开始犯过的错误。最早客户想得很简单:给摄像头传一张图,告诉它是生还是熟。我们拿分类网络试了几轮,发现根本压不住。

原因在于照片场景的复杂度:一串卡达巴香蕉上,不同果指之间的成熟度往往存在明显梯度——向阳侧的果指先黄,内侧还在转色。整图分类只能给出一个全局标签,对分选毫无意义。目标检测稍微好一点,但检测框会把背景大量带进来,框内既包括香蕉本身也包括背后的叶片、果柄、相邻果指,成熟度特征被噪声稀释得很严重。

分割是扛这项任务的正解:给每个果指画出一个精确多边形,让模型输出“哪个像素属于哪根香蕉、这根香蕉处于什么成熟阶段”。下游分选机械臂抓取边界、统计每根香蕉的成熟面积占比、甚至按串分装,都需要这种边界信息。所以这个数据集一开始就定位成实例分割任务,标注格式选labelme,为的就是把每个果实边界直接落到坐标点上,方便后续转成COCO、VOC等主流格式去训模型。

2. 702张数据集的生产流水线:从香蕉园到JSON文件

2.1 采集策略:让数据集“见多识广”

一个分割数据集能不能养活模型,采集阶段就决定了上限。我们前期最担心的是样本太“干净”,毕竟室内灯箱拍摄的香蕉和田间树上的香蕉,环境光照、背景纹理差得太远。

实际采集分了三个来源:

  • 田间挂树拍摄:覆盖早晨、正午、傍晚三个时段,光线角度差异大,蕉串悬挂姿态随机,目标尺寸从远到近都有。
  • 采后处理线拍摄:香蕉在输送带上移动,背景相对干净,但存在运动模糊和反光,贴近实际部署场景。
  • 近景补拍:针对单根果指和局部蕉串特写,保证每张图里有大目标,让模型学到果皮颜色和质地的细节。

三个来源各占约三分之一,总数控制在702张。分辨率统一压到1920x1080以内,避免单张图片过大影响标注效率。

2.2 清洗与标注入库流程

原始素材拍了两千多张,最后只保留702张,删掉的都是“给模型挖坑”的图。淘汰原则有三:画面严重模糊、主体被遮挡超过30%、以及曝光失控导致果皮颜色完全失真的。这些图留着只会让标注人员纠结,让训练标签变得不可信。

标注工具用的是labelme桌面版,流程上我们定了几条规矩:

  • 每根香蕉只标一个多边形,严格沿果指外轮廓打点,不把果柄纳入边界。
  • 点序按顺时针走,起点从果指顶部开始,后续转COCO时polygon格式能省一次坐标重排。
  • 单个果指的点数限制在20到40个之间。点太少边界粗糙,点太多转换效率和训练内存都吃亏。
  • 每张图至少由两位标注员独立标注,再交给仲裁人比对,边界差异超过5个像素的重新标。

整批数据前后花了约三周完成,中间还专门停了一天给标注员做类别标准培训,后面会细说。

2.3 702张图背后的统计口径

很多人第一反应是“702张够吗”,其实按实例数折算并不算少。我们把三类做了大致均衡的设计,避免模型被多数类带偏:

类别图片张数果实实例数标签名
未成熟2381490unripe
半成熟2311322midripe
完全成熟2331378ripe

合计图片702张,多边形实例约4190个。平均每张图里有6个左右的实例,对大目标场景来说这个密度足够训练分割模型了。后续做数据划分时,我们按图像来源分层抽样,训练集562张、验证集70张、测试集70张,确保三个来源在三份数据里的比例一致,不让验证集因为场景分布偏差而失真。

3. labelme JSON逐字段拆解:多边形标注背后的工程语义

3.1 一份完整JSON长什么样

labelme保存的标注文件是JSON,一张图对应一个同名JSON。训练时大多数脚本要先解析这个文件,把坐标点读出来转成掩码。很多团队卡在这一步,所以我直接贴一份典型结构:

{ "version": "5.3.1", "flags": {}, "shapes": [ { "label": "midripe", "points": [[512.3, 318.0], [524.7, 342.5], [541.2, 370.1], [518.9, 388.4], [493.5, 362.0]], "group_id": null, "shape_type": "polygon", "flags": {} } ], "imagePath": "kadaba_0142.jpg", "imageData": null, "imageHeight": 1080, "imageWidth": 1920 }

注意这里的points我为了展示做了截断,实际标注里每根香蕉会有几十个点。坐标是浮点数,单位是像素,相对图像左上角原点。

3.2 关键字段的工程语义

先看shapes数组,这是整个JSON的核心。每个元素对应一个标注对象,label字段就是类别名;points字段是多边形顶点坐标;shape_type固定为polygon;group_id我建议统一用null,除非你要把同一串香蕉的多个果指归组,这个字段对单果分割没意义。

imagePath字段存储图片文件名,它在不同环境下会有坑。比如labelme保存时默认写的可能是绝对路径,也可能是相对于JSON目录的路径。我们踩过一次:训练脚本拿imagePath直接拼目录,结果路径里多了一层"data/images",图片全找不到。保险做法是自己维护一份图片文件名和JSON路径的映射表,不要完全依赖标注工具写出来的路径。

imageData字段是图片的Base64编码。labelme默认会把它写进JSON,但一张1080p的图塞进去,JSON直接变成几兆,磁盘占用和解析耗时都暴涨。我建议保存时选择不带imageData的选项,图片单独放一个目录,训练时按文件名读取。

3.3 为什么最终选了labelme格式而不是COCO直接标注

这个问题我们内部讨论过。直接用COCO数据格式确实方便训练,但COCO的json结构对人工标注并不友好,人类没法拿那种嵌套结构逐条手改。labelme的好处是“一眼能看懂”:一个对象一个数组,一个数组一串坐标,标注员拿到文件能自查,脚本也容易生成。真实项目里,标注工具的选择不只是给算法工程师看的,还得照顾标注团队的操作习惯。我们最终保留了两套数据:原始labelme格式作为“母版”,再用脚本转出COCO和VOC版本用于训练。这样任何模型框架都能接得上。

4. 三个类别的定义边界:从农业标准到机器学习微调

4.1 三类划分标准与判断优先级

成熟度怎么定义,是前期标注最纠结的问题。给模型分类和给经销商分级的逻辑不完全一样:经销商看的是“能不能卖”,模型需要的是“视觉上可区分”。我们最后定了一套按果皮颜色面积占比的操作性标准:

类别判定标准备注
未成熟果皮绿色面积超过90%允许基部略微泛黄
半成熟绿黄面积比在1:3到3:1之间转色期的常见形态
完全成熟黄色面积超过90%,或出现可见黑斑全黄和微黑斑都算

判断优先级是先看黑斑,再看黄绿比例。只要出现明显黑斑,即使仍有小片青绿色也归入完全成熟。这条规则是为了兼容实际采收习惯:不能运输途中开始有斑点还标成半熟。

4.2 边界样本的处理协议

转色期的香蕉非常容易让标注员打架。同一根果指,上半段黄了、下半段还青,按面积比例算刚好卡在“半成熟”和“完全成熟”之间,这时候怎么办?

我们定的协议是:当一个果指的不确定区域超过20%时,标注员把它归入面积占比更高的类别,并在仲裁阶段保留标记。也就是说,边界样本不是取中间,而是“硬切”到某一边。这个选择牺牲了部分标注的精确度,但换来训练时类别边界更干净。模型在推理时本来就会学习概率分布,如果训练标签本身就是模糊的,损失函数会在边界区域来回震荡,收敛效果很差。

4.3 与采收标准的一致性检查

训练模型不是最终目的,能替代人工评级才是。我们建完标注标准后,特意请产区的评级老师傅看了50张测试图,把他们的结论和标注结果做了一次比对。比对结果出现了单张图上约7%的差异,主要集中在半成熟和完全成熟的边界上。最后我们反向调整了一轮标注规则:老师傅认为“已经可以采”的果实,即使黄绿面积比还略低于90%,也统一归入完全成熟。这一步对齐很关键,否则模型训得再准,落地时客户也会觉得“你判断的成熟度跟老师傅不一样,没法用”。

5. 用702张数据训练分割模型,实测效果如何

5.1 实验配置与训练细节

数据准备好之后,我们拿当前主流的分割模型做了两轮实验。基础环境是PyTorch框架,显卡用8GB显存的消费级N卡,输入尺寸统一做letterbox缩放到1280x1280,batch size调到8。训练脚本里开了mosaic增强、随机水平翻转、HSV色域扰动和随机缩放平移。对于成熟度任务,HSV扰动要刻意限制饱和度变化的幅度,因为颜色本身是核心特征,扰动太强等于给标签注噪声。

数据增强的具体参数我们调了一版稳定配置:

增强项参数
Mosaic开启概率0.5
水平翻转概率0.5
HSV饱和度扰动幅度0.3
HSV亮度扰动幅度0.2
随机缩放0.5到1.5倍
平移0.1倍图像宽高

训练轮数设为120个epoch,早停阈值看验证集mAP50连续15轮不涨就停止。

5.2 分割结果与误差分析

我们对比了几种结构的实测结果,统一在相同测试集上评估:

模型mAP50mAP50-95单张推理耗时(毫秒)
YOLOv8n-seg0.8520.70122
YOLOv8s-seg0.8720.73035
YOLOv8m-seg0.8790.73852
Mask R-CNN(常规卷积主干)0.8610.71285

小模型和中等模型差距没有想象中大,说明702张数据能提供的特征复杂度有限,堆参数带来的收益不如预期。按类别拆开看,半成熟的AP普遍比另外两类低8到10个百分点,这个结果在意料之中——转色期的颜色特征跨度太大,同一类里既有偏绿的也有偏黄的,类内方差高,模型自然不好学。

单看mAP还不够,我们又统计了“错判成相邻类”的比例:测试集里完全成熟被认成半成熟的占比3.2%,半成熟被认成未成熟的占比6.8%。这个错位信息对分选线很重要,因为差一个等级只是误分,跨两个等级就是事故。

5.3 泛化验证:换一个果园会怎样

训练集里的第三批图片来源有限,我们担心模型过拟合特定园区的背景和光照。所以专门跑到另一个产区,重新拍摄了30张卡达巴香蕉照片,不做任何归入训练集的操作,直接拿来推理。实测mAP50掉到0.79,比原测试集低了约8个点。误差集中在小目标果指和逆光场景,背景换了之后false positive也变多。这个结果告诉我们,千万不能拿702张数据训完就当“万能模型”用,落地到新场景前至少要再采集几十张目标场景图片做微调,否则现场效果一定会打折。

6. 容易被忽略的四个坑:标注一致性、转换脚本与推理速度

6.1 标注阶段的坑:多边形越界和标准漂移

第一个坑是labelme里手绘多边形很容易超出图像边界,尤其是快速打点时鼠标滑出画布。labelme不会自动帮你把越界的点裁掉,转成掩码的时候数组索引变成负数或超长,直接报错。后来我们在后处理脚本里统一加了一步:检查所有点坐标,把越界的点强制裁剪到图像宽高范围内。

第二个坑是标注标准漂移。标注团队前两天盯得紧,后面越标越随性,同一张等级的果实轮廓粗细都不一样。我们中途做了一次抽检,发现后三分之一批次的标注点数量明显偏少,边界粗略。解决办法是每天同步一次“标准样图”到标注群,每个人在开工前先看三张标准图保底,再开始标,后面错误率立刻降下来。

6.2 数据转换阶段的坑:路径分割符与掩码渲染

labelme转COCO的脚本看起来简单,真跑起来问题不少。最常踩的是Windows和Linux的路径分隔符不一致,JSON里存的imagePath如果是在Windows上标完的,拿到Linux服务器上一拼路径就带反斜杠,解析直接失败。我的建议是全流程统一在Linux环境标注,或者干脆在转换脚本里用os.path.basename只取文件名。

掩码渲染也是重灾区。坐标点是浮点数,直接画到全零图上会丢掉边缘细节。我们转换时先用cv2.fillPoly,再对掩码做一次高斯模糊和阈值二值化,把边缘洗平滑,这样转出来的mask在训练时不会出现锯齿状边界误差。

6.3 训练与部署阶段的坑:显存占用和后处理粘连

训练时最尴尬的是原始图直接硬塞进网络,1920x1080的分辨率加上batch size 4,显存直接溢出。这不是模型结构问题,而是输入尺寸没控制好。统一letterbox到1280,batch size拉到8,问题迎刃而解。

推理阶段更大的坑是后处理。串状香蕉的果指之间天然有遮挡,分割mask经常连成一片,一个实例的掩码把旁边果指也包进去了。我们加了两步后处理:先用连通域分析把所有mask分成独立区域,再按每个连通域的面积过滤——面积小于整图万分之一的区域直接丢掉,这样能压掉大部分背景误分割碎块。实测这步操作让视觉层面的实例计数准确率提高约7%,代价是每张图增加不到3毫秒的CPU处理时间,完全值得。

一点个人体会和后续建议

项目收尾时,我最大的体会是数据集的价值不在于“张数多漂亮”,而在于标注标准的严谨程度和与实际业务标准的对齐程度。我们后来做线上测试,把模型输出接到分选线的模拟流程里,发现真正的瓶颈反而不是模型精度,而是数据训练场景和现场场景的差距。如果你也打算做类似的农产品识别项目,我建议在采集阶段就把目标场景的机位、光照、输送速度都考虑进去,不要等模型训完了再回头补数据。

最后再分享一个小技巧:labelme标注时把“自动保存”开启,并且每标完50张就手动把JSON文件复制到备份目录。标注是个体力活,某个程序闪退或者误操作导致文件损坏,找回成本远高于备份成本。就这个习惯,帮我们规避了一次标注进度几乎清零的事故。数据准备好了,剩下的就交给模型去学,希望这份数据集也能帮你少走几段弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询