简介:本资源为药品布洛芬目标检测数据集,面向从事药品识别、智能零售与医药分拣等方向的算法工程师、学生及科研人员,可用于训练和验证单类别目标检测模型。压缩包共1430个文件,包含476张jpg图片、476个VOC格式xml标注文件、476个YOLO格式txt标注文件及少量说明文件,整体约19.62MB,图片与标注一一对应,方便直接接入YOLO或Pascal VOC训练流程。标注采用labelImg完成,仅设buluofen一个类别,共657个矩形框,平均每张图约1.4个目标,适合小样本单类检测的快速实验与迁移学习验证。目前已有175人学习下载,可作为药品检测赛题或课程设计的基础数据,帮助读者省去采集与标注成本,快速搭建训练与评估管线。
1. 药品泡罩包装检测的起点:476张布洛芬数据集的真实定位
药品泡罩包装的视觉检测是个容易被低估的场景。铝塑板反光、药片排列紧密、包装边缘与背景对比度低,这些因素叠加在一起,让通用目标检测模型直接迁移过来时经常出现漏检。我最近拆了一份专门针对布洛芬药片的目标检测数据集,476张jpg图片,配套476个VOC格式xml和476个YOLO格式txt,标注类别只有一个:buluofen,总框数657。标注工具用的是labelImg,规则就是画矩形框,没有分割路径的txt文件,纯粹的目标检测任务。
这份数据集适合什么人?如果你正在做药品分拣、泡罩包装缺陷检测、或者医药自动化产线上的视觉定位,这个数据集能直接拿来跑通YOLO训练流程。它不是那种几万张的大规模数据集,但胜在类别单一、标注干净,适合快速验证模型结构和训练参数,也适合作为小样本场景下的基线实验材料。476张图片对应657个框,平均每张图1.38个目标,说明大部分图片里布洛芬药片数量不多,可能是单粒或双粒的特写拍摄,这对检测小目标和密集排列的能力要求反而更高。
2. VOC与YOLO双格式拆解:目录结构、字段含义与转换逻辑
2.1 VOC格式的xml里到底存了什么
Pascal VOC格式的标注文件是xml结构,每个xml对应一张jpg图片。打开一个典型的xml,你会看到几个关键节点:filename记录图片文件名,size里包含width、height、depth三个值,object节点下是标注信息,包括name、pose、truncated、difficult、bndbox。bndbox里有xmin、ymin、xmax、ymax四个坐标值,这是矩形框的左上角和右下角像素坐标。
对于这份布洛芬数据集,name字段的值固定是buluofen,没有其他类别。pose、truncated、difficult这三个字段在标注时通常保持默认值,labelImg默认pose为Unspecified,truncated和difficult为0。实际训练时YOLO格式并不读取这些字段,但如果你要做数据清洗或筛选困难样本,difficult字段可以作为过滤依据。
xml文件的数量和jpg完全对应,476个xml对应476张图,没有遗漏。这意味着你不需要做额外的文件名匹配检查,直接按文件名前缀就能配对。
2.2 YOLO格式的txt坐标归一化规则
YOLO格式的txt文件每行代表一个目标,格式是:class_id x_center y_center width height。这五个值用空格分隔,其中x_center、y_center、width、height都是相对于图片宽高的归一化值,范围在0到1之间。class_id从0开始编号,这份数据集只有一个类别buluofen,所以class_id恒为0。
归一化的计算方式是:x_center = (xmin + xmax) / 2 / image_width,y_center = (ymin + ymax) / 2 / image_height,width = (xmax - xmin) / image_width,height = (ymax - ymin) / image_height。这里有个容易翻车的点:如果你的图片尺寸在标注之后被修改过,xml里的size和实际图片尺寸不一致,归一化就会出错。这份数据集的xml里size字段和实际jpg尺寸应该是一致的,但保险起见,训练前还是用脚本校验一遍。
2.3 用Python做格式校验与可视化检查
拿到数据集后不要急着丢进训练脚本,先跑一遍校验。下面这段代码检查jpg、xml、txt三者是否一一对应,同时验证YOLO坐标是否在合法范围内。
import os import xml.etree.ElementTree as ET from PIL import Image img_dir = "images" xml_dir = "annotations_xml" txt_dir = "labels_yolo" img_files = set(os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".jpg")) xml_files = set(os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.endswith(".xml")) txt_files = set(os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(".txt")) # 检查三者是否完全一致 print("jpg-xml差集:", img_files - xml_files) print("jpg-txt差集:", img_files - txt_files) for name in list(img_files)[:5]: img_path = os.path.join(img_dir, name + ".jpg") txt_path = os.path.join(txt_dir, name + ".txt") w, h = Image.open(img_path).size with open(txt_path) as f: for line in f: cls, xc, yc, bw, bh = map(float, line.strip().split()) # 检查归一化值是否越界 assert 0 <= xc <= 1 and 0 <= yc <= 1, f"{name} center越界" assert 0 < bw <= 1 and 0 < bh <= 1, f"{name} 宽高越界" # 对比xml中的size和实际图片尺寸 tree = ET.parse(os.path.join(xml_dir, name + ".xml")) root = tree.getroot() xml_w = int(root.find("size/width").text) xml_h = int(root.find("size/height").text) if xml_w != w or xml_h != h: print(f"{name} 尺寸不一致: xml({xml_w}x{xml_h}) vs 实际({w}x{h})")这段代码做了三件事:第一,用集合差集找出缺失的配对文件;第二,逐行读取YOLO txt,断言归一化坐标在0到1之间;第三,对比xml里的size和PIL读出的实际图片尺寸。如果尺寸不一致,说明标注后图片被裁剪或缩放,需要重新计算归一化坐标。我一般会在训练前强制跑一遍这个校验,避免训练到一半发现loss不降反升。
3. 从零跑通YOLO训练:环境配置、数据yaml与参数调优
3.1 环境搭建与版本选择
YOLO系列版本很多,这份数据集规模不大,用YOLOv8n或YOLOv8s就够。环境配置上,Python 3.8到3.10都行,PyTorch选1.13以上,CUDA版本根据你的显卡驱动来。如果你用Anaconda,创建一个独立环境避免和系统包冲突。
conda create -n yolo_buluofen python=3.9 conda activate yolo_buluofen pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118ultralytics包会自动安装YOLOv8所需的依赖。安装完成后用yolo checks命令验证环境,它会输出PyTorch版本、CUDA是否可用、以及当前YOLO版本。如果CUDA不可用,训练会回退到CPU,速度会慢很多,476张图在CPU上跑100轮可能要几个小时。
3.2 数据集目录组织与yaml配置
YOLO训练要求特定的目录结构。我一般这样组织:
buluofen_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml把476张jpg按8:2划分,380张训练,96张验证。对应的txt文件放到labels下同名子目录。划分时注意随机种子固定,保证每次划分一致。然后写data.yaml:
path: /absolute/path/to/buluofen_dataset train: images/train val: images/val nc: 1 names: ["buluofen"]nc是类别数,names是类别名称列表。这里只有一个类别,所以nc=1。path写绝对路径,避免相对路径解析出错。如果你的数据集里图片和标签在同一目录下,YOLO也能自动匹配,但分开存放更清晰。
3.3 训练命令与关键参数含义
启动训练的命令很简单:
yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 lr0=0.01逐个参数说:model=yolov8n.pt表示从预训练权重开始微调,这对小数据集很重要,能显著加快收敛。epochs=100是训练轮数,476张图跑100轮大概十几分钟到半小时,取决于显卡。imgsz=640是输入分辨率,如果你的图片本身分辨率远大于640,可以适当调大,但显存占用也会增加。batch=16是批次大小,显存不够就降到8或4。lr0=0.01是初始学习率,YOLOv8默认是0.01,小数据集可以降到0.001避免过拟合。
训练过程中关注几个指标:box_loss和cls_loss应该持续下降,mAP50在验证集上逐步上升。如果box_loss震荡不降,可能是学习率太大或标注框有问题。如果mAP50很低但loss在降,可能是验证集划分不合理或类别不平衡。
3.4 推理测试与置信度门限调整
训练完成后用best.pt做推理:
yolo detect predict model=runs/detect/train/weights/best.pt source=test_images save=True conf=0.25conf=0.25是置信度门限,低于这个值的检测框会被过滤。对于药品检测场景,漏检比误检更严重,所以可以适当降低门限到0.15或0.2,宁可多检几个假阳性也不要漏掉真药片。但门限太低会引入大量误检,需要根据实际业务做权衡。我一般会跑几组不同conf值,对比precision和recall曲线,选一个F1分数最高的点。
4. 避坑与排查:标注、格式、训练中的五个血泪教训
4.1 现象:训练loss正常但mAP始终为0
原因:YOLO格式的class_id从0开始,但有些转换脚本从1开始编号。这份数据集只有一个类别,如果txt里写的是1而不是0,YOLO会认为类别索引越界,所有标注被忽略。
解决:打开任意一个txt文件,确认第一列是0。如果是1,用脚本批量减1。另外检查data.yaml里的nc是否和实际类别数一致,nc=1时class_id只能是0。
4.2 现象:图片尺寸和xml里的size不一致导致框偏移
原因:标注完成后图片被裁剪或缩放,但xml里的size字段没有同步更新。YOLO格式的归一化坐标是基于xml里的size计算的,如果实际图片尺寸变了,框的位置就会偏移。
解决:用2.3节的校验脚本检查所有图片。如果发现不一致,要么恢复原始图片尺寸,要么用实际图片尺寸重新计算归一化坐标。我一般会在标注前统一图片尺寸,避免后期返工。
4.3 现象:验证集mAP波动大,每次训练结果差异明显
原因:476张图的数据集规模偏小,如果验证集划分时没有固定随机种子,每次训练用的验证集不同,mAP自然波动。另外小数据集对batch size和学习率敏感,参数稍微一变结果就差很多。
解决:固定随机种子划分数据集,训练时设置deterministic=True。如果波动仍然大,可以用交叉验证,把476张图分成5折,每折轮流做验证集,取平均mAP作为最终指标。
4.4 现象:推理时检测框重叠严重,同一个药片被检出多次
原因:NMS的iou阈值设置过高,导致重叠框没有被抑制。YOLO默认iou=0.7,对于密集排列的药片,这个值可能偏大。
解决:推理时降低iou阈值到0.5或0.45,让NMS更激进地合并重叠框。命令里加iou=0.5即可。但iou太低也会导致相邻药片被误合并,需要根据实际图片中药片的间距来调。
4.5 现象:训练到后期loss突然变成NaN
原因:学习率太大或数据中有异常标注框。比如某个框的width或height为0,归一化后出现除零错误。或者某张图片的txt文件为空但图片存在,YOLO读取时可能出错。
解决:先用校验脚本检查所有txt,确保没有空文件、没有宽高为0的框。然后把学习率降到0.001,加梯度裁剪clip_grad=10.0。如果还有NaN,检查图片是否有损坏,用PIL打开所有图片验证完整性。
5. 小样本下的进阶技巧:数据增强、模型微调与部署前验证
476张图在目标检测里属于小样本,直接训练容易过拟合。我一般会开YOLO内置的数据增强,包括mosaic、mixup、随机翻转、HSV抖动。mosaic把四张图拼成一张,能显著增加背景多样性。mixup把两张图按透明度叠加,对药品这种形状固定的目标效果不错。但要注意,如果药片颜色是判断类别的关键特征,HSV抖动幅度不要太大,否则颜色失真会导致误检。
模型微调方面,可以冻结backbone的前几层,只训练head部分。YOLOv8里用freeze=10冻结前10层,这样训练速度更快,也能防止小数据集把预训练特征带偏。等head收敛后再解冻全部层做微调,学习率降到0.0001。
部署前验证有个容易被忽略的步骤:用实际产线相机拍几张图,不标注,直接跑推理,看检测框是否稳定。实验室图片和产线图片在光照、角度、背景上差异很大,这一步能提前暴露域偏移问题。如果产线图片检测效果差,可以用少量产线图片做微调,或者调整推理时的图像预处理参数,比如对比度增强、直方图均衡化。
我自己的习惯是,每次拿到新数据集,先跑一遍2.3节的校验脚本,再跑一遍5张图的推理可视化,确认标注框和检测框能对上,才正式启动训练。这个流程帮我省过好几次返工的时间。希望这份拆解能帮到你,少走一些我踩过的弯路。
本文还有配套的精品资源,点击获取