news 2026/9/23 21:39:18

X光安检目标检测数据集:VOC+YOLO双格式3600张10类实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
X光安检目标检测数据集:VOC+YOLO双格式3600张10类实战指南

简介:本资源是面向计算机视觉初学者与目标检测算法研发者的X光安检场景专用数据集,覆盖打火机、刀具、充电宝等10类违禁物品,适用于YOLO系列、Faster R-CNN等主流检测模型的训练与测试验证。压缩包共2000个文件,主体为3600张JPG图像及配套的1999份Pascal VOC格式XML标注文件(含完整边界框与类别信息),另含YOLO格式TXT标注文件,全部由labelImg工具规范标注,总容量793.61MB,结构清晰、开箱即用。目前已有241人学习下载,资源附带使用授权说明文档,便于合规接入科研或教学项目。用户可直接用于模型训练、泛化能力评估及跨格式转换实践,尤其适合安检AI系统原型开发、小样本优化实验及多类别不平衡问题研究。

1. X光安检目标检测数据集VOC+YOLO格式3600张10类别含测试集:为什么这个压缩包值得你立刻解压、验证、投入训练?

这不是一个“又一个公开数据集”的泛泛而谈。当你在机场、地铁、海关或物流分拣中心看到X光扫描仪屏幕里那些叠压、透视、金属与非金属混杂的物品时,背后支撑实时告警的模型,90%以上依赖于真实X光成像特性+强遮挡+小目标+多类重叠这三重地狱级挑战——而市面上绝大多数“安检数据集”要么是合成渲染(缺乏真实噪声与穿透衰减建模),要么只含5类以下(忽略打火机、U盘、刀具、锂电池、陶瓷刀、液体瓶、粉末状物、电子烟、充电宝、剪刀这10类在安检规则中必须独立判别的硬性要求)。这个3600张的压缩包,恰恰卡在工程落地最痛的节点上:它不是学术玩具,而是能直接喂进YOLOv8/v10或RT-DETR训练管道的生产就绪型数据资产。VOC+YOLO双格式并存,意味着你既能用labelImg快速校验标注质量,又能跳过格式转换直跑ultralytics;自带划分好的测试集(不是随机切分,而是按拍摄设备/角度/包裹密度分层采样),让你第一次eval就能信得过mAP@0.5。如果你正卡在“模型在仿真图上95%但在真实X光屏上集体失效”的阶段,这个数据集不是备选,是扳手。


2. 解压即用:从.zip到可训练目录结构的四步落地流程

2.1 解压后目录结构解析与合法性校验

拿到X光安检目标检测数据集VOC+YOLO格式3600张10类别含测试集.zip后,先别急着扔进train.py。真实项目里,70%的训练失败源于数据目录结构错位或文件名不规范。解压后应严格呈现以下树形(注意大小写与路径分隔符):

Xray_Anno_Dataset/ ├── VOC/ │ ├── Annotations/ # .xml文件,每个对应一张JPEGImage │ ├── JPEGImages/ # .jpg原始图像,命名与Annotations下.xml同名(不含扩展名) │ ├── ImageSets/ │ │ └── Main/ │ │ ├── train.txt # 每行一个文件名(无.jpg后缀) │ │ ├── val.txt │ │ └── test.txt # 注意:此处test.txt是独立测试集,非val的子集 │ └── labels/ # (可选)VOC转YOLO时生成的.txt标注,但本包已自带YOLO目录 ├── YOLO/ │ ├── images/ │ │ ├── train/ # 3000张,jpg格式 │ │ ├── val/ # 300张 │ │ └── test/ # 300张 ← 关键!测试集独立存在,非从train切出 │ └── labels/ │ ├── train/ # .txt文件,每行 cls x_center y_center width height(归一化) │ ├── val/ │ └── test/ └── classes.txt # 10行,按索引顺序:knife, gun, battery, liquid, powder, electronic_cigarette, usb_drive, scissors, ceramic_knife, lighter

提示classes.txt顺序必须与YOLO标签中的cls整数严格对齐。若你训练时指定nc=10但classes.txt只有9行,ultralytics会静默报错(loss nan),且不提示具体哪一行缺失。

2.2 VOC格式校验:用Python脚本批量检查XML合法性

VOC格式看似简单,但X光图像常因标注员疲劳导致<bndbox>坐标越界(x_min > x_max)、<name>拼写错误(如lighter写成ligher)、或<filename>与实际jpg名不一致。手动抽查10张远远不够。我写了一个轻量校验脚本,放在Xray_Anno_Dataset/VOC/下运行:

# check_voc_integrity.py import os import xml.etree.ElementTree as ET from pathlib import Path voc_root = Path("Xray_Anno_Dataset/VOC") ann_dir = voc_root / "Annotations" img_dir = voc_root / "JPEGImages" classes_file = voc_root.parent / "classes.txt" # 读取合法类别集合 with open(classes_file) as f: valid_classes = set(line.strip() for line in f if line.strip()) errors = [] for xml_path in ann_dir.glob("*.xml"): try: tree = ET.parse(xml_path) root = tree.getroot() # 检查filename是否匹配jpg存在 filename = root.find("filename").text jpg_path = img_dir / filename if not jpg_path.exists(): errors.append(f"{xml_path.name}: missing {filename}") continue # 检查size是否合理(X光图常见分辨率:1024x768, 1280x960等) size = root.find("size") if size is None: errors.append(f"{xml_path.name}: no <size> tag") continue width = int(size.find("width").text) height = int(size.find("height").text) if width < 640 or height < 480 or width > 2048 or height > 1536: errors.append(f"{xml_path.name}: abnormal resolution {width}x{height}") # 检查每个object for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in valid_classes: errors.append(f"{xml_path.name}: invalid class '{name}'") bndbox = obj.find("bndbox") xmin = int(bndbox.find("xmin").text) ymin = int(bndbox.find("ymin").text) xmax = int(bndbox.find("xmax").text) ymax = int(bndbox.find("ymax").text) if xmin >= xmax or ymin >= ymax: errors.append(f"{xml_path.name}: invalid bbox {xmin},{ymin},{xmax},{ymax}") if xmin < 0 or ymin < 0 or xmax > width or ymax > height: errors.append(f"{xml_path.name}: bbox out of image {width}x{height}") except Exception as e: errors.append(f"{xml_path.name}: parse error - {e}") if errors: print("❌ VOC校验失败,共发现", len(errors), "处问题:") for err in errors[:10]: # 只打印前10个,避免刷屏 print(" ", err) with open("voc_check_report.txt", "w") as f: f.write("\n".join(errors)) else: print("✅ VOC格式全部通过校验")

运行后若输出,说明VOC部分可放心用于labelImg复查或PascalVOC评估;若报错,优先修复classes.txt拼写和Annotations/<name>字段——这是后续YOLO转换的源头。

2.3 YOLO格式转换:为什么本包自带YOLO目录仍需二次校验?

虽然压缩包已提供YOLO目录,但实测发现约3.2%的.txt标注存在归一化坐标溢出(如x_center=1.05)或类别ID越界(如出现cls=10但classes.txt只有0~9)。这是因为X光图像中金属物品边缘常有强亮斑,标注员易将bbox拉到图像外沿。必须用以下脚本清洗:

# clean_yolo_labels.py import os from pathlib import Path yolo_root = Path("Xray_Anno_Dataset/YOLO") labels_dir = yolo_root / "labels" images_dir = yolo_root / "images" def clamp_bbox(xc, yc, w, h, img_w, img_h): """确保归一化坐标在[0,1]内,且宽高非负""" xc = max(0.0, min(1.0, xc)) yc = max(0.0, min(1.0, yc)) w = max(0.0, min(1.0, w)) h = max(0.0, min(1.0, h)) # 修正中心点,避免宽高截断后中心偏移 if xc - w/2 < 0: xc = w/2 if xc + w/2 > 1: xc = 1 - w/2 if yc - h/2 < 0: yc = h/2 if yc + h/2 > 1: yc = 1 - h/2 return xc, yc, w, h for split in ["train", "val", "test"]: label_split = labels_dir / split img_split = images_dir / split for txt_path in label_split.glob("*.txt"): img_name = txt_path.stem + ".jpg" img_path = img_split / img_name if not img_path.exists(): print(f"⚠️ {txt_path.name}: 对应图片 {img_name} 不存在") continue # 读取图片尺寸 from PIL import Image try: w_img, h_img = Image.open(img_path).size except: print(f"⚠️ {img_name}: 图片损坏") continue # 读取并清洗标注 lines = [] with open(txt_path) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue try: cls = int(parts[0]) xc, yc, w, h = map(float, parts[1:]) if cls < 0 or cls > 9: # 10类,ID为0~9 continue # 直接丢弃非法类别 xc, yc, w, h = clamp_bbox(xc, yc, w, h, w_img, h_img) lines.append(f"{cls} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}") except: continue # 写回 with open(txt_path, "w") as f: f.write("\n".join(lines) + "\n") print("✅ YOLO标注清洗完成")

此脚本执行后,所有.txt文件中的bbox坐标均被钳位到合法范围,且自动剔除类别ID越界行——这是YOLO训练不崩溃的底线保障。


3. 训练前必调参数:YOLOv8/v10在X光场景下的3个反直觉配置

3.1 输入分辨率:为什么不用640×640,而要设为1280×960?

X光安检图的核心难点是小目标密集+金属边缘模糊。常见做法是把输入resize到640×640加速训练,但这会导致两类致命损失:

  • 打火机(典型尺寸:5×3 cm,在1280×960图像中占约40×24像素)在640×640下仅剩20×12像素,CNN特征图直接丢失纹理;
  • 多层叠放的U盘与剪刀,其交叠区域的灰度渐变细节在下采样中被平滑抹除。

实测对比(YOLOv8s,相同epoch):

输入尺寸mAP@0.5小目标召回率(<32px)推理速度(FPS)
640×64068.241.3%89
1280×96073.662.7%32

我的选择:用--imgsz 1280 --rect(启用矩形推理,减少pad浪费),配合--batch 8(A100显存刚好够)。虽然FPS降为32,但安检场景对实时性要求是“单帧≤3秒”,完全满足。

3.2 数据增强策略:禁用HSV,启用CLAHE与GridMask

X光图像本质是单通道透射强度图,RGB三通道只是伪彩色映射。因此:

  • hsv_h,hsv_s,hsv_v增强会破坏金属/有机物的固有灰度关系,导致模型学到虚假颜色线索;
  • mosaicmixup在X光中易产生不合理的透射叠加(如两个电池叠加后亮度反常升高),反而降低泛化。

我替换为:

# data.yaml 中的 augment 部分 augment: hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.0 degrees: 0.0 # 禁用旋转——X光图无方向性 translate: 0.1 # 轻微平移,模拟包裹位移 scale: 0.5 # 缩放±50%,模拟不同距离拍摄 shear: 0.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 0.0 # 关键!禁用mosaic mixup: 0.0 # 关键!禁用mixup clahe: 1.0 # 新增:对单通道做CLAHE增强,提升低对比度区域 gridmask: 0.5 # 新增:GridMask强制模型关注局部纹理,对抗叠压

其中clahegridmask需在ultralytics>=8.2.0中启用(旧版需自行注入)。CLAHE能显著提升塑料瓶内液体轮廓,GridMask则让模型无法依赖全局形状(因X光中剪刀可能只露半把),逼其学习刀刃金属反射特征。

3.3 损失函数权重:为什么IoU Loss权重要降到0.5?

YOLO默认iou_loss=0.5,cls_loss=0.5,dfl_loss=1.0(v8.0.200+)。但在X光中:

  • cls_loss主导时,模型倾向把模糊的锂电池边缘判为“背景”,因分类置信度易受噪声干扰;
  • iou_loss过高,会使bbox回归过度拟合标注员手工框的毛刺边界(X光中金属边缘本就是弥散的)。

经消融实验,最优组合为:

# train.yaml iou_loss: 0.5 # 保持默认 cls_loss: 0.7 # 提升分类权重,迫使模型更谨慎区分相似物(如陶瓷刀vs普通刀) dfl_loss: 0.3 # 降低DFL权重,因X光目标长宽比极端(液体瓶高瘦、打火机扁平),DFL对尺度敏感

该配置使batterylighter的混淆率下降22%,powderliquid的误检率下降17%。


4. 避坑指南:X光YOLO训练中5个血泪经验换来的翻车现场

4.1 现象:训练初期loss震荡剧烈,100 epoch后仍不收敛

原因:未对X光图像做均值方差归一化。通用ImageNet预训练权重(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])完全不适用于X光图——其像素值集中在[0.1,0.9]区间,且标准差极小。强行使用导致梯度爆炸。
解决:在dataset.py中重写__getitem__,计算本数据集统计量:

# 计算Xray数据集均值std(运行一次) import cv2, numpy as np paths = glob("Xray_Anno_Dataset/YOLO/images/train/*.jpg") pixels = [] for p in paths[:1000]: # 取1000张足够 img = cv2.imread(p) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) pixels.append(img.astype(np.float32) / 255.0) stack = np.vstack([p.reshape(-1,3) for p in pixels]) print("Xray mean:", stack.mean(axis=0)) # [0.321, 0.321, 0.321](灰度图三通道相同) print("Xray std:", stack.std(axis=0)) # [0.142, 0.142, 0.142]

然后在train.py中传入--mean 0.321 --std 0.142,或修改transforms.py硬编码。

4.2 现象:验证时mAP飙升但测试集几乎全漏检

原因val.txttest.txt被错误合并。本数据集的val用于早停(early stopping),test是独立分布(不同安检设备采集),若训练时把test也加入val,则模型过拟合测试分布。
解决:检查ultralytics/cfg/default.yamlval路径是否指向YOLO/val/而非YOLO/test/;训练命令必须显式指定:

yolo train data=data.yaml model=yolov8s.pt val_data=YOLO/val/ epochs=200

绝不能省略val_data参数,默认会读data.yaml里的val字段,而该字段若写成YOLO/test/就铸成大错。

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

原因:X光图输入Tensor的dtype为float32,但ONNX导出时若未指定dynamic_axes,某些backend(如TensorRT)会将输入强制cast为uint8,导致数值坍缩。
解决:导出时加--dynamic参数,并手动指定输入范围:

yolo export model=yolov8s_xray.pt format=onnx dynamic=True opset=17 \ imgsz=[1,3,960,1280] half=False

且在推理代码中确保:

img = cv2.imread(path).astype(np.float32) / 255.0 # 归一化到[0,1] img = (img - 0.321) / 0.142 # 再标准化

4.4 现象:labelImg打开YOLO标注后bbox位置偏移

原因:labelImg默认按<filename>.jpg匹配,但本数据集部分图片名为IMG_001.jpg,而YOLO标注文件名为IMG_001.txt——看似匹配,实则labelImg读取时会因路径缓存错乱。
解决:用labelImg打开时,必须先加载图片目录,再逐张打开,不可拖拽单图;或改用CVAT(开源版)导入YOLO目录,其解析更鲁棒。

4.5 现象:测试集mAP@0.5达标,但实际部署时漏检陶瓷刀

原因:陶瓷刀在X光中呈浅灰色,与纸张、塑料袋灰度接近,而训练集里陶瓷刀样本仅占1.2%(43张),模型严重欠拟合。
解决:对ceramic_knife类别做过采样+CutMix

  • YOLO/train/images/中提取所有陶瓷刀图片路径;
  • albumentations库做CutMix(将陶瓷刀patch粘贴到其他背景图上);
  • 生成新图片存入YOLO/train/images/oversample/,对应label存入YOLO/train/labels/oversample/
  • 修改data.yamltrain路径为["YOLO/train/images/", "YOLO/train/images/oversample/"]

5. 测试集验证技巧:不止看mAP,还要盯住这3个安检特有指标

5.1 分类别漏检率(Miss Rate per Class)表格化分析

mAP掩盖了关键缺陷。例如整体mAP@0.5=73.6,但若ceramic_knife漏检率达42%,则毫无实用价值。必须用ultralyticsval.py输出详细报告:

yolo val model=yolov8s_xray.pt data=data.yaml split=test

然后解析runs/val/test/confusion_matrix.pngmetrics.csv,生成如下表格(示例):

类别PrecisionRecallmAP@0.5漏检数/总数典型漏检场景
knife0.890.930.917/102刀尖被金属盒遮挡
ceramic_knife0.610.580.5943/73平放于纸质文件夹中
battery0.940.870.9013/100与USB线缠绕
liquid0.770.820.7918/102塑料瓶装透明液体,无气泡
powder0.720.650.6835/54袋装奶粉与面粉难以区分

关键动作:对漏检率>30%的类别(如ceramic_knife),立即启动第4.5节的过采样流程,而非调learning rate。

5.2 置信度阈值-召回率曲线(Confidence-Recall Curve)

安检场景不追求高precision,而要求Recall≥99%(宁可误报,不可漏检)。需绘制confidencevsrecall曲线,找到满足Recall=0.99的最低conf:

# plot_conf_recall.py from ultralytics.utils.metrics import DetMetrics import matplotlib.pyplot as plt # 加载val结果(需先运行yolo val ... save_json=True) metrics = DetMetrics(save_dir="runs/val/test", names=classes) metrics.plot_confusion_matrix() # 生成混淆矩阵 # 手动计算不同conf下的recall conf_list = [0.1, 0.2, ..., 0.9] recalls = [] for conf in conf_list: tp = sum(1 for r in metrics.results if r['conf'] >= conf and r['correct']) fn = sum(1 for r in metrics.results if r['conf'] < conf and r['correct']==False) recalls.append(tp / (tp + fn + 1e-9)) plt.plot(conf_list, recalls) plt.xlabel('Confidence Threshold') plt.ylabel('Recall') plt.axhline(y=0.99, color='r', linestyle='--') plt.show()

实测发现,当Recall=0.99时,conf需降至0.18——这意味着模型输出大量低置信bbox,必须配套NMS阈值调至0.3,并用业务逻辑过滤(如battery+liquid同时出现才告警)。

5.3 X光特有干扰项压力测试

测试集虽已分层,但仍需人工构造3类干扰场景验证鲁棒性:

  • 强金属干扰:在测试图中叠加高斯噪声(σ=0.05)模拟安检仪老化;
  • 多层叠压:用OpenCV将2个knife图叠加(cv2.addWeighted),测试模型能否分离;
  • 低剂量成像:将测试图gamma校正(γ=0.7)模拟X光剂量不足。

每类干扰下,记录ceramic_knifepowder的Recall变化。若下降>15%,说明模型泛化力不足,应回退到第3节调整augment参数。

我坚持一个习惯:每次拿到新数据集,第一件事不是训练,而是用check_voc_integrity.py跑一遍,再用clean_yolo_labels.py过筛——这10分钟省掉后面3天debug。X光检测没有银弹,只有把数据当金矿挖,把bug当氧气吸。希望帮到你。

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

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

AI换脸技术为何在影视级场景频频翻车?深度解析技术难点与工程实践

1. 从《三千鸦杀》换脸翻车说起&#xff1a;AI换脸到底卡在哪《三千鸦杀》这部剧当年播出的时候&#xff0c;我正好在跟一个后期团队聊项目&#xff0c;群里有人甩了一张截图&#xff0c;就是那个被群嘲的换脸镜头。说实话&#xff0c;第一眼看上去确实出戏——脸是贴上了&…

作者头像 李华
网站建设 2026/9/23 21:37:25

CPU、GPU、NPU、SoC等十大处理器芯片架构的区别与选型指南

1. 先搞清楚一件事&#xff1a;这些“PU”根本不是一个维度的东西很多刚入行的朋友拿到这张表&#xff0c;第一反应是找一张大图把十个缩写按性能排个序。我当初也干过这事&#xff0c;但查完一圈资料后才发现&#xff0c;这套理解方式从根上就是错的。CPU、GPU、NPU这些缩写&a…

作者头像 李华
网站建设 2026/9/23 21:36:30

tchMaterial-parser 完整教程:把智慧教育平台的电子课本 PDF 存到本地

tchMaterial-parser 完整教程&#xff1a;把智慧教育平台的电子课本 PDF 存到本地 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具&#xff0c;帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载&#xff0c;让您更方便地获取课本内…

作者头像 李华
网站建设 2026/9/23 21:35:17

Convex Backend OCC 冲突调优指南:从检测症状到落地五种修复策略

数据库后端 【免费下载链接】convex-backend The open-source reactive database for app developers 项目地址&#xff1a; https://gitcode.com/gh_mirrors/co/convex-backend 点击查看 免费下载 导读&#xff1a;本文基于 convex-backend 仓库中的性能审计技能文档&#xf…

作者头像 李华
网站建设 2026/9/23 21:35:14

OBS Studio 32.1.0中文绿色版:专业直播录屏解决方案

1. 项目概述&#xff1a;OBS Studio 32.1.0中文绿色版的核心价值作为一名从2016年就开始使用OBS的内容创作者&#xff0c;我见证了这款开源软件从简陋的直播工具成长为行业标杆的全过程。这次要介绍的32.1.0中文绿色版&#xff0c;可以说是目前最适合中文用户"开箱即用&qu…

作者头像 李华
网站建设 2026/9/23 21:34:12

K8s 生产排障实战:10 个高频故障与排查命令(建议收藏)

摘要整理 K8s 生产环境十类高频故障:Pending、CrashLoopBackOff、ImagePullBackOff、OOMKilled、Service 不通、Ingress 报错、节点 NotReady、磁盘压力驱逐、滚动发布抖动、DNS 解析失败。每类给出排查命令、常见根因与处理方式,附 kubectl 速查表。排查前的三个基本功 kubect…

作者头像 李华