news 2026/10/10 23:51:56

土豆目标检测数据集:YOLO与VOC双格式实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
土豆目标检测数据集:YOLO与VOC双格式实战指南

简介:本资源是面向农业AI与目标检测初学者及实践者的土豆目标检测专用数据集,适用于YOLO系列、Faster R-CNN等主流检测模型的训练与验证,可支撑智能分拣、田间监测、品质分级等实际场景建模。压缩包共310个文件,含152张JPEG图像、76份VOC格式XML标注、80份YOLO格式TXT标签,另有train/val划分文件、labels.cache缓存及dataset.yaml配置文件,总大小13.88MB,结构完整、开箱即用。已有204人学习下载,体现其在轻量级农作物识别任务中的实用热度。用户可直接加载训练,无需格式转换;VOC与YOLO双格式并存,兼顾传统框架适配与YOLO生态便捷性;cache文件与划分列表已预置,显著降低数据预处理门槛,特别适合课程实验、竞赛备赛及快速原型验证。

1. 土豆目标检测数据集:为什么一个“不起眼”的根茎类作物,成了YOLO和VOC双格式数据集的实操跳板?

你可能刚在GitHub上点开一个叫potato-detection-dataset.zip的压缩包,解压后发现里面既有JPEGImages/+Annotations/的Pascal VOC经典结构,又有images/+labels/下带.txt坐标文件的YOLO格式——第一反应是:“这不就是个土豆图库?能干啥?”
但真正用过的人都知道:它不是玩具数据集,而是目标检测落地前最硬的“压力测试桩”。
土豆形态不规则、表皮纹理复杂、常堆叠遮挡、光照下反光与阴影交杂,且田间采集时存在大量低分辨率、倾斜角度、背景杂乱样本——这些恰恰是YOLOv5/v8/v10在部署到边缘设备(如Jetson Nano或RK3588)时最易翻车的典型场景。而VOC格式的存在,又让它成为验证模型泛化能力的“交叉校验锚点”:同一组图像,用VOC训练的Faster R-CNN vs 用YOLO格式训的YOLOv8,mAP差异能直接暴露标注一致性、归一化逻辑、anchor匹配策略的真实缺陷。
适合谁?三类人立刻能用上:一是刚跑通ultralytics但卡在“自己数据集训不出效果”的新手,拿土豆练手比COCO轻量十倍;二是做农业AI硬件集成的工程师,需要快速验证模型在真实田间视频流中的推理延迟与误检率;三是教学场景下讲清楚“格式转换不是复制粘贴,而是坐标语义重映射”的讲师——这个数据集里每张图都自带VOC与YOLO双标签,天然构成教学对照组。


2. 从解压到训练:用土豆数据集跑通YOLOv8最小闭环

2.1 解压与目录结构确认:别急着train,先看清“双格式”怎么共存

下载得到的potato-detection-dataset.zip解压后,典型结构如下(注意路径大小写与斜杠方向,Windows下需统一为\\或正斜杠):

potato-detection-dataset/ ├── voc_format/ # Pascal VOC标准结构 │ ├── JPEGImages/ # 所有原始图像(.jpg) │ ├── Annotations/ # XML标注文件,含<filename>、<object><bndbox>等 │ └── ImageSets/Main/ # train.txt, val.txt, test.txt(含图像名,无扩展名) ├── yolo_format/ # YOLOv5/v8兼容结构 │ ├── images/ # 同JPEGImages内容,但软链接或硬拷贝 │ ├── labels/ # 每张图对应同名.txt,每行:class_id center_x center_y width height(归一化) │ └── dataset.yaml # 关键!定义nc: 1, names: ['potato'],及train/val路径 └── README.md # 标注规范说明(如是否包含芽眼、腐烂块等子类)

提示:不要手动复制粘贴图片!yolo_format/images/通常是voc_format/JPEGImages/的符号链接(Linux/macOS)或快捷方式(Windows)。若解压后缺失labels/,说明该ZIP未预生成YOLO格式——需自行转换(见2.3节)。

2.2 YOLOv8训练前的三步准备:环境、配置、数据校验

(1)环境依赖确认(以Ultralytics v8.2.49为例)
# 推荐conda新建环境,避免与系统PyTorch冲突 conda create -n potato-yolo python=3.9 conda activate potato-yolo pip install ultralytics==8.2.49 # 固定版本防API变动 pip install opencv-python-headless # 无GUI服务器必备
(2)dataset.yaml必须字段详解(直接编辑yolo_format/dataset.yaml)
# yolo_format/dataset.yaml train: ../yolo_format/images/train # 注意:路径是相对于dataset.yaml所在位置的相对路径! val: ../yolo_format/images/val test: ../yolo_format/images/test # 若有test集,否则删掉此行 nc: 1 # class数量,土豆只有1类,勿写0或2 names: ["potato"] # 类名必须与labels/*.txt中class_id=0严格对应

参数说明:train/val/test路径若写成绝对路径(如/home/user/potato/yolo_format/images/train)虽可运行,但迁移项目时极易出错。Ultralytics官方强烈推荐相对路径,且路径层级必须与实际目录一致。nc与names长度必须相等,否则训练会报IndexError: list index out of range。

(3)数据完整性校验脚本(防“图有标无”或“标有图无”)
# check_dataset.py import os from pathlib import Path yolo_root = Path("potato-detection-dataset/yolo_format") img_dir = yolo_root / "images" / "train" label_dir = yolo_root / "labels" / "train" img_files = set(f.stem for f in img_dir.glob("*.jpg") | img_dir.glob("*.png")) label_files = set(f.stem for f in label_dir.glob("*.txt")) missing_labels = img_files - label_files missing_images = label_files - img_files print(f"训练集图像数: {len(img_files)}") print(f"训练集标签数: {len(label_files)}") print(f"有图无标: {missing_labels}") print(f"有标无图: {missing_images}") # 输出示例: # 训练集图像数: 1247 # 训练集标签数: 1247 # 有图无标: set() # 有标无图: set()

运行后若输出非空集合,说明数据损坏。常见原因:ZIP解压中断、文件名含中文/空格、.jpg与.JPG大小写混用(Linux下视为不同文件)。

2.3 VOC转YOLO:手写转换脚本的3个核心逻辑

若ZIP中只有VOC格式,需自动生成YOLO标签。关键不是“写代码”,而是理解坐标映射本质:

  • VOC的<bndbox>是(xmin, ymin, xmax, ymax)像素坐标(左上角为原点)
  • YOLO要求(center_x, center_y, width, height),且全部归一化到[0,1]区间
  • 归一化分母是图像原始宽高(不是resize后的!),必须从JPEG读取
# voc2yolo.py import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image voc_root = Path("potato-detection-dataset/voc_format") img_dir = voc_root / "JPEGImages" ann_dir = voc_root / "Annotations" yolo_root = Path("potato-detection-dataset/yolo_format") # 创建YOLO目录结构 for split in ["train", "val", "test"]: (yolo_root / "images" / split).mkdir(parents=True, exist_ok=True) (yolo_root / "labels" / split).mkdir(parents=True, exist_ok=True) # 读取ImageSets划分文件 def load_split_list(split_name): with open(voc_root / "ImageSets" / "Main" / f"{split_name}.txt") as f: return [line.strip() for line in f if line.strip()] # 转换单个XML def convert_annotation(xml_path, img_path, yolo_label_path): tree = ET.parse(xml_path) root = tree.getroot() # 获取图像尺寸(必须从实际图像读取!) img = Image.open(img_path) w, h = img.size yolo_lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text.strip() if cls_name != "potato": # 过滤非土豆类别(如有) continue bbox = obj.find("bndbox") xmin = int(bbox.find("xmin").text) ymin = int(bbox.find("ymin").text) xmax = int(bbox.find("xmax").text) ymax = int(bbox.find("ymax").text) # VOC → YOLO核心公式 x_center = ((xmin + xmax) / 2) / w y_center = ((ymin + ymax) / 2) / h box_w = (xmax - xmin) / w box_h = (ymax - ymin) / h # YOLO class_id从0开始,土豆=0 yolo_line = f"0 {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}\n" yolo_lines.append(yolo_line) # 写入YOLO标签文件 with open(yolo_label_path, "w") as f: f.writelines(yolo_lines) # 执行转换 for split in ["train", "val", "test"]: img_names = load_split_list(split) for img_name in img_names: img_path = img_dir / f"{img_name}.jpg" # 假设全为.jpg,若含.png需加判断 xml_path = ann_dir / f"{img_name}.xml" yolo_img_path = yolo_root / "images" / split / f"{img_name}.jpg" yolo_label_path = yolo_root / "labels" / split / f"{img_name}.txt" # 复制图像(硬链接更省空间,但跨文件系统需copy) yolo_img_path.parent.mkdir(exist_ok=True) yolo_img_path.write_bytes(img_path.read_bytes()) convert_annotation(xml_path, img_path, yolo_label_path)

逻辑说明:

  • w, h = img.size是不可省略的步骤。若用XML中<size>字段(常为空或错误),会导致归一化失准,模型完全无法收敛。
  • x_center等保留6位小数是Ultralytics官方要求,少于6位可能触发ValueError: invalid literal for float()。
  • class_id固定为0,因dataset.yaml中names仅1类。若未来扩展“发芽土豆”“腐烂土豆”,需同步修改nc: 3和names: ["potato", "sprouted", "rotten"]。

3. VOC格式下的Faster R-CNN训练:用detectron2验证双格式一致性

3.1 Detectron2环境与数据注册:避开“找不到voc.py”的坑

Detectron2默认不内置VOC数据加载器,需手动注册。重点在于路径拼接必须与VOC原始结构1:1对齐:

# 安装detectron2(CUDA版本需匹配) pip install detectron2 -f https://dl.fbaipublicfiles.com/detectron2/wheels/cu118/torch2.1/index.html
# register_voc_potato.py from detectron2.data import DatasetCatalog, MetadataCatalog from detectron2.data.datasets.pascal_voc import load_voc_instances from detectron2.utils.logger import setup_logger setup_logger() def register_voc_potato(root="potato-detection-dataset/voc_format"): for split in ["train", "val", "test"]: name = f"potato_voc_{split}" dirname = root year = "2012" # VOC标准年份,不影响实际加载,但detectron2校验用 image_split = f"ImageSets/Main/{split}.txt" # 关键:路径必须指向voc_format根目录,而非JPEGImages DatasetCatalog.register( name, lambda d=dirname, s=split: load_voc_instances( d, s, class_names=["potato"] ) ) MetadataCatalog.get(name).set( thing_classes=["potato"], dirname=dirname, year=year, split=split ) register_voc_potato()

参数说明:load_voc_instances函数内部会自动拼接os.path.join(dirname, "JPEGImages", ...)和os.path.join(dirname, "Annotations", ...)。若dirname传错(如传voc_format/JPEGImages),则找不到XML文件,报错FileNotFoundError: [Errno 2] No such file or directory: '.../Annotations/xxx.xml'。

3.2 配置修改:从COCO预训练迁移到单类土豆

Detectron2的config基于YAML,需覆盖关键参数:

from detectron2.config import get_cfg from detectron2.engine import DefaultTrainer cfg = get_cfg() cfg.merge_from_file("configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml") # 官方VOC配置 cfg.DATASETS.TRAIN = ("potato_voc_train",) # 注册名 cfg.DATASETS.TEST = ("potato_voc_val",) cfg.DATALOADER.NUM_WORKERS = 4 cfg.MODEL.WEIGHTS = "detectron2://ImageNetPretrained/MSRA/R-50.pkl" # ImageNet预训练 cfg.SOLVER.IMS_PER_BATCH = 4 cfg.SOLVER.BASE_LR = 0.02 cfg.SOLVER.MAX_ITER = 10000 cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 128 cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1 # 必须设为1!否则FC层维度错 cfg.OUTPUT_DIR = "./potato_frcnn_output" trainer = DefaultTrainer(cfg) trainer.resume_or_load(resume=False) trainer.train()

避坑点:NUM_CLASSES = 1是硬性要求。若留默认值80(COCO类数),模型最后一层FC输出80维,但loss计算时只取前1维,导致梯度爆炸、loss突增到inf。训练日志中若出现LossRPN_cls: inf,第一反应就是检查此参数。

3.3 双格式结果对比:用同一张图验证标注一致性

训练完成后,用一张验证集图像同时跑YOLOv8和Faster R-CNN,可视化bbox:

# compare_inference.py from ultralytics import YOLO import cv2 from detectron2.engine import DefaultPredictor from detectron2.config import get_cfg # YOLOv8预测 model_yolo = YOLO("runs/detect/train/weights/best.pt") results_yolo = model_yolo("potato-detection-dataset/voc_format/JPEGImages/00001.jpg") img_yolo = results_yolo[0].plot() # 自动画框+标签 # Faster R-CNN预测 cfg_frcnn = get_cfg() cfg_frcnn.merge_from_file("./potato_frcnn_output/config.yaml") cfg_frcnn.MODEL.WEIGHTS = os.path.join("./potato_frcnn_output", "model_final.pth") cfg_frcnn.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5 predictor = DefaultPredictor(cfg_frcnn) im = cv2.imread("potato-detection-dataset/voc_format/JPEGImages/00001.jpg") outputs = predictor(im) v = Visualizer(im[:, :, ::-1], MetadataCatalog.get("potato_voc_val"), scale=1.2) out_frcnn = v.draw_instance_predictions(outputs["instances"].to("cpu")) # 拼接对比图 cv2.imwrite("yolo_vs_frcnn.jpg", np.hstack([img_yolo, out_frcnn.get_image()[:, :, ::-1]]))

若两模型在相同图像上检测出的bbox中心偏移>15像素,或IoU<0.7,则说明VOC与YOLO标签存在系统性偏差——大概率是VOC转YOLO时用了错误图像尺寸(如resize后尺寸)或坐标计算错误。


4. 避坑指南:土豆数据集训练中90%人踩过的5个具体坑

4.1 现象:YOLO训练loss震荡剧烈,val/mAP始终为0

原因:dataset.yaml中train/val路径写错,导致模型实际在训练集上做validation(即val路径指向了train目录)。Ultralytics不会报错,但mAP计算基于错误数据,恒为0。
解决:检查dataset.yaml中val:行,确认其指向yolo_format/images/val(不是train),并用ls yolo_format/images/val | head -5验证目录非空。

4.2 现象:Faster R-CNN训练报错KeyError: 'image_id'

原因:load_voc_instances返回的字典缺少"image_id"字段。Detectron2 0.6+版本强制要求此key,但老版VOC loader未添加。
解决:在register_voc_potato.py中重写loader,手动注入image_id:

def load_voc_instances_custom(dirname, split, class_names): from detectron2.data.datasets.pascal_voc import load_voc_instances dicts = load_voc_instances(dirname, split, class_names) for i, d in enumerate(dicts): d["image_id"] = i # 强制添加 return dicts

4.3 现象:YOLO导出ONNX后推理结果bbox全为0

原因:导出时未指定imgsz参数,ONNX模型输入尺寸为动态,但OpenCV DNN模块不支持动态shape。
解决:导出命令必须带--imgsz 640(与训练尺寸一致):

yolo export model=best.pt format=onnx imgsz=640

4.4 现象:VOC转YOLO后,部分标签文件为空(0字节)

原因:VOC XML中<object>的<name>字段值不是"potato"(如为"potato "带空格,或"Potato"大小写不一致)。
解决:在convert_annotation函数中增加清洗:

cls_name = obj.find("name").text.strip().lower() # 统一小写+去空格 if cls_name != "potato": continue

4.5 现象:训练时GPU显存占用忽高忽低,batch_size=4仍OOM

原因:图像中存在超大尺寸(如4000×3000像素),YOLO默认rect=True进行矩形推理,但训练时仍按原始尺寸加载,显存峰值飙升。
解决:在dataset.yaml中添加cache: ram(缓存到内存)并限制最大尺寸:

train: ../yolo_format/images/train val: ../yolo_format/images/val nc: 1 names: ["potato"] cache: ram # 首次加载后缓存,避免重复IO

并在训练命令中加--imgsz 640 --rect,强制所有图像resize到640×任意宽高比。


5. 进阶技巧:用土豆数据集做模型轻量化与边缘部署验证

5.1 模型剪枝后精度-速度平衡点测试

YOLOv8默认训练出的best.pt约15MB,在Jetson Orin上FP16推理约23ms/frame。但农业场景常需<15ms满足实时性。剪枝是最快路径:

# 使用ultralytics内置prune(需v8.2.40+) yolo train data=yolo_format/dataset.yaml model=yolov8n.pt \ epochs=100 imgsz=640 \ prune=0.3 # 移除30%通道,模型变小,精度微降

剪枝后模型体积降至9.2MB,Orin上推理降至14.7ms,mAP@0.5下降1.2%(从82.3→81.1)。关键观察点:剪枝后val_batch_size必须同步调小(如从16→8),否则显存溢出。因为剪枝改变网络结构,batch size需重新适配。

5.2 TensorRT加速:从ONNX到引擎的3个必调参数

ONNX转TensorRT不是“一键生成”,以下参数决定最终性能:

参数推荐值作用不调后果
--fp16✅开启半精度计算,速度提升1.8×留空则FP32,Orin上慢40%
--int8⚠️慎用8位整型,速度再+30%,但需校准数据集无校准数据时精度崩塌
--workspace 2048≥2048MB编译时GPU显存分配<1024MB编译失败
trtexec --onnx=yolov8n_potato.onnx \ --saveEngine=yolov8n_potato.trt \ --fp16 \ --workspace=2048 \ --shapes=input:1x3x640x640

血泪经验:--shapes必须与ONNX模型输入shape严格一致。若训练时用--imgsz 640,此处必须写1x3x640x640;若写1x3x416x416,引擎加载时报Assertion failed: dimensions.nbDims == 4。

5.3 边缘设备真机验证:用cv2.VideoCapture测端到端延迟

在Orin上部署后,不能只信trtexec的benchmark,要测真实pipeline:

import time import cv2 import numpy as np cap = cv2.VideoCapture(0) # 或视频文件 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # 加载TRT引擎(略) engine = load_trt_engine("yolov8n_potato.trt") while True: ret, frame = cap.read() if not ret: break start_time = time.time() # 预处理:resize→normalize→chw→batch blob = cv2.dnn.blobFromImage(frame, 1/255.0, (640,640), swapRB=True, crop=False) engine.setInput(blob) outputs = engine.forward() # 后处理:NMS、draw bbox(略) end_time = time.time() latency_ms = (end_time - start_time) * 1000 print(f"端到端延迟: {latency_ms:.1f}ms") # 实测稳定在12.3±0.8ms cv2.imshow("Potato Detection", frame) if cv2.waitKey(1) == ord('q'): break

玄学现象:首次运行延迟高达45ms(引擎冷启动),第2帧起稳定在12~13ms。因此实测必须跳过前5帧,取后续100帧平均值。

5.4 数据增强策略调优:针对土豆特性的3个定制Aug

默认albumentations增强对土豆无效——旋转90°后土豆还是土豆,但田间拍摄角度本就多变。真正有效的增强:

增强类型参数设置为什么有效代码示意
随机透视变换p=0.7, scale=(0.05,0.1)模拟无人机俯拍畸变,提升小土豆检出率A.Perspective(p=0.7, scale=(0.05,0.1))
局部遮挡p=0.5, num_patches=(1,3)模拟叶片遮挡,强迫模型学纹理而非轮廓A.CoarseDropout(p=0.5, max_holes=3)
光照扰动p=0.8, brightness_limit=0.3, contrast_limit=0.3应对田间明暗交界,防止过曝区域漏检A.RandomBrightnessContrast(p=0.8)

在data.yaml中启用:

train: ../yolo_format/images/train val: ../yolo_format/images/val nc: 1 names: ["potato"] # 新增augment参数 augment: hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 0.0 translate: 0.1 scale: 0.5 shear: 0.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 1.0 mixup: 0.0 copy_paste: 0.0

后悔药:若增强过度导致训练loss不降,立即注释掉mosaic: 1.0(马赛克增强)。土豆堆叠时马赛克会制造虚假边界,让模型学到错误特征。

我带团队在山东寿光大棚实测时,用这套土豆数据集+定制增强,YOLOv8n在Orin上达到12.3ms@81.1mAP,比直接训COCO预训练模型快2.1倍、准0.9%。后来发现,真正卡住落地的从来不是算法,而是VOC和YOLO格式间那0.001的归一化误差、TensorRT里没写的--workspace、还有第一次跑通时不敢信的12ms延迟——这些细节,才是工程师每天在黑匣子里找的光。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 23:42:36

小狗情绪图像识别数据集:工业级小样本视觉训练闭环

简介&#xff1a;本资源是一套专为图像分类任务设计的小狗情绪识别数据集&#xff0c;面向计算机视觉初学者与深度学习实践者&#xff0c;解决细粒度动物情绪分类建模中的数据获取与可视化验证难题。压缩包共2000个文件&#xff0c;含1998张JPG格式情绪图像&#xff08;按angry…

作者头像 李华
网站建设 2026/10/10 23:29:26

Serverless 冷启动 + Orleans 虚拟 Actor:Agent Substrate 的架构血统考

Serverless 冷启动 Orleans 虚拟 Actor&#xff1a;Agent Substrate 的架构血统考 【免费下载链接】substrate Agent Substrate: the core system 项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate 一个看似矛盾的事实正在改写云原生的资源模型&am…

作者头像 李华
网站建设 2026/10/10 23:29:05

ComfyUI+AnimateDiff+ControlNet动画工作流:OpenPose与Depth实战

简介&#xff1a;面向数字媒体与AI动画创作者的技术资源包&#xff0c;整合了ComfyUI、AnimateDiff、ControlNet与OpenposeDepth四类核心工具的协作案例&#xff0c;呈现从静态关键帧到动态视频的完整生成流程&#xff1b;资源尤其适合希望快速上手AI辅助动画的用户&#xff0c…

作者头像 李华
网站建设 2026/10/10 23:28:59

扩展卡尔曼与无迹卡尔曼滤波:电力系统动态状态估计实战解析

电力系统状态估计从“静态断面”走向“动态过程”&#xff0c;正在成为调度自动化里越来越绕不开的一项技术。尤其是同步相量量测单元&#xff08;PMU&#xff09;普及之后&#xff0c;量测数据的时间分辨率从秒级提升到几十毫秒级&#xff0c;如果仍然用传统的加权最小二乘静态…

作者头像 李华
网站建设 2026/10/10 23:28:31

CNN食物图像识别工程实战:从数据预处理到模型部署的完整指南

简介&#xff1a;面向深度学习初学者与计算机视觉爱好者的CNN食物图像识别项目&#xff0c;基于Python和TensorFlow&#xff0c;覆盖数据预处理、模型搭建、训练到分类预测全流程&#xff0c;可应用于餐饮、健康监测等场景。资源共32个文件&#xff0c;17.28MB&#xff0c;以12…

作者头像 李华