ARTICLE DETAIL

资讯详情

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

石榴成熟阶段检测:YOLO数据集格式转换与训练全流程

石榴成熟阶段检测:YOLO数据集格式转换与训练全流程 简介面向石榴成熟阶段检测任务的数据集包适合农业视觉、智慧果园等场景下的目标检测算法训练与验证。数据按VOC与YOLO两种格式组织内含五千八百五十五张清晰图像标签覆盖花苞、早期果实、花朵、中期生长、成熟果实五个阶段合计一万一千四百八十二个矩形框可支持从开花到成熟全周期的成熟度识别模型开发。包体共两千个文件以XML标注与TXT标签文件为主压缩包大小约四百零六兆字节目录按图像、标注、标签三个模块划分便于直接进行数据切分与训练。数据集未做图像增强提供准确合理的框级标注可直接接入主流检测框架使用。目前已有七十九人浏览学习适合需要石榴生长阶段分类样本或目标检测入门实践的研究者。1. 石榴成熟阶段检测数据集5855张图解决的是“成熟度分级”而非“有没有果”做果园自动分拣或采摘机器人时真正难的不是“检测出石榴”而是“判断这个石榴现在能不能摘”。同一个品种从青绿到暗红颜色、纹理、光泽都在变边框大小反而差别不大。我拿到这份“目标检测-石榴成熟阶段检测数据集5855张5个阶段YOLOVOC.zip”时第一反应是这正好卡在目标检测的经典痛点上类别之间是连续渐变不是离散跳变。5855张图、5个成熟阶段意味着你可以用YOLO系列直接训练一个“成熟度分级”模型而不是只做“有无果实”的二分类。它把VOC格式的xml和YOLO格式的txt都给了省掉最磨人的格式转换环节适合刚入门目标检测的工程师也适合想在果园场景做落地验证的团队——毕竟数据集的标注质量、类别边界是否合理直接决定你后面要不要重新洗数据。2. 数据集结构与格式先搞清YOLO和VOC两套标注怎么对应再谈训练2.1 目录布局与5个阶段的类别设计常见做法是压缩包解压后分为images和annotations其中annotations下同时存在VOC子目录xml文件和YOLO子目录txt文件文件名与图片一一对应。5个阶段通常命名为unripe、green、half_ripe、ripe、overripe之类但具体名字你最好解压后打开data.yaml或classes.txt确认因为不同数据集作者的命名习惯差别很大有的用stage_1到stage_5有的直接用中文拼音缩写。关键点类别顺序决定txt里的类别id。YOLO格式的txt第一列是类别编号永远从0开始不是从1开始。我见过有人把VOC的name直接当编号用导致训练时类别全错位。解压后第一件事是统计每个类别的样本数和标注框数别急着开训。用一条命令就能看清楚# 统计YOLO标注中每个类别的框数量 cat annotations/YOLO/*.txt | awk {print $1} | sort | uniq -c输出里五行的数量差距如果很大比如ripe有3000个框而overripe只有200个你就要考虑类别不平衡问题。类别不平衡会直接拉低少数类的召回率后面即使整体mAP很好看实际落地时“过熟”的石榴大概率漏检因为采摘机器人最想避开的恰恰是过熟果。2.2 YOLO txt与VOC xml的坐标换算关系VOC格式里每个框是xmin, ymin, xmax, ymax单位是像素是绝对坐标。YOLO格式里每个框是x_center, y_center, width, height单位是图像宽高的比例是归一化相对坐标。两者换算公式如下# VOC像素坐标 - YOLO归一化坐标 x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height注意VOC的xmax、ymax一般指像素坐标值有的标注工具存的是“右下角像素索引”有的存的是“右下角像素索引1”。如果训练时发现框整体往左上偏一个像素大概率是这个原因。虽然一个像素对640分辨率的训练影响极小但做严谨评估时还是要把这个偏差消掉。给你一张对比表方便直接对照检查对比项VOC xmlYOLO txt坐标单位绝对像素归一化01框表示xmin, ymin, xmax, ymaxx_center, y_center, width, height类别编号字符串name如ripe整数id04小数精度整数居多保留6位小数常见文件格式xml每行一个目标空格分隔还有一个容易忽略的点VOC的类别名顺序不一定和YOLO的类别文件顺序一致。有的数据集作者把VOC xml里的name按字母序排但YOLO的classes.txt按成熟阶段排直接转换会张冠李戴。所以每次拿到双格式数据集我都是先随机抽三张图把YOLO txt画回图上再和VOC xml对照确认无误后才进训练流程。3. 用YOLOv8训练石榴成熟阶段的完整流程从数据集划分到mAP评估3.1 划分数据集并生成YOLO格式的data.yamlYOLOv8的ultralytics包要求目录结构是images/train、images/val、labels/train、labels/val。直接把下载的images和annotations/YOLO平行放进去是不行的必须先按比例切分。常见做法是8:2划分训练集和验证集但要注意按“图”切不是按“框”切更不能随机无脑切。否则同一张图的不同目标可能一半进train一半进val造成验证指标虚高。下面是我常用的脚本import os import random import shutil from pathlib import Path random.seed(42) data_dir Path(/path/to/pomegranate_dataset) images_dir data_dir / images labels_dir data_dir / annotations / YOLO # 1. 创建YOLO期望的目录结构 for split in [train, val]: (data_dir / yolo_format / images / split).mkdir(parentsTrue, exist_okTrue) (data_dir / yolo_format / labels / split).mkdir(parentsTrue, exist_okTrue) all_images list(images_dir.glob(*.jpg)) random.shuffle(all_images) val_count int(len(all_images) * 0.2) val_files all_images[:val_count] train_files all_images[val_count:] for split, files in [(train, train_files), (val, val_files)]: for img_path in files: txt_name img_path.stem .txt # 跳过没有对应标注的图 if not (labels_dir / txt_name).exists(): continue shutil.copy(img_path, data_dir / yolo_format / images / split / img_path.name) shutil.copy(labels_dir / txt_name, data_dir / yolo_format / labels / split / txt_name) print(ftrain images: {len(train_files)}, val images: {len(val_files)})划分完成后还需要写一份data.yaml告诉YOLOv8类别名和路径。注意路径写绝对路径最省心YOLOv8对相对路径的解析在不同版本里改过好几次我吃过亏# data.yaml path: /path/to/pomegranate_dataset/yolo_format train: images/train val: images/val names: 0: unripe 1: green 2: half_ripe 3: ripe 4: overripenames的顺序必须和你txt里类别id一致。这里我按“未熟/青熟/半熟/熟/过熟”五个阶段命名实际数据集可能不同以解压后的classes.txt为准。yaml文件保存为UTF-8无BOM格式否则Windows下训练会报编码错误。3.2 训练命令与关键参数imgsz、epochs、batch直接用ultralytics命令开训基础命令是yolo detect train \ --model yolov8n.pt \ --data data.yaml \ --epochs 150 \ --imgsz 640 \ --batch 16 \ --device 0这里我用了yolov8n.pt预训练模型下载作为起点而不是从随机权重开始训。迁移学习对石榴这种纹理细粒度分类特别重要颜色渐变类别的特征底子边缘、光斑、遮挡和COCO上的自然图像有很多共享部分。如果网络不好没法下载预训练权重也可以设modelyolov8n.yaml从零训但收敛会慢很多精度也会低几个点。几个关键参数说明--imgsz控制训练分辨率。石榴果在实地拍摄中占图比例可能不大640是速度与精度的平衡点。如果检测框普遍小于32×32考虑提到960或做切片推理。--epochs我设150但更稳的做法是配合patience30早停。石榴阶段分类的loss可能在120轮后还在缓慢下降早停设太紧会欠拟合。--batch受显存限制。16是8GB显存的常见值如果你是V100 32GB可以直接--batch 64。显存不够时优先降batch别降imgsz否则小目标更惨。--device指定显卡编号。多卡用0,1。训练时会看到每个epoch输出box_loss、cls_loss、dflloss、mAP50等指标。我一般不是死等150轮跑完——盯住验证集mAP50-95曲线一旦连续15轮不涨就手动停。训练日志里YOLOv8会自动在runs/detect/train/下保存best.pt和last.pt最后评估加载best即可。3.3 用混淆矩阵看成熟阶段误判这个数据集的瓶颈在相邻阶段训练结束后的第一件事不是看mAP而是看runs/detect/train/confusion_matrix.png。对石榴成熟阶段来说最大的误判往往集中在相邻阶段half_ripe被预测成riperipe被预测成overripe。这是因为相邻阶段的颜色分布高度重叠标注员本身也会有分歧。我在实际项目中遇到过一次类似情况把模型部署到分拣线上发现系统把很多青熟果判成半熟导致分拣等级错位。后来查混淆矩阵发现训练集里green和half_ripe的样本颜色差异极小很多框甚至肉眼都难以区分。解决办法不是堆更多数据而是重新检查标注边界和农业专家一起定出可量化标准——比如“果面红色面积超过三分之一算半熟”。如果你的数据集也有这个问题建议在训练前先用标注工具如labelImg或X-AnyLabeling抽样复核一遍而不是全信压缩包里的标签。再提一个YOLOv8特有的点混淆矩阵的总和可能不是100%。有的版本输出的是“归一化后的概率”有的输出“实际框数”你看到某一行相加不等于验证集里该类别的框总数别慌先确认是哪种模式。confusion_matrix.png默认是归一化版本如果要看原始计数可以用ConfusionMatrix类自己算。这不算bug只是展示口径不同。4. 把VOC转成YOLO格式的脚本自己动手处理类似数据集4.1 转换脚本核心代码虽然这个数据集给的是双格式但很多其他数据集只给VOC或者只给LabelMe格式。你以后大概率需要自己写转换。下面这个脚本是我改过多次的最终版支持对任意VOC目录批量转YOLO并自动检查越界和空标注import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, class_names, img_width, img_height): tree ET.parse(xml_file) root tree.getroot() size root.find(size) img_w int(size.find(width).text) if img_width is None else img_width img_h int(size.find(height).text) if img_height is None else img_height yolo_lines [] for obj in root.iter(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) # 归一化并裁剪到[0,1] x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h # 修正浮点误差导致的越界 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) width min(max(width, 0.0), 1.0) height min(max(height, 0.0), 1.0) yolo_lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) return yolo_lines def convert_dir(xml_dir, output_dir, class_names): xml_dir Path(xml_dir) output_dir Path(output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) for xml_file in xml_dir.glob(*.xml): lines voc_to_yolo(xml_file, class_names, img_widthNone, img_heightNone) if lines: # 跳过空标注 output_path output_dir / (xml_file.stem .txt) output_path.write_text(\n.join(lines), encodingutf-8) else: print(fWARNING: {xml_file.name} has no valid objects) if __name__ __main__: class_names [unripe, green, half_ripe, ripe, overripe] convert_dir(path/to/VOC/Annotations, path/to/YOLO/labels, class_names)4.2 参数说明与边界坑voc_to_yolo函数里我保留了img_width和img_height两个可选参数默认从xml的size读取。但有的数据集xml里没写size或者图片被resize过而xml没更新这时就必须传入真实图片尺寸否则坐标全乱。保险做法是用OpenCV读图import cv2 img cv2.imread(str(img_path)) h, w img.shape[:2] lines voc_to_yolo(xml_file, class_names, w, h)另一个边界坑是xmax可能等于img_width归一化后width等于1.0这在YOLO里是允许的但有些数据增强比如随机缩放会把这个框弄出界。我在脚本里做了min/max裁剪把越界值硬拉回[0,1]宁可损失几个像素也别让训练时出现“negative width”之类的报错。还要注意如果同一张图有多个目标txt文件里每行一个目标顺序无所谓。但如果某张图没有标注就不要生成txt文件。YOLO训练时遇到一个空的txt会默认成“背景图”有时会在训练日志里报WARNING: ignoring corrupt image。我一般会统计一下空xml的比例超过5%就说明数据本身有问题而不是转换脚本的问题。5. 避坑石榴阶段检测的5个常见翻车现场5.1 现象训练loss正常但验证mAP低原因数据集划分时用了随机划分同一个石榴的不同照片可能一半在train、一半在val。石榴在树上姿态近似模型记住了“这张图的果”而不是“果的特征”验证集全是见过的纹路指标虚高。反过来如果划分时按时间顺序把前面几天的照片全归train、后面全归val模型又可能因为光线变化而mAP暴跌。解决按“果树”或“拍摄时间”分桶。最好的划分方式是同一个树ID的所有照片要么全在train要么全在val。如果压缩包目录结构里没体现树ID按文件名里的时间戳前缀划分或者干脆用GroupShuffleSplit。我用过的最简单办法拿到文件名后取前几位作为组标识按组划分能极大缓解数据泄漏。5.2 现象检测结果把“青熟”和“半熟”混成一类原因标注的边界主观相邻阶段的颜色分布重叠严重。这是阶段检测数据集最本质的坑不是模型能力问题。翻车现场常见于你拿着模型去另一片果园试那里的光照和土壤条件让“半熟”看起来更像“青熟”。解决两个方向。一是合并类别把5阶段改成3阶段未熟/可采/过熟牺牲粒度换稳定。二是给边界类别加正则权重用YOLO的--cls参数提高分类loss的权重比如--cls 1.5让模型更不敢乱猜边界。我实际经验是如果生产只要求分三档直接合并最省事。5.3 现象小目标漏检远处树冠上的石榴基本不理原因5855张图里如果拍摄距离远很多石榴框可能只有40×40像素在640分辨率下占比不到0.4%。YOLOv8默认anchor是在COCO尺度上设计的对小目标响应本来就弱。解决训练时把--imgsz提到960让目标相对变大。推理时可以做tiling——把原图切成四块分别检测再合并结果。另外检查一下数据增强里mosaic是否把多个小块拼在一起时把可爱的小石榴打散了可以设mosaic0.5降低拼接概率。补小目标样本永远是治本但数据集的拍摄距离是固定的你只能从推理侧靠切图来捞。5.4 现象VOC转YOLO后框偏移画出来整体往右下方移动原因转换脚本里读到的是xml里的xmin/ymin但那是字符串有的xml用xmin、ymin有的用x_min、y_min字段名不一样。最常见的是把“左上角坐标”和“中心点坐标”混用还有的是把整数当浮点float之后除错了图片宽度。解决转换后一定要可视化抽查。写一个十分钟的脚本把txt画到原图上import cv2 import numpy as np def draw_yolo_boxes(image_path, txt_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) x_center float(parts[1]) * w y_center float(parts[2]) * h bw float(parts[3]) * w bh float(parts[4]) * h x1 int(x_center - bw / 2) y1 int(y_center - bh / 2) x2 int(x_center bw / 2) y2 int(y_center bh / 2) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, class_names[cls_id], (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return img抽10张图左右对照原图框只要偏一个果的半径说明坐标公式有bug别盲目调标注。5.5 现象mAP50很高但mAP50-95很低模型框不准原因mAP50只看IoU0.5算不算命中但成熟阶段检测对框的位置精度要求高分拣机械臂要按框的中心点去抓握IoU0.5时中心点可能偏了20像素。解决训练时关注box regression损失。YOLOv8的box_loss和dfllossDistribution Focal Loss共同负责框回归。可以适当调高--box权重默认是7.5我试过调到10框精度有明显提升但训练会变慢。另一个更有效的做法在推理阶段用 confidence 阈值卡掉低质量框的同时用IoU NMS阈值从0.7降到0.5减少重叠框对中心点判断的影响。6. 落地验证用训练好的模型给一批新图打分并量化阶段分布训练完不等于项目完。我每次拿到新模型都会先跑一个批量推理脚本输出每张图的成熟阶段分布而不是只看平均mAP。因为分拣线关心的是“我今天摘的这批果成熟度分布是否合理”整体mAP高不代表每个阶段都稳。最简单的批量验证脚本from ultralytics import YOLO model YOLO(runs/detect/train/best.pt) results model.predict( sourcenew_images/, imgsz640, conf0.25, iou0.6, save_txtTrue, save_confTrue, projectruns/detect, namevalidation_inference ) # 统计每个类别的检测数量 from collections import Counter cnt Counter() for r in results: for c in r.boxes.cls.tolist(): cnt[int(c)] 1 print(cnt)这里conf0.25是默认置信度阈值但对石榴阶段检测我习惯调成0.4。因为成熟度误判的成本比漏检高把生果放进熟果筐比漏检一个果损失更大。iou0.6控制NMS的冗余抑制0.6在密集果实场景是个不错的起点如果树上果实重叠严重可以降到0.5。再做一步把同一张图的检测结果按置信度排序把置信度最低的20个结果拿出来人工看一遍。这个习惯救过我很多次——有一次发现模型把干枯的叶子当成过熟石榴就是因为低置信度结果里全是这种样本而它们恰好都处于光线暗的区域。如果这类误检太多就要考虑在数据增强里加亮度扰动或者收集更多暗光样本做--cache ram微调。这个数据集的5个阶段如果能稳定区分那说明从数据到模型这条链路已经通了。剩下的工作就是把模型量化成TensorRT或者ONNX部署到Jetson或者RK3588上跑实时推理。我在嵌入式上踩过最大的坑是INT8量化后成熟阶段分类精度掉了3%以上颜色渐变类别对量化噪声太敏感。所以我一般用FP16部署除非你能在目标设备上重新校准并验证分阶段mAP不掉。说到最后每次拿到新数据集我都有个习惯把训练日志和验证结果按日期归档文件名写成pomegranate_v1_20250520_epoch150_best_mAP50-95_0.735.txt。看起来很土但半年后你在项目现场翻日志时就知道自己当时为什么选那个参数了。希望这份记录能帮你在石榴成熟度检测或者类似的农业目标检测项目上少走几条弯路祝你好运。本文还有配套的精品资源点击获取
返回列表