☰
药品布洛芬检测数据集:476张VOC+YOLO格式实战YOLOv8训练与避坑指南
2026/10/5 7:16:51 网站建设 项目流程

简介:本资源为药品布洛芬目标检测数据集,面向从事药品识别、智能零售与医药分拣等方向的算法工程师、学生及研究者,可用于训练与验证单类别目标检测模型。包内共1430个文件,包含476张jpg图片、476个VOC格式xml标注文件、476个YOLO格式txt标注文件及少量说明文件,压缩包约19.62MB,VOC与YOLO双格式并存,便于直接接入YOLO系列或Faster R-CNN等主流框架。标注类别仅buluofen一类,共657个矩形框,采用labelImg工具绘制,标注规范统一。目前已有175人学习下载。读者可据此快速构建药品检测训练集,省去采集与标注成本,并借助双格式标注灵活切换训练流程,适合作为课程设计、毕业设计或算法对比实验的数据基础。

1. 药品布洛芬检测数据集:476张VOC+YOLO格式到底能跑出什么

药房里最容易被拿错的一类药,就是那些铝塑泡罩包装长得几乎一模一样的小药片。布洛芬作为解热镇痛类的常用药,单盒外观和感康、阿莫西林、对乙酰氨基酚摆在一起,肉眼扫过去差别极小。如果你正在做一个药品分拣、药房盘点或者智能药柜的项目,第一个卡住你的往往不是模型结构,而是「我上哪找一批标注好的布洛芬图片」。这个476张、VOC+YOLO双格式的目标检测数据集,解决的就是这个冷启动问题——它让你在半天内跑通一条从数据到检测框的完整链路,而不是花两周去拍图、标框、转格式。适合谁?适合刚接触目标检测、想拿一个真实小样本数据集练手的人,也适合已经在做药品视觉识别、需要一个可快速验证的基线数据的工程师。476张不算多,但足够你把YOLO的训练流程、格式转换、过拟合判断这几件事全部走一遍。

2. 先搞清楚VOC和YOLO两种格式差在哪:别拿到压缩包就急着训练

2.1 VOC的XML结构和YOLO的TXT结构,字段对应关系

VOC格式的核心是每张图配一个同名的XML文件,标注信息全在里面。YOLO格式则是每张图配一个同名的TXT文件,一行一个目标。这两种格式不是简单的「换个后缀」,坐标体系完全不同:VOC用的是绝对像素坐标,YOLO用的是归一化后的中心点坐标加宽高。你拿到数据集后第一件事不是解压完就丢给训练脚本,而是先确认两种格式的目录结构对不对。

VOC的典型目录长这样:

VOC2007/ ├── Annotations/ # 存放XML标注文件 │ ├── 000001.xml │ └── ... ├── JPEGImages/ # 存放原始图片 │ ├── 000001.jpg │ └── ... ├── ImageSets/ │ └── Main/ # 存放训练/验证集划分文件 │ ├── train.txt │ ├── val.txt │ └── trainval.txt └── SegmentationClass/ # 分割任务用,检测任务可忽略

YOLO的典型目录长这样:

dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 训练集标注TXT │ └── val/ # 验证集标注TXT └── data.yaml # 数据集配置文件

一个VOC的XML文件内容大致是:

<annotation> <folder>JPEGImages</folder> <filename>000001.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>ibuprofen</name> <!-- 类别名 --> <bndbox> <xmin>120</xmin> <!-- 左上角x,绝对像素 --> <ymin>85</ymin> <!-- 左上角y,绝对像素 --> <xmax>310</xmax> <!-- 右下角x,绝对像素 --> <ymax>260</ymax> <!-- 右下角y,绝对像素 --> </bndbox> </object> </annotation>

对应的YOLO TXT文件内容是一行:

0 0.3359 0.3594 0.2969 0.3646

这五个数的含义分别是:类别索引、中心点x归一化值、中心点y归一化值、框宽归一化值、框高归一化值。归一化的分母就是图片的宽和高。很多人第一次转格式时框全偏了,就是因为把绝对坐标直接除以了错误的尺寸,或者忘了VOC的xmax/ymax是包含边界的,而YOLO的宽高是算出来的差值。

2.2 476张图为什么还要分VOC和YOLO两份:选型理由

你可能会问,既然YOLO训练只用TXT,为什么数据集还要附带VOC格式?原因有三个。第一,VOC是很多标注工具的默认导出格式,LabelImg、Labelme这些工具原生输出就是XML,保留VOC等于保留了「原始标注证据」,万一YOLO的TXT转错了,你还能从XML重新转一遍。第二,有些框架和评估脚本仍然吃VOC格式,比如早期的Faster R-CNN实现、部分比赛提交格式。第三,VOC的XML里除了框还有图片尺寸、深度、文件夹路径这些元信息,排查问题时比光秃秃的TXT有用得多。

对于476张这个量级,我的建议是:训练用YOLO格式,但VOC那份别删。你后面做数据增强、做错例分析、甚至想换到MMDetection框架时,VOC的XML能省掉你重新标注的功夫。这不是冗余,是后悔药。

2.3 用脚本把VOC转成YOLO:转换逻辑与边界处理

如果你拿到的数据集里VOC和YOLO是分开的两个文件夹,那直接用YOLO那份就行。但如果你只有VOC,或者想验证两份是否一致,就需要自己写转换脚本。下面这个Python脚本是我常用的版本,处理了类别映射、坐标归一化和边界裁剪:

import xml.etree.ElementTree as ET import os import glob # 类别映射:根据你的数据集实际类别修改 CLASSES = ['ibuprofen'] def voc_to_yolo(xml_path, output_dir, img_w, img_h): """ 将单个VOC XML转为YOLO TXT xml_path: XML文件路径 output_dir: TXT输出目录 img_w, img_h: 图片宽高,用于归一化 """ tree = ET.parse(xml_path) root = tree.getroot() # 用文件名(不含后缀)作为TXT文件名 base_name = os.path.splitext(os.path.basename(xml_path))[0] txt_path = os.path.join(output_dir, base_name + '.txt') lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text if cls_name not in CLASSES: continue # 跳过不在类别表里的目标 cls_id = CLASSES.index(cls_name) bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 边界裁剪:防止标注超出图片范围 xmin = max(0, min(xmin, img_w)) xmax = max(0, min(xmax, img_w)) ymin = max(0, min(ymin, img_h)) ymax = max(0, min(ymax, img_h)) # 转为中心点+宽高的归一化格式 cx = (xmin + xmax) / 2.0 / img_w cy = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") with open(txt_path, 'w') as f: f.write('\n'.join(lines)) # 批量转换示例 xml_dir = 'VOC2007/Annotations' out_dir = 'labels' os.makedirs(out_dir, exist_ok=True) # 注意:这里需要你从图片或XML的size节点读取宽高 # 如果XML里有size节点,可以直接从XML读,不用额外传参 for xml_file in glob.glob(os.path.join(xml_dir, '*.xml')): tree = ET.parse(xml_file) size = tree.getroot().find('size') w = int(size.find('width').text) h = int(size.find('height').text) voc_to_yolo(xml_file, out_dir, w, h)

这段代码的关键点有三个。第一,CLASSES列表必须和你的数据集类别严格对应,顺序错了类别索引就全错。第二,边界裁剪那四行不能省,药品数据集的标注有时候框会压到图片边缘甚至超出几个像素,不裁剪的话归一化后会出现负数或大于1的值,训练时直接报错。第三,归一化保留6位小数足够,YOLO训练时对精度不敏感,但格式必须统一。

参数方面,img_w和img_h优先从XML的size节点读,这样最准。如果XML里没有size节点(有些标注工具会省略),你就得用OpenCV或PIL去读图片实际尺寸,千万别用固定值。

3. 用YOLOv8跑通476张药品检测:从data.yaml到第一次推理

3.1 环境配置与data.yaml的四个必填字段

环境这块我不绕弯子,直接给一套能跑通的组合:Python 3.9以上、PyTorch 2.0以上、ultralytics 8.x。安装命令就一行:

pip install ultralytics

装完之后yolo命令就能用了。接下来是数据集配置文件data.yaml,这是YOLO训练最容易被忽略但最不能错的文件。它长这样:

path: /home/user/ibuprofen_dataset # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 1 # 类别数量 names: ['ibuprofen'] # 类别名称列表

四个字段里,path是根目录,train和val是相对于path的路径,nc和names必须一一对应。我见过太多人把nc写成类别名数量但names里多写了一个空格,结果训练时类别索引越界。还有一个坑:train和val指向的是图片目录,不是标签目录,YOLO会自动去找同级的labels目录。所以你的目录结构必须是images/train和labels/train并列,不能把标签塞到别的地方。

3.2 训练命令与关键参数:epochs、imgsz、batch怎么定

476张图属于小样本,训练策略和大数据集不一样。下面是我在这个量级上常用的命令:

yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=30 \ augment=True \ project=runs/ibuprofen \ name=exp1

逐个说参数。model=yolov8n.pt选的是nano版本,476张图用大模型纯属浪费,nano足够跑出一个可用的基线。epochs=150是因为小样本需要多轮才能收敛,但别设500,过拟合会来得很快。imgsz=640是YOLO的默认输入尺寸,药品图片如果分辨率不高,可以降到416或320,能明显提速。batch=16取决于你的显存,8G显存跑640尺寸的nano模型,16基本是上限。lr0=0.01是初始学习率,小样本可以适当降到0.005,收敛更稳。patience=30是早停耐心值,30轮验证集指标不提升就停,省时间。augment=True开启内置数据增强,476张图必须开,否则模型见到的样本太单一。

训练过程中重点看两个指标:mAP50和mAP50-95。mAP50到0.8以上说明框基本找准了,mAP50-95到0.5以上说明框的精度也还行。如果mAP50很高但mAP50-95很低,说明框的位置不够准,可能是标注质量有问题。

3.3 推理验证:用训练好的权重跑单张图和批量图

训练完权重默认存在runs/ibuprofen/exp1/weights/best.pt。跑单张推理:

yolo detect predict \ model=runs/ibuprofen/exp1/weights/best.pt \ source=test_images/ \ conf=0.25 \ save=True

conf=0.25是置信度阈值,低于这个值的框不显示。药品检测场景下,我一般会把conf调到0.3到0.4,因为药盒之间的误检比漏检更麻烦——你把一个不是布洛芬的盒子框成布洛芬,分拣线就出错了。save=True会把带框的图片存到runs/detect/predict目录下,方便你肉眼检查。

批量推理就是把source指向一个文件夹,YOLO会遍历里面所有图片。如果你要集成到自己的Python代码里,用下面这段:

from ultralytics import YOLO model = YOLO('runs/ibuprofen/exp1/weights/best.pt') results = model('test_images/', conf=0.3, save=True) # 遍历结果,打印每个框的类别和坐标 for r in results: boxes = r.boxes for box in boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) xyxy = box.xyxy[0].tolist() # 左上右下坐标 print(f"类别: {model.names[cls_id]}, 置信度: {conf:.2f}, 坐标: {xyxy}")

这段代码里box.xyxy返回的是绝对像素坐标,和VOC的格式一致,方便你后续做裁剪或计数。model.names是类别索引到名称的映射,直接从模型里读,不用自己维护。

4. 476张小样本训练的避坑清单:这五个坑我替你踩过了

4.1 坑一:训练loss正常下降但mAP一直是0

现象:训练日志里box_loss和cls_loss都在降,但验证集的mAP50始终是0,模型好像什么都没学到。

原因:九成是data.yaml里的names和标注TXT里的类别索引对不上。比如你的TXT里写的是0,但names列表里第一个类别不是布洛芬,或者nc写成了2但实际只有1类。YOLO不会报错,它会默默地把所有预测都归到错误的类别上,导致mAP计算时匹配不上。

解决:打开一个标注TXT,看第一个数字是几,然后确认data.yaml里names列表对应索引位置的类别名是不是布洛芬。再检查nc是否等于len(names)。改完重新训练,一般前10个epoch就能看到mAP往上走。

4.2 坑二:验证集mAP很高但实际推理框全偏了

现象:训练完看验证集指标,mAP50有0.9,感觉不错。但拿几张没参与训练的图片一跑,框的位置明显偏移,有的框甚至框到了背景上。

原因:476张图如果划分验证集时用了随机划分,而图片之间高度相似(比如同一个药盒的不同角度),验证集和训练集分布几乎一样,指标虚高。另外,如果标注时框画得太松,模型学到的就是松框,推理时也会偏。

解决:划分验证集时按「不同拍摄批次」或「不同背景」来分,别用纯随机。如果数据量实在小,至少保证验证集里有几张和训练集明显不同的图。标注质量方面,用LabelImg重新过一遍框,把明显偏大的框收紧。

4.3 坑三:batch设太大导致显存溢出但报错信息看不懂

现象:训练启动几秒后报CUDA out of memory,但你的显存明明还有空余。

原因:YOLO训练时的显存占用不是线性的,batch和imgsz是乘数关系。640尺寸下batch=16可能刚好卡在8G显存的边缘,加上数据加载的缓存,就爆了。另外,如果开了augment=True,数据增强也会占额外显存。

解决:先把batch降到8,如果还爆就降到4。或者把imgsz从640降到416,显存占用大约能降一半。还有一个技巧是设workers=2,减少数据加载进程数,也能省一点显存。别硬撑,小样本训练batch小一点反而梯度更稳。

4.4 坑四:VOC转YOLO后框全部挤在左上角

现象:转换完TXT,用可视化工具一看,所有框都缩在图片左上角一小块区域。

原因:归一化时除错了分母。VOC的坐标是绝对像素,YOLO需要除以图片的宽和高。如果你把x坐标除以了高、y坐标除以了宽,或者用了固定的640和480去归一化但实际图片尺寸不是这个,框就会全偏。

解决:归一化前先打印几张图片的实际尺寸,确认和XML里size节点一致。然后用img_w除x相关坐标,img_h除y相关坐标,别搞反。转换完随机抽5张图,用OpenCV把YOLO框画回图片上,肉眼确认位置对不对。

4.5 坑五:训练完模型只认识训练集里的那几种摆放角度

现象:训练集里布洛芬都是正面朝上拍的,推理时遇到侧放或倒放的药盒,模型完全检测不到。

原因:476张图如果拍摄角度单一,模型学到的特征就是「正面朝上的布洛芬」,没有见过其他姿态。这不是模型的问题,是数据分布的问题。

解决:训练时开启YOLO内置的旋转增强。在训练命令里加degrees=10.0,让图片在正负10度内随机旋转。如果数据量允许,手动补拍一些侧放、倒放、部分遮挡的图片。药品检测场景下,遮挡是常态,药盒叠在一起时只露出一角,模型也得能认出来。

5. 把476张用到极致:小样本药品检测的进阶技巧

476张图训练一个能用的模型不难,难的是让它稳定。我自己的习惯是,训练完第一版之后不急着调参,先做一件事:把验证集里所有预测错的图挑出来,一张一张看。错例分析比盲目调epochs有用十倍。下面这张表是我常用的错例分类框架,你可以直接套:

错例类型典型表现优先处理方式
漏检图里有布洛芬但没框出来检查标注是否漏标,补标后重训
误检把背景或其他药盒框成布洛芬增加负样本,调高conf阈值
框不准框到了但位置偏大或偏小重新收紧标注框,检查归一化
类别混淆框对了但类别标错确认names列表顺序,检查TXT索引

错例分析做完,如果漏检和误检都集中在某几种背景上,那就针对性地补拍那几种背景的图片。476张不够就补到600张,补图比调参见效快。

另一个技巧是冻结 backbone 做微调。如果你之前用其他药品数据集训练过YOLO,可以把backbone冻结,只训练检测头。命令里加freeze=10,表示冻结前10层。这样476张图能在更少的epoch里收敛,而且不容易过拟合。我一般会在数据量低于500张时优先试这个策略。

还有一个容易被忽略的点:推理时的输入尺寸。训练用640,推理也可以用640,但如果你的实际部署环境是边缘设备,推理尺寸可能要降到320。这时候别直接拿640训练的模型去跑320的推理,精度会掉。正确做法是训练时就把imgsz设成320,让模型在目标尺寸上收敛。我吃过这个亏,训练时640,部署时320,mAP直接掉了15个点,血泪经验。

最后说一个验证方法:把数据集里最难的10张图单独拎出来,不参与训练,作为「测试集」。每次调完参,先跑这10张,看框得怎么样。这10张图的表现比验证集指标更能反映真实水平。如果这10张能框准,模型基本就稳了。

我自己的习惯是,拿到任何一个小样本数据集,先跑通基线,再做错例分析,最后才动参数。476张布洛芬图片不多,但足够你把目标检测的完整流程走一遍。别指望一次训练就完美,迭代三轮是常态。希望帮到你。

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

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

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

立即咨询