简介X光安检打火机识别数据集聚焦机场安检场景面向计算机视觉算法工程师与安检设备研发者主要解决危险品中打火机的自动检测问题。数据集共2119个文件包含真实场景jpg图像706张以及配套的xml与txt标注文件各706个分别对应YOLO和VOC格式所有图片均由LabelImg人工标注类别统一为lighter并分目录存放压缩包整体约102.38MB可导入常见检测框架直接训练。已有979人学习浏览获取后可省去手动标注环节既能直接开展YOLO系列模型训练也能通过对比xml与txt文件理解两种标注格式的转换关系为后续自建数据集提供参考模板特别适合入门者快速熟悉目标检测数据的组织与使用方式。真实安检图像中的遮挡与角度差异有助于验证打火机识别模型在复杂场景下的泛化性能。1. YOLO机场X光安检打火机识别数据集为什么这不是一个普通的物体检测项目做安检智能判图的人应该都有体会拿 COCO 上跑得飞起的 YOLO 模型直接丢到机场 X 光机上识别打火机第一轮测试几乎必翻车。原因很简单——X 光成像和可见光成像完全是两套视觉逻辑打火机在透视图像里可能被手机、充电宝、金属水杯叠在一起轮廓被切得七零八落。专门整理一份针对打火机的 X 光安检识别数据集再把 YOLO 模型按这个数据域的规律去调才是把项目落地的正道。这篇笔记写给两类人一是要做安检智能判图算法的工程师二是准备采购或自建训练数据的集成商。数据集的采集规范、格式转换脚本、训练参数和避坑点我按实际做过的方案一次讲透。2. X光安检成像的特殊性打火机为什么在可见光数据集上训练不起来2.1 X光成像的核心逻辑灰度、穿透与材料密度普通相机拍到的打火机靠的是表面反射光塑料外壳的红色、金属砂轮的银色都是关键特征。X 光安检机完全不同——它记录的是射线穿过物体后的衰减值材质密度越高、原子序数越大图像上就越亮或者越暗取决于安检机的色彩映射策略。常见的机场安检机把图像按有机物、无机物、金属做伪彩色映射有机物偏橙色无机物偏蓝色金属显示为深蓝色到黑色。但很多出口的数据集为了通用性直接保存为灰度 PNG 或原始 16 位穿透率数据。打火机在 X 光下是典型的复合材料金属外壳或金属中架是高密度区域图像上非常亮内部的丁烷液体是低密度有机物显示为相对透明的区域砂轮里的压电陶瓷和火石是小而硬的高亮颗粒。这三部分组合在一起和可见光图像里的“打火机”长相完全不同。你的 YOLO 模型如果是在 COCO 上预训练的它学到的纹理特征是表面颜色和光影换到 X 光灰度图后特征分布彻底漂移这就是为什么直接搬预训练权重效果差。2.2 打火机在X光图像里的视觉特征与标注难点我在标注打火机 X 光图时总结出三个稳定特征一是整体轮廓多为矩形或圆角矩形宽高比接近 2:1 到 3:1二是内部有气体腔形成的低密度暗区边缘过渡柔和三是金属打火机常看到高亮的壳体边线。如果安检机图像是伪彩色的打火机外壳的蓝色金属部分和内部橙色气体部分会有明显分界。但真正的难点不在这里而在遮挡和重叠。行李箱里打火机很少单独躺着它可能塞在背包侧袋、压在保温杯底下、和钥匙硬币混在一起。X 光透视把这些东西在二维平面上叠加目标边界被其他物品的高亮区域切断。所以数据集的标注规范里我一般要求标注工遵循“可辨识即标注”原则——只要人眼能看出那里有打火机的关键部位金属壳、砂轮、气体腔至少两个特征就标一个完整外接框哪怕部分被遮挡。因为训练 YOLO 时遮挡目标的学习信号本来就弱再不标全模型会倾向于把局部特征当成完整目标导致部署时大量漏检。2.3 标注格式选择VOC 还是 COCOX 光安检数据集的标注格式没有统一标准但落地时关键看你的训练管线。YOLO 系列v5/v8/v11原生支持两种格式一是每张图对应一个 txt每行是 class x_center y_center width height归一化坐标二是 COCO JSON。我实际更推荐标注时先用 VOC XML 格式LabelImg 默认输出便于人工校对再统一脚本转成 YOLO txt。原因很简单XML 里能看到 xmin/ymin/xmax/ymax 的整数像素坐标人工检查边界框是否偏离时直观COCO JSON 的嵌套结构在多人协作时经常出现 id 错位排查起来费时间。3. 构建打火机识别数据集从原始图像到 YOLO 训练集的完整流程3.1 图像采集多设备、多角度、多遮挡等级数据集的源头是安检机的原始输出。我一般会向机场或安检设备厂商要三类数据一是不同品牌安检机海康、同方威视、史密斯 Heimann 等的导出图像因为各家的能量分辨率和色彩映射差异很大二是不同通道的图像比如 1 号通道和 5 号通道即便型号相同射线源老化程度也不同灰度分布会有偏移三是同一物品在不同摆放角度下的扫描图。这里有个关键参数——图像分辨率。安检机导出图的尺寸从 800x600 到 2000x1500 都有行李图像通常整包呈现在画面中央。如果后续打算用 YOLOv8 在 640x640 下训练大图上的打火机可能只占 30x30 像素直接整图缩放会丢失大量细节。常见的处理是先在原图上做目标裁剪或切片把打火机区域切出来再缩放或者干脆训练时用 imgsz1024 甚至 1280。我建议数据采集时就记录每个目标的原始像素尺寸后续统计目标大小分布决定训练分辨率。采集时还要注意正负样本比例。安检场景里正常行李占绝大多数打火机只是在部分包里有。一份实用的数据集除了包含打火机的图像还要有 20% 左右的纯负样本完全没有违禁品的行李图。负样本虽然不提供正样本梯度但能让模型学会“什么都不输出”到“输出背景类”的判断显著降低误报率。负样本图不要和正样本图来自同一批行李扫描——同一只包取出打火机再扫一遍这两张图背景几乎一样放进数据集会造成评估虚高。3.2 标注格式统一VOC XML 转 YOLO txt 的脚本拿到标注好的 XML 后写一个转换脚本把 VOC 格式转成 YOLO txt。这个脚本我每次都会复用先把路径、类别名和坐标处理写清楚import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, class_names, out_txt_path): 将 LabelImg 输出的 VOC XML 转为 YOLO txt 格式。 class_names: [lighter] 这样的类别列表索引即 YOLO 类别 ID。 tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: # 类别不在预设列表里就跳过避免脏数据混入 continue cls_id class_names.index(name) xmlbox obj.find(bndbox) xmin float(xmlbox.find(xmin).text) ymin float(xmlbox.find(ymin).text) xmax float(xmlbox.find(xmax).text) ymax float(xmlbox.find(ymax).text) # YOLO 格式要求归一化的中心点坐标和宽高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h box_w (xmax - xmin) / img_w box_h (ymax - ymin) / img_h # 对越界框做裁剪防止标注超出图像边界导致训练报错 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_w min(max(box_w, 0.0), 1.0) box_h min(max(box_h, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines)) # 批量转换入口 if __name__ __main__: xml_dir Path(./annotations_xml) txt_dir Path(./labels) txt_dir.mkdir(exist_okTrue) CLASSES [lighter] # 类别顺序固定训练配置里的 nc 和 names 要和这里一致 for xml_file in xml_dir.glob(*.xml): out_txt txt_dir / (xml_file.stem .txt) voc_to_yolo(str(xml_file), CLASSES, str(out_txt))这段脚本里最值得注意的参数是框坐标的裁剪。实际标注中时常出现把框拖到图像边缘外的情况如果不 clip 到 [0,1] 区间YOLO 训练时会在 loss 计算里拿到负数宽高轻则警告重则直接崩掉。另外类别名的顺序一定要和后续训练的 data.yaml 完全一致——class_names 列表的下标就是 YOLO 的类别 ID排错一个位置整个模型的混淆矩阵就会乱掉。3.3 数据集划分与数据增强别让数据泄露毁掉验证集格式转换完成后按 7:2:1 划分 train/val/test。划分时有个容易忽视的原则同一件行李的多次扫描图比如正位、侧位、倒置必须放进同一个集合。如果同一件行李的图像既在训练集又在验证集模型相当于见过“答案”验证 mAP 会虚高 10 个百分点以上部署后立刻现原形。最稳妥的方式是按“行李 ID”划分——如果原始文件命名里有设备编号和包裹编号直接用编号前缀分组没有的话至少确保训练集和验证集的文件名没有重复的图像内容。数据增强方面YOLOv8 自带的 Mosaic 增强对 X 光图有效但有几个参数建议按安检场景调整。Mosaic 会把四张图拼在一起相当于人为制造了“多个物体叠加”的场景恰好模拟了行李箱里的遮挡关系所以我一般让 mosaic 的概率保持在 1.0默认即开启。旋转增强的角度要调小默认的 rotate0.0 就行因为打火机在 X 光下的特征方向性较强大角度旋转会改变金属件和气体腔的相对位置关系可能学出不合理的特征。水平翻转可以开安检机图像不存在左右语义差异。另外 X 光图的灰度直方图和可见光差异很大数据增强里不要用色彩抖动hsv_h/hsv_s/hsv_v 都设为 0否则会把原始材料的密度信息破坏掉。4. 用 YOLOv8 训练打火机识别模型配置、命令与调参要点4.1 数据配置文件data.yaml 的写法与检查点YOLO 系列训练的第一步是准备 data.yaml路径必须是绝对路径或用相对 YOLO 项目根目录的写法。我踩过最深的一个坑是在服务器上用相对路径启动训练没问题换一台机器路径变了就直接报 Dataset not found。所以现在统一用绝对路径。data.yaml 内容如下# data.yaml path: /data/xray_lighter # 数据集根目录 train: images/train # 相对 path 的训练图目录 val: images/val # 验证图目录 test: images/test # 测试图目录训练时不使用 nc: 1 # 类别数只需要打火机一类 names: 0: lighter # 类别名和 txt 标注里的类 ID 一一对应训练命令一般长这样yolo detect train \ data/data/xray_lighter/data.yaml \ modelyolov8s.pt \ epochs200 \ imgsz1024 \ batch16 \ device0 \ patience30 \ project/output/xray_lighter \ namerun1这里的 imgsz1024 是关键参数。刚才提到安检原图上打火机经常只有几十像素用默认的 640 会丢失小目标特征。我对比过同一份数据集在 imgsz640 和 1024 下的结果小目标召回率差距在 8~12 个点。代价是训练显存和耗时翻倍所以如果你的显卡是 V100 或 A100直接用 1024如果是 2080Ti 这类 11G 显存的卡batch 降到 8 或者用 imgsz960 折中。另外很多人纠结要不要用预训练模型我的建议是用 yolov8s.pt 或 yolov8m.pt 的 COCO 预训练权重做初始化但不要对它抱有太大期待。X 光域和自然图像域差别太大预训练权重提供的更多是低层边缘、纹理特征的初始化能加速收敛但不会改变最终的精度上限。如果数据集量足够大比如打火机目标超过 1 万个框直接从空白权重训练也能收到接近的结果只是 epoch 需要的更多。4.2 训练过程中的指标读取从 loss 曲线到混淆矩阵训练时我习惯盯三个东西box_loss、cls_loss 和验证集的 mAP50。YOLOv8 的训练日志里会实时打印也可以用 wandb 记录。box_loss 是边界框回归损失它下降得慢不要慌——因为 X 光图像里遮挡导致的边界模糊本来就多模型需要比较多的 epoch 才能收敛到稳定的框。cls_loss 更关键如果 cls_loss 在训练后期出现反弹往往是数据增强过强比如 Mosaic 的随机缩放把打火机缩得太小超过了学习能力或者学习率没配合好。训练结束后一定要做验证集评估不要只盯着训练集 loss。运行yolo detect val \ data/data/xray_lighter/data.yaml \ model/output/xray_lighter/run1/weights/best.pt \ imgsz1024 \ conf0.25 \ iou0.6conf 是置信度阈值iou 是 NMS 的 IoU 阈值。对安检场景我建议 conf 单独看两条结果线一条用默认 0.25 看理论召回一条用 0.5 以上看实际可用状态。因为安检员不可能接受机器频繁报警——每 100 个包里报警 80 次他们会直接把系统关掉。你需要在高置信度下保持召回这个指标在验证阶段就要量化出来。4.3 损失函数与类别不均衡打火机类别要不要单独调权重这里要回应一下“yolo损失函数”这个搜索词。YOLOv8 的损失函数分成三部分边界框回归损失CIoU 或 DFL、分类损失BCE、以及 DFL 的分布损失。分类损失默认对每个类别平等对待但如果你的数据集里打火机目标只占所有框的很小比例安检图像里单张图可能只有 1 个打火机背景区域巨大模型会偏向“什么都不检”。这时候可以在 data.yaml 里设置 cls 损失的权重或者在训练命令里加cls1.5这类参数。不过我实测下来对单类数据集只有 lighter 一类cls 权重的作用有限——因为模型不需要区分打火机和别的类别只需要区分目标和背景。真正有效的是调节前景-背景样本比例通过 mosaic、copy_paste 增强增加每张图的目标数量。YOLOv8 默认开启 mosaic但 copy_paste 在修改版里没有默认开启可以手动在增强参数里打开。5. 训练与部署避坑X光安检场景下的 5 个常见问题5.1 现象一训练到一半 loss 变成 NaN权重文件全废这个问题我自己在刚转 X 光项目时就遇到过两次后来发现和“yolo训练中bn崩溃”的描述完全吻合。现象是训练到 40 到 60 轮时box_loss 和 cls_loss 突然变成 nan训练进程不退出但指标全坏。原因是 BatchNorm 统计量崩了。安检图分辨率大为了塞进显存batch size 往往被压到 4 或 8。小 batch 下的 BN 层均值方差估计不稳定一旦某次前向传播出现极端激活值统计量被污染loss 立刻发散。解决办法分三步第一步batch size 提到 16 以上如果显存不够就降低 imgsz 到 960 或 896而不是牺牲 batch。第二步如果必须用小 batch可以在训练命令里关闭部分 BN 的更新或者换用batch-1让 YOLO 自动用最大 batch。第三步检查数据里有没有异常图像——比如全黑的全白的、或者 16 位深度没转成 8 位的图这些异常像素值会直接让 BN 崩掉。5.2 现象二验证集混淆矩阵“总和”不等于样本数有人在验证后打印混淆矩阵发现把每一格加起来和 GT 框总数对不上。搜“yolo混淆矩阵总合不唯一”看到的现象基本一样不是矩阵算错了而是 YOLO 的混淆矩阵包含“漏检”这一格同时 NMS 和置信度过滤会吞掉一部分低分预测框。另外如果背景类被设置为忽略默认 bg 不参与 loss那背景预测和背景真实各自独立一格总和自然不等于前景目标数。这类问题通常说明你的标注或评估配置有歧义。我的处理习惯是跑验证时固定conf0.001, iou0.5看原始召回能力得到一个“理论上限”再正常置信度下跑一次看“实际可用值”。两个数之间的差就是置信度阈值带来的损失这个差值如果过大超过 20%说明模型输出置信度分布不合理需要在训练时加一些难例挖掘或重采样。5.3 现象三打火机被金属水杯完全“吞掉”漏检严重X 光透视下不锈钢水杯密度极高图像上是一大片深色高亮区域背后如果藏着一个打火机灰度值范围和水杯重叠模型几乎不可能从单张 2D 图像里分辨出来。这不是模型能力问题是物理成像的极限。解决思路有两个层面。算法上把输入从单能灰度图换成双能伪彩色图——很多安检机输出有机物/无机物分离的彩色图金属、有机物、无机物各有不同颜色通道打火机的气体腔有机物和水杯金属在颜色上会被分开模型学到的特征区分度大幅提升。如果只有灰度图则要裁剪出可疑区域做局部直方图均衡化增强人为拉开密度差。我试过在预处理时对每个切片做 CLAHE对中等遮挡场景的召回提升约 5 个点。5.4 现象四高分辨率原图直接缩放训练小目标全部丢失这个坑几乎所有人都会踩一遍。安检原图 1500x1200设 imgsz640 后原图被压缩到 1/2 以下一个原本 40x40 像素的打火机在输入图上只剩 20x20特征细节基本没了。YOLOv8 在 640 下对小目标的检测本身就弱暴力缩放等于雪上加霜。我现在的做法是先用原图统计目标像素尺寸分布。如果 80% 的目标长边在 32 像素以下imgsz 直接上 1280或者更高只要显存够且标注质量可信。如果只能用 640那就切片推理——推理阶段把大图裁成 640 的滑窗块逐块检测后再映射回原图坐标。切片重叠率设 20%可以有效避免目标正好卡在切片边线上被切断。5.5 现象五部署到安检机现场后误报率奇高训练时 mAP50 有 0.95一到现场每分钟报 8 次警。这个问题我排查下来通常出在两个地方现场安检机的图像色彩映射和训练数据不一致导致整体灰度分布偏移或者现场图像分辨率/位深和数据集不一致模型看到的是域外数据。购买或收集数据时我建议明确记录每一张训练图像的来源设备型号、图像位深8bit/16bit、颜色空间灰度/伪彩色。训练时做灰度扰动增强模拟同一台设备在不同老化阶段的表现。部署前留一份“现场样本袋”——拿一小部分现场采集图做 blind testmAP 不掉点超过 5 个点就不能上线。6. 验证模型是否真的可用测试集设计、置信度阈值和部署前的最后一道检查训练完模型不要急着接进安检机。先做一个贴近实战的盲测找同事拿不同品牌、不同新旧程度的打火机塑料壳、金属壳、防风打火机分别塞进双肩包、行李箱、手提袋在安检机上过一遍采集 200 到 300 张现场图。这批图不参与任何训练和验证只在最后跑推理计算两个指标召回率有打火机的包里检出来多少和误报率没打火机的包里报警多少次。这两个指标才是安检员真正关心的。置信度阈值别拍脑袋定用验证集画一条 F1-置信度曲线。YOLO 的 val 输出会告诉你不同 conf 下的 F1 变化一般选 F1 最高的点作为基准值再往高调 0.05 左右留出安全冗余。如果曲线显示最高 F1 也只有 0.8说明模型本身的判别力不够这时去调阈值没有意义得回到数据层面补充难例。最后一件事是检查模型的输入输出约定。如果是接机场原有安检机检测结果要触发告警和图像标记务必确认模型输出的坐标是在原图分辨率下的像素坐标而不是训练时的 1024x1024 坐标系。我习惯在部署代码里加一个坐标映射函数把模型输出框乘以原图与输入图的缩放比。这个小步骤能避免“框画在物品旁边”的尴尬情况。我现在的习惯是每个安检数据集项目都保留三组数据:用于训练的常规集、用于选阈值的验证集、用于最终验收的现场盲测集。三组互相隔离任何一组被污染都能从指标异常上看出来。这个习惯帮我避开了很多“训练时好看、现场打脸”的局面。希望帮到你。本文还有配套的精品资源点击获取