news 2026/10/16 12:00:23

中草药目标检测数据集:YOLO格式实战与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
中草药目标检测数据集:YOLO格式实战与避坑指南

简介:面向目标检测任务的中草药图像YOLO数据集,适合需要训练中草药识别模型的算法工程师、科研人员及目标检测初学者。数据已按YOLOv5目录结构严格划分,训练集约2600张、验证集约190张、测试集约100张图片及对应txt标注,类别共8个,包括Cardamom、Cumin、Neem等,具体可查看classes文件。标注采用YOLO标准相对坐标格式(类别、中心点x、中心点y、宽、高),无需任何格式转换,可直接投入YOLO系列模型训练与评估。压缩包内共2000个文件,以1999个txt标注文件为主,配合1个show.py数据可视化脚本;该脚本无需修改即可随机读取图片并绘制边界框,结果自动保存至当前目录,方便快速核查标注质量。资源包大小209.51MB,已有1017人学习下载,无论是用于毕设、科研实验还是实际项目原型验证,都能省去数据准备环节,帮助开发者直接聚焦模型效果,是一份可直接上手的现成数据基础。

1. 中草药目标检测数据集:拿过来就能跑的YOLO格式资源

做目标检测最头疼的不是模型选型,而是数据。中草药这类细粒度目标,网上公开数据集少得可怜,自己爬图标注一张平均要两分钟,两千张就是六十多个小时。这份YOLO格式的中草药图像数据集,解决了从零开始攒数据的最大痛点——它已经完成标注、划分和格式整理,下载后直接用YOLOv5/v8训练即可,连目录结构都是按datasets标准摆放的。八类中草药(Cardamom、Cumin、Neem等),训练集约2600张、验证集约190张、测试集约100张,全部采用YOLO相对坐标标注(class, x_center, y_center, w, h)。适合三类人:刚入门想跑通YOLO训练全流程的新手、做农产品或药材检测项目需要快速验证方案、以及需要一份干净基线数据做算法对比的研究者。

2. 数据集内部结构:YOLOv5目录规范与标注文件格式

2.1 目录树拆解:为什么说“按YOLOv5文件夹保存”就能直接训

拿到数据集后,第一件事是先摸清目录结构。项目按YOLOv5官方推荐的datasets布局组织,根目录下是images和labels两个大文件夹,各自再按train、val、test拆分。这种结构的好处是YOLOv5的train.py默认就读取这种布局,不需要改数据加载代码,只是训练时在data.yaml里指定路径即可。

datasets/ ├── images/ │ ├── train/ # 约2600张 │ ├── val/ # 约190张 │ └── test/ # 约100张 ├── labels/ │ ├── train/ # 对应txt标注 │ ├── val/ │ └── test/ ├── classes.txt # 类别文件 └── show.py # 可视化脚本

注意labels的目录层级必须与images完全镜像,文件名也必须一一对应——图片是1000_F_604576389_xxx.jpg,标注就是1000_F_604576389_xxx.txt,只差后缀名。训练时YOLO靠这个对应关系去找标注文件,一旦文件名对不上就会在训练日志里刷Warning,而且这些图片会被静默跳过,属于常见的数据集翻车点。

2.2 labels里的txt到底写的什么:相对坐标解析

打开任意一个txt文件,内容长这样:

2 0.48359375 0.3578125 0.603125 0.575 5 0.6953125 0.18359375 0.240625 0.284375

每行对应一个目标框,四个数字的含义是:类别id、归一化后的中心点x坐标、归一化后的中心点y坐标、归一化后的框宽、归一化后的框高。归一化是指除以图片原始宽高,所以所有值都在0到1之间。这一点和VOC的x_min, y_min, x_max, y_max格式不同,很多从VOC转过来的新手在这里翻车——拿着VOC的绝对坐标直接当YOLO用,训练出来的框全是偏的。

类别id与classes.txt的序号一一对应。比如classes.txt内容如果是:

Cardamom Cumin Neem ...

那么第一行开头写2,就代表该框属于第三类Neem(从0开始计数)。训练前务必用文本编辑器打开classes.txt核对类别顺序,因为data.yaml里的names列表必须与之一致,否则类别标签会错位——表现是loss正常下降,但推理出来的类别名和实际物体对不上,这是最难排查的玄学问题之一。

2.3 用Python快速检视数据集完整性

在动手训练前,我习惯先写个脚本做完整性检查:图片数量与txt数量是否一致、有没有空标注文件、类别分布是否均衡。这个检查只需要Python标准库就能实现,不用装额外依赖:

import os from pathlib import Path for split in ['train', 'val', 'test']: img_dir = Path(f'datasets/images/{split}') label_dir = Path(f'datasets/labels/{split}') imgs = list(img_dir.glob('*.jpg')) + list(img_dir.glob('*.png')) labels = list(label_dir.glob('*.txt')) print(f'{split}: images={len(imgs)}, labels={len(labels)}') empty_labels = [] for label_path in labels: if label_path.stat().st_size == 0: empty_labels.append(label_path.name) label_path.unlink() # 直接删掉空文件 if empty_labels: print(f' -> 发现并删除{len(empty_labels)}个空标注: {empty_labels[:5]}')

这里删除空txt对应图片的标注是必要的——YOLO训练时遇到空文件会视为背景图,如果你的应用场景不需要背景图,留着反而干扰训练。不过删之前最好确认一下该图片是否真的没有目标,有时候是标注工具漏标了,删掉标注会让这张图变成纯背景样本,影响正负样本平衡。

2.4 类别分布统计:训练前必须知道的数字

from collections import Counter category_counter = Counter() for split in ['train', 'val', 'test']: label_dir = f'datasets/labels/{split}' for file in os.listdir(label_dir): with open(os.path.join(label_dir, file)) as f: for line in f: category_counter[int(line.split()[0])] += 1 for class_id, count in sorted(category_counter.items()): print(f'class {class_id}: {count} instances')

类别分布直接决定模型收敛质量。如果某类只有几十个实例而其他类有两千多个,训练出来的模型对该类的recall会明显偏低。这份数据集整体分布相对均衡,但不同类别间仍然有几倍的差距。遇到不平衡,常见的做法是给data.yaml里每个类别设置不同的weight,或者简单粗暴地对少数类做数据增强——Mosaic、Copy-Paste这类增强对中草药这种纹理特征明显的目标效果不错。

3. 数据可视化与质量自检:show.py的运行逻辑和改造方法

3.1 原版show.py做了什么

项目自带的show.py是典型的数据集可视化复盘工具,核心逻辑很简单:随机抽一张图片,读取对应的txt标注,用OpenCV或PIL把矩形框画在图上,保存到当前目录。不需要改任何配置,直接运行就能出图,对新手很友好。

import cv2 import glob import random image_files = glob.glob('datasets/images/train/*.jpg') img_path = random.choice(image_files) label_path = img_path.replace('images', 'labels').replace('.jpg', '.txt') img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: for line in f: cls, x_center, y_center, bw, bh = map(float, line.split()) x1 = int((x_center - bw / 2) * w) y1 = int((y_center - bh / 2) * h) x2 = int((x_center + bw / 2) * w) y2 = int((y_center + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imwrite('visualized.jpg', img)

这段代码的关键点是坐标转换:把yolo的相对坐标乘回图片宽高得到像素坐标,然后用cv2.rectangle画框。类别用数字id展示,要显示类别名称的话,需要从classes.txt读进来做一个id到name的映射。

3.2 改造一:批量生成可视化缩略图而不是单张

原脚本一次只画一张图,要看全貌得反复运行,效率低。我一般会改造成批量模式——从每个类别里抽几张有代表性的图,一次画完拼成网格图。

import os import cv2 import numpy as np from collections import defaultdict # 按类别分组收集图片 class_images = defaultdict(list) for label_file in os.listdir('datasets/labels/train'): with open(f'datasets/labels/train/{label_file}') as f: first_line = f.readline().strip() if not first_line: continue cls = int(first_line.split()[0]) img_name = label_file.replace('.txt', '.jpg') class_images[cls].append(os.path.join('datasets/images/train', img_name)) # 每个类别抽3张,拼成3x3网格 for cls, imgs in class_images.items(): if len(imgs) >= 3: selected = np.random.choice(imgs, 3, replace=False) grid = np.zeros((h * 3, w * 3, 3), dtype=np.uint8) for i, img_path in enumerate(selected): img = cv2.imread(img_path) img = cv2.resize(img, (w, h)) r, c = divmod(i, 3) grid[r*h:(r+1)*h, c*w:(c+1)*w] = img cv2.imwrite(f'class_{cls}_sample.jpg', grid)

这个改造的核心价值是快速暴露类别错标问题——如果某个类别抽出来的3张图里有明显不是该类别的物体,说明标注阶段有噪声,训练前需要清洗。

3.3 改造二:画框的同时附带类别名和置信度

正式训练后你可能会想可视化预测结果而不是标注,这时候我把同样的框画法用在模型输出上,多了一个置信度维度:

# 假设这是模型输出的格式:cls, conf, x_center, y_center, w, h def draw_yolo_prediction(img_path, detections, class_names, output_path): img = cv2.imread(img_path) h, w = img.shape[:2] for cls, conf, xc, yc, bw, bh in detections: name = class_names[int(cls)] label = f'{name} {conf:.2f}' x1, y1 = int((xc - bw/2) * w), int((yc - bh/2) * h) x2, y2 = int((xc + bw/2) * w), int((yc + bh/2) * h) color = (0, 255, 255) if conf > 0.5 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 1) cv2.imwrite(output_path, img)

低置信度框用红色画,高置信度框用黄色画,一眼就能看出哪些目标模型拿不准,这些就是需要补数据或调阈值的候选样本。

3.4 可视化输出的判读标准:什么样的图说明数据有问题

可视化不只是“看一眼有没有框”,要看的是框的质量。我总结了几个快速判读维度:一是框是否紧贴目标边缘——如果框明显大于目标(比如框里有一大半是背景),说明标注时用上了外接矩形的习惯,这样训练出来的模型定位精度会差一点,但不算致命。二是同类目标在不同图片里框的大小分布是否合理——如果某类在中远景下框都很小,而数据集里几乎没有大目标的样本,模型对该类的大目标检测能力会偏弱。三是框之间有没有大量重叠——如果同一张图里同类目标框大面积重叠,这通常是重复标注而不是目标密集,需要人工确认。把可视化脚本多跑几次,随机抽几十张图看一遍,比盯着一千行log有用得多。

4. 避坑指南:这份数据集最容易踩的五个坑

4.1 图片和txt文件名对不上导致训练样本缩水

现象:训练日志里出现大量WARNING: Ignoring empty label file,或者训练完发现val集的mAP比预期低很多,训练集明明有两千六百张图,但实际参与训练的只有两千张左右。

原因:这份数据集来自多个渠道(文件名里带rf.前缀的是Roboflow导出格式),部分图片在导出时丢失了对应的txt文件,或者某些txt是空的。YOLOv5在数据加载阶段会把没有标注或标注为空的图片直接过滤掉,这个过滤是静默的,只在日志里刷Warning,容易被忽略。

解决:数据集根目录下跑一次完整性脚本,把没有对应txt的图片文件单独拎出来,确认这些图片是否真的没有目标——如果是漏标注可以人工补,如果本身是背景图就直接移出训练集,避免影响正负样本比例。脚本逻辑不复杂,遍历images目录下所有jpg,检查同名txt是否存在即可。

4.2 验证集和测试集被当作同一个目录用

现象:看项目介绍时发现测试集路径写的是datasets-images-val,明明是test却指向val目录。

原因:原作者在整理目录时把测试集和验证集放在了同一个目录下,或者README里路径写重复了。这种情况在网上下载的数据集里经常出现——标注工作量太大,最后划分阶段偷懒了。

解决:训练前自己检查一遍三个目录的实际图片数量,确认真实存在test目录并且有大约100张图片。如果发现test目录和val目录是同一个(软链接或重复拷贝),要么自己从val里随机抽出100张当测试集,要么接受只用val做评估,但要在日志里注明测试集和验证集有重叠,mAP数值会有虚高成分。

4.3 类别id从1开始而不是从0开始

现象:模型训练完成后,推理时发现预测的类别名整体往右偏移一位——比如真正的Cardamom被识别成了Cumin,Cumin被识别成了Neem。

原因:数据集的classes.txt里类别序号从1开始编号,但YOLO要求的类别id是从0开始。如果标注文件里写的是1-8,而data.yaml里names列表按0-7映射,那么类别名和id就错位了。

解决:训练前打开一个txt文件,看里面的class数字范围。如果最大数字等于类别总数而最小数字是1,说明标注从1开始,需要写个脚本把所有txt里每行第一个数字减1,或者干脆在data.yaml的names列表第一行加一个None占位让索引对齐。这个坑比较隐蔽,因为loss会正常收敛,不推理基本发现不了。

4.4 中草药图像背景复杂导致的漏标

现象:可视化抽检时发现,部分图片里的中草药在画面边缘、被遮挡或与背景颜色接近的位置没有被标注。

原因:中草药数据集很多是从素材网站爬的图,背景有纯白、木桌、草地等多种场景。标注人员面对复杂背景时容易漏掉被遮挡的目标,特别是叶片颜色和背景相近的Neem这类深色植物。

解决:训练前用第3章的批量可视化脚本把所有训练图过一遍,重点看那些小目标密集的图片。如果发现连续多张图都有漏标,可以考虑把标注工具(LabelImg或X-AnyLabeling)重新打开,手动补充漏标框。漏标对模型的负面影响比错标还大——错标的框至少让模型学到了一个位置,漏标则直接告诉模型“这个位置没有目标”,在推理时模型会倾向于略过相似位置。

4.5 图片尺寸不统一导致归一化坐标换算错误

现象:可视化时发现某些框明显偏移,框的中心点和目标实际位置不重合,且只出现在特定几张图上。

原因:数据集里混入了不同分辨率的图片,标注软件在导出时如果按统一尺寸归一化,而实际图片没有resize到那个尺寸,就会导致坐标错位。比如标注时把图片统一resize到640x640再归一化,但实际保存的是原图1920x1080,框的x_center是按640宽度算的,画到1080p图上自然偏移。

解决:可视化脚本里加一个图片宽高打印,抽检时对比不同尺寸图片的标注质量。如果发现特定尺寸的图片全部错位,写脚本把这些图片统一转成标注时的尺寸,或者重新生成标注文件。严格来说,YOLO格式的归一化坐标是自适应的,不会因为图片尺寸变化而失效,只有标注时用了错误基准尺寸才会出现这种问题。

5. 进阶用法:从跑通到跑好——锚框重聚类与训练参数调优

数据集能直接训练,但“能训练”和“训练得好”是两回事。这份中草药数据集的标注目标多为中等尺寸的叶片或果实个体,而YOLOv5/v8默认的锚框是基于COCO数据集聚类的,COCO的目标普遍偏大,直接迁移到中草药场景不是最优解。我推荐训练前先跑一次k-means锚框聚类,用数据集自身的框尺寸分布替换默认锚框。

import numpy as np from sklearn.cluster import KMeans def load_boxes(label_dir): boxes = [] for file in os.listdir(label_dir): with open(os.path.join(label_dir, file)) as f: for line in f: _, _, _, w, h = map(float, line.split()) boxes.append([w, h]) return np.array(boxes) boxes = load_boxes('datasets/labels/train') kmeans = KMeans(n_clusters=9, random_state=0).fit(boxes) anchors = kmeans.cluster_centers_.flatten() print('新锚框:', np.round(anchors, 3))

聚类结果出来后,把新锚框写进models/yolov5s.yaml或yolov8的yaml配置里,同时注意配合数据集的图片尺寸——如果训练时imgsz设为640,锚框值不需要额外缩放,因为YOLO内部会做归一化处理。

训练参数方面,我建议batch size根据显存来定,GTX 1080Ti级别用16,A100用32或更大。epochs设150-200足够,因为数据集规模不大,300轮以上容易过拟合。中草药这类目标是典型的纹理识别任务,模型不需要很大的感受野,所以优先用最小的模型yolov5s或yolov8n起步,跑通了再考虑升级到m或l。lr=0.01、momentum=0.937是YOLOv5的默认值,一般不用动,但weight_decay可以适当调到0.0005,防止在小数据集上过拟合。

训练完成后,除了看val集的mAP,我还有一个习惯:把测试集里每个类别的预测结果单独导出,按置信度排序,看低置信度的前十个样本长什么样。这些样本通常是遮挡严重、目标极小或背景高度相似的hard case,它们比mAP数字更能告诉你模型的真实边界在哪。这份数据集自带测试集,正好用来做这个分析。

数据增强方面,中草药叶片边缘纹理是辨识关键,所以颜色抖动(HSV)和轻微旋转是有益的,但上下翻转要慎用——药用植物特征和朝向无关的话没问题,但如果某些类别有方向性特征(比如花朵朝上),翻转反而会引入噪声。建议在hyp.yaml里把flipud设为0,fliplr保持0.5,hsv_h、hsv_s、hsv_v分别设为0.015、0.7、0.4。

说到最后,我自己每次拿到一份新数据集,都会强制走一遍同样的流程:完整性检查、类别分布统计、可视化抽检、锚框重聚类、小模型试跑。这套流程帮我筛掉了至少七八份看起来能训但实际有各种暗病的数据集。这份中草药数据集整体质量在线,核心坑位我都标注在上面了,按这个顺序过一遍,训练流程基本不会出大问题。希望帮到你。

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

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

Zapier、Coze、Dify、n8n 四方混战:企业 AI 工作流到底押注谁?

Zapier、Coze、Dify、n8n 四方混战:企业 AI 工作流到底押注谁? 【免费下载链接】n8n Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400 integrations. 项目地…

作者头像 李华
网站建设 2026/10/16 12:00:10

python类的私有属性和公共属性说明

前言 「Python 的私有属性」这个说法,本身就不太准确。官方教程里写得很干脆:在 Python 中,那种「除非在对象内部,否则无法访问」的私有实例变量是不存在的。 之所以大家还总把它挂在嘴边,是因为 Python 提供了两套约定…

作者头像 李华
网站建设 2026/10/14 16:40:50

上下文易失?用claude-mem给命令行AI外接一块记忆硬盘

我见过不少刚接触命令行 AI 的人,都有同一个错觉:以为跟模型聊过一次之后,它就多少记着点你。现实是,只要换一个终端窗口,模型对你的了解约等于零。这个断层曾经让我非常沮丧,直到我把 claude-mem 接进日常…

作者头像 李华
网站建设 2026/10/16 0:58:29

CSS - 边框颜色:border-color 的取值与样式设置

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕CSS这个话题展开,希望能为你带来一些启发或实…

作者头像 李华