news 2026/9/28 5:37:08

马铃薯缺陷检测数据集:8000张图5类缺陷,YOLO训练与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
马铃薯缺陷检测数据集:8000张图5类缺陷,YOLO训练与避坑指南

简介:本资源为面向目标检测学习者的马铃薯缺陷检测数据集,适用于YOLO全系列网络训练,可支撑农产品质检、智能农业等场景下的缺陷识别任务。数据集融合了常见马铃薯缺陷图像,涵盖发芽、真菌病害、机械损伤等5个类别,具体类别可参考class文本文件。压缩包共2000个文件,以1999个txt标签文件和1个Python脚本为主,整体约409.72MB,标签采用YOLO格式,可直接投入训练流程。其中show.py脚本可用于数据可视化,将标注框绘制在图像上,便于快速核验标注质量与类别分布。目前已有436人学习下载,适合从事目标检测实践、需要真实缺陷样本进行模型训练与验证的开发者及学生参考使用。

1. 马铃薯缺陷检测数据集:8000 张图、5 类缺陷,能不能直接喂给 YOLO

拿到一个农业质检的项目,客户张口就要「识别发芽、发霉、破损的土豆」,还要求产线速度。你第一反应肯定是找开源数据集,但 COCO、VOC 里根本没有「发芽马铃薯」这种细粒度类别,自己从零标 8000 张图,两个人干一个月都未必标得完。这份马铃薯(potato)图像缺陷检测数据集就是冲着这个缺口来的:它把常见的马铃薯缺陷数据做了融合,总共超过 8000 张图像,配 labelme 标注,并且已经处理成 YOLO 格式,训练集、验证集、标签、class 文件齐全,YOLO 全系列网络都能直接吃。

它解决的不是「有没有图」的问题,而是「类别定义能不能对上产线质检口径」的问题。类别一共 5 类,包括 Sprouted potato(发芽)、Diseased-fungal potato(真菌病害)、Damaged potato(破损)等,具体以 class 文本文件为准。适合谁?做农产品分选、食品加工质检、农业机器人视觉的从业者,以及想拿一个真实缺陷场景练 YOLO 微调的人。下面我按「先看懂结构、再跑通可视化、再训练、最后避坑」的顺序拆一遍。

2. 数据集结构与 YOLO 格式:先搞懂目录和标签长什么样

2.1 目录组织与文件命名规律

这份数据集最容易被忽略的是它的文件命名。你从项目正文里能看到一堆像images-11-_jpeg_jpg.rf.79ba1df764e9e8c303a2e7e7b6259ab0.txt这样的标签文件名,中间那串rf.加 32 位十六进制是典型的在线标注平台导出特征——图像和标签同名,只是扩展名不同。这意味着你拿到手后,图像目录和标签目录是分开的,靠文件名主干一一对应。

常见做法是整理成这样的结构,方便 YOLO 直接读:

potato_dataset/ ├── images/ │ ├── train/ # 训练图像 │ └── val/ # 验证图像 ├── labels/ │ ├── train/ # 训练标签 txt │ └── val/ # 验证标签 txt ├── classes.txt # 5 个类别名,一行一个 └── show.py # 可视化脚本

这里有个血泪经验:很多人直接把所有图丢进一个文件夹就开训,结果验证集里混进了训练图,mAP 虚高到 0.95,上线一测全崩。训练集和验证集必须在文件层面就分开,别指望训练脚本帮你随机切。

2.2 YOLO 标签格式逐字段拆解

YOLO 的标签是纯文本,每行一个目标,格式是class_id x_center y_center width height,后四个都是归一化到 0~1 的相对值。拿一行举例:

0 0.512 0.634 0.221 0.318
  • 0:类别索引,对应 classes.txt 里的第 0 行,比如 Sprouted potato
  • 0.512:目标框中心点 x 坐标 ÷ 图像宽度
  • 0.634:中心点 y 坐标 ÷ 图像高度
  • 0.221:框宽 ÷ 图像宽度
  • 0.318:框高 ÷ 图像高度

为什么用归一化而不是绝对像素?因为 YOLO 训练时会做多尺度增强,绝对坐标一缩放就错位,归一化后无论图怎么 resize 都成立。这也是为什么你改图像尺寸时不用动标签。

2.3 用脚本校验标签合法性

在训练前,我一般会先跑一个校验脚本,把越界、空标签、类别越界的文件揪出来。这类融合数据集最容易出现标注平台导出时的坐标溢出:

import os import glob def check_labels(label_dir, num_classes=5): bad_files = [] for txt in glob.glob(os.path.join(label_dir, "*.txt")): with open(txt, "r") as f: lines = f.readlines() if not lines: bad_files.append((txt, "空标签")) continue for i, line in enumerate(lines): parts = line.strip().split() if len(parts) != 5: bad_files.append((txt, f"第{i}行字段数={len(parts)}")) continue cls_id = int(parts[0]) coords = [float(x) for x in parts[1:]] if cls_id < 0 or cls_id >= num_classes: bad_files.append((txt, f"第{i}行类别越界={cls_id}")) if any(c < 0 or c > 1 for c in coords): bad_files.append((txt, f"第{i}行坐标越界={coords}")) return bad_files if __name__ == "__main__": bad = check_labels("potato_dataset/labels/train") print(f"发现 {len(bad)} 个问题文件") for path, reason in bad[:20]: print(path, reason)

逻辑说明:遍历标签目录下所有 txt,逐行检查字段数是否为 5、类别 id 是否在[0, num_classes)内、四个坐标是否落在[0,1]。参数num_classes默认 5,如果你的 class 文件实际类别数不同,改这个值。跑完把问题文件列出来,坐标越界的要么修要么删,别带着脏数据训练,否则 loss 会莫名其妙震荡。

3. 可视化与训练:show.py 怎么用、YOLO 怎么配

3.1 show.py 把 box 画回图像上

数据集自带的show.py是验证「图和标签对不对得上」的第一道关。它的作用就是把 YOLO 格式的 box 反归一化后画到原图上。核心逻辑大概是这样:

import cv2 import os def draw_yolo_box(img_path, label_path, classes, save_path=None): img = cv2.imread(img_path) h, w = img.shape[:2] if os.path.exists(label_path): with open(label_path) as f: for line in f: cls_id, xc, yc, bw, bh = line.strip().split() cls_id = int(cls_id) xc, yc, bw, bh = map(float, (xc, yc, bw, bh)) # 反归一化:中心点 + 宽高 -> 左上右下像素坐标 x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, classes[cls_id], (x1, max(y1 - 5, 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) if save_path: cv2.imwrite(save_path, img) return img if __name__ == "__main__": classes = [l.strip() for l in open("potato_dataset/classes.txt")] draw_yolo_box("potato_dataset/images/train/xxx.jpg", "potato_dataset/labels/train/xxx.txt", classes, "vis_out.jpg")

逻辑说明:先读图拿宽高,再把归一化坐标乘回像素。xc - bw/2是左上角 x,xc + bw/2是右下角 x,y 同理。参数classes从 classes.txt 读,顺序必须和标签里的 class_id 严格对应,错一位就会把「发芽」标成「破损」。跑几张图肉眼看一下,框是不是正好套在缺陷上,这是最省事的质检方式。

3.2 生成 YOLO 训练用的 data.yaml

YOLO 系列训练靠一个 yaml 描述数据路径和类别。常见写法:

path: /home/user/potato_dataset train: images/train val: images/val nc: 5 names: 0: Sprouted potato 1: Diseased-fungal potato 2: Damaged potato 3: class_4 4: class_5

path是数据集根目录,train/val是相对路径。nc必须等于类别数,names的键从 0 开始连续。这里最容易翻车的是names顺序和 classes.txt 不一致——训练能跑,但推理时类别名全错位,你还以为是模型没学好。

3.3 起训命令与关键参数

以 YOLOv8 为例,一条命令就能起训:

yolo detect train \ data=potato_dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/potato \ name=exp1

参数逐个说:model=yolov8n.pt用 nano 版先跑通,确认流程没问题再换 s/m;imgsz=640是输入分辨率,缺陷目标小的话可以提到 960,但显存翻倍;batch=16按显存调,爆显存就降到 8;lr0=0.01初始学习率,微调预训练模型时我一般降到 0.001 更稳;patience=20是早停,20 轮没提升就停,省时间。训练日志里重点盯mAP50和mAP50-95,前者看召回,后者看框的精度。

4. 避坑与排查:融合数据集最容易踩的五个坑

4.1 类别名对不上,训练正常但推理全错

现象:训练 loss 正常下降,mAP 也还行,但推理时框的位置对、类别名全乱。原因:data.yaml的names顺序和classes.txt不一致,或者标签里的 class_id 是从 1 开始而不是 0。解决:用 2.3 的校验脚本确认 class_id 范围,再逐行比对 classes.txt 和 yaml 的 names,顺序必须完全一致。

4.2 图像和标签文件名主干不匹配

现象:训练报「找不到标签」或大量图被跳过,实际参与训练的样本远少于 8000。原因:融合数据来自多个来源,命名规则不统一,有的图是.jpg标签是.txt但主干差一个后缀。解决:写脚本按主干(去掉扩展名)做匹配,把没有对应标签的图移出去,别让它们污染训练集。

4.3 验证集混入训练图导致指标虚高

现象:验证 mAP 高得离谱,上线一测惨不忍睹。原因:切分时随机打乱,同一张图的增强版本同时进了训练和验证。解决:按原始图像(不是增强后)切分,训练验证比例 8:2 或 9:1,切完再各自做增强。

4.4 小目标缺陷被 resize 抹掉

现象:发芽这种小目标召回率极低。原因:imgsz=640时原图被压缩,几十像素的芽点直接糊没。解决:提高输入分辨率到 960 或 1280,或者用切片推理(把大图切小块分别检测再合并)。代价是显存和推理时间上升,产线要权衡。

4.5 类别不平衡导致模型偏向多数类

现象:破损类样本多,发芽类样本少,模型几乎不预测发芽。原因:5 类缺陷在 8000 张图里分布不均。解决:训练时开类别权重,或用过采样补少数类;YOLOv8 可以在 loss 里调cls权重,也可以先统计每类框数量再决定策略。

5. 进阶技巧:用混淆矩阵和单类 AP 定位短板

训练跑完不是看个总 mAP 就完事。我习惯先看混淆矩阵,它能告诉你模型把哪两类搞混了——比如「Diseased-fungal」和「Damaged」经常互串,说明这两类视觉特征接近,得回去看标注边界是否清晰。YOLO 训练完会在runs/potato/exp1/下生成confusion_matrix.png和results.csv。

results.csv里每轮都有metrics/mAP50-95(B),但真正有用的是按类拆开的 AP。用下面这段把每类 AP 拉出来对比:

import pandas as pd df = pd.read_csv("runs/potato/exp1/results.csv") df.columns = [c.strip() for c in df.columns] # 找出所有按类记录的 AP 列 ap_cols = [c for c in df.columns if "AP" in c and "50-95" in c] print(df[ap_cols].iloc[-1].sort_values())

逻辑说明:读训练结果 csv,筛出每类的 AP50-95 列,取最后一轮的值排序。排在最下面的就是短板类。参数上,如果某一类 AP 明显低于其他类,优先补这类样本或检查标注质量,而不是盲目加轮数。

再补一个实用习惯:推理时把置信度阈值调低到 0.25 先看召回,确认漏检情况,再逐步提到 0.5 看精度。产线场景宁可多报也别漏报,阈值策略要按业务定。我一般会在验证集上画 PR 曲线,找召回和精度的平衡点,而不是拍脑袋定 0.5。

从那以后我每次拿到融合数据集,都强制先跑一遍标签校验、再可视化抽检 20 张、最后按类看 AP,这三步走完才敢起正式训练。希望这份拆解帮到你,少走几个我踩过的坑。

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

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

MGWR多尺度地理加权回归:Python实战从原理到应用

做空间分析这些年&#xff0c;我最深的体会是&#xff1a;模型跑不出来固然让人着急&#xff0c;但模型跑出来之后不知道该怎么解释&#xff0c;才真正让人头疼。今天要聊的多尺度地理加权回归&#xff08;MGWR&#xff09;&#xff0c;就是那种“跑起来容易、解释起来有意思”…

作者头像 李华
网站建设 2026/9/28 5:36:39

微信小程序+SSM家庭大厨全栈项目实战:从数据库到真机调试

项目标题里的“家庭大厨微信小程序ssm”&#xff0c;看着很典型&#xff0c;其实就是一套“微信小程序做前端展示、SSM做后端服务”的完整实战项目。做过毕业设计或者课程设计的人应该都懂&#xff0c;这类项目最讲究“麻雀虽小五脏俱全”&#xff1a;小程序端要能看菜谱、搜菜…

作者头像 李华
网站建设 2026/9/28 5:36:27

用Docker部署Jenkins:容器化安装配置与排障全指南

1. 为什么要用 Docker 部署 Jenkins先说结论&#xff1a;如果你还在用传统方式往宿主机上装 Jenkins&#xff0c;那大概率是在给自己埋坑。传统安装 Jenkins 的痛点我太熟悉了。首先是 JDK 依赖问题&#xff0c;Jenkins 新版本对 JDK 版本有硬性要求&#xff0c;比如 Jenkins 2…

作者头像 李华
网站建设 2026/9/28 5:36:26

今日头条中文新闻分类数据集:从zip到可训练语料的完整实战路径

简介&#xff1a;这份今日头条中文新闻文本分类数据集面向NLP研究者、算法开发者及机器学习爱好者&#xff0c;用于训练和评估中文文本分类模型&#xff0c;覆盖国际、国内、娱乐、体育等新闻类别的识别任务&#xff0c;适合入门练手与进阶实验。压缩包共4个文件&#xff0c;以…

作者头像 李华
网站建设 2026/9/28 5:35:27

网络通信模型实战指南:从分层原理到故障排查

很多开发者在排查网络问题时&#xff0c;第一反应是“是不是网断了”“是不是防火墙拦了”&#xff0c;但很少会去想&#xff1a;一次HTTP请求从发起到返回&#xff0c;中间到底经过了哪些环节、每一层各自干了什么活。这个问题如果答不清楚&#xff0c;那排查网络故障基本靠猜…

作者头像 李华
网站建设 2026/9/28 5:34:03

Linux命令本质与实战:从背命令到用命令解决真实问题

1. 别急着背命令&#xff0c;先搞清楚 Linux 命令的本质每年都有大量新人涌入 Linux 这个圈子&#xff0c;有的是运维转岗&#xff0c;有的是开发要部署环境&#xff0c;还有的是学生做实验。大家干的第一件事出奇一致&#xff1a;找一份"Linux 常用命令大全"开始背。…

作者头像 李华