news 2026/10/4 2:38:17

机场安检危险品自动识别:YOLOv8实战与数据不均衡优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
机场安检危险品自动识别:YOLOv8实战与数据不均衡优化

简介:这是一份基于深度学习的机场安检危险品自动识别系统Python源码,面向高校计算机、人工智能、信息安全等专业学生与教师,适合作为课程设计、毕业设计、期末大作业或初期项目立项演示使用。资源共179个文件,包括37个源码文件、53个编译缓存文件、63张图片,同时包含XML标注、UI界面、启动脚本等辅助内容,压缩包仅9.73MB,结构清晰,便于按模块查阅。已有346人学习下载,代码经过功能验证可稳定运行,既能直接运行体验,也方便基于此做二次开发。项目基于Faster R-CNN目标检测框架,覆盖数据准备、模型训练、推理识别、界面展示等完整流程,并配有演示动图,既能帮助理解目标检测原理,也可快速扩展到实时视频流或更多危险品种类,实用性与可玩性兼备。

1. 机场安检危险品自动识别:本质是一个“数据极不均匀的目标检测”项目

机场安检场景里,X光机每秒钟都在产生行李图像,安检员需要长时间盯着屏幕找刀具、打火机、液体瓶等危险品,疲劳和注意力分散是真实痛点。基于深度学习的机场安检危险品自动识别系统,做的就是训练一个目标检测模型,让它自动在X光图上定位并分类这些危险品;一个典型的Python源码包会把训练脚本、推理代码、标注转换工具和模型导出封装在一起,让团队可以快速复现整个流程。适合做这件事的人是算法工程师、安检设备集成商,以及用它做研究生课题的学生。这里先给一个反直觉结论:这个项目最难的环节从来不是换一个更深的模型,而是数据分布极端不均衡,以及现场成像差异导致的漏检。

2. 先选YOLOv8作为基线:实时性、迁移学习与Python源码包结构

在真实安检X光机上,行李随传送带连续过检,留给算法的时间窗口很短。这意味着目标检测必须在几十毫秒内完成,在边缘设备上跑得动,而且不能把正常行李误报成危险品。这类硬实时要求,天然把模型候选限定在单阶段检测器里。常见做法是先选YOLO系,当前最适合拿来搭建危险品自动识别原型的是YOLOv8。它不是在某个指标上碾压对手,而是工程收益的综合结果:结构不复杂、训练生态完整、导出部署路径清晰,拿到源码包后可以很快跑通一条从数据到模型的链路。

2.1 X光成像差异:为什么不能拿COCO权重直接上线

大部分YOLOv8预训练权重是在COCO自然图像上学的。自然图像里有颜色、纹理、阴影,而安检X光图是透射图,物体没有真实颜色,只有原子序数导致的灰度差异;行李箱里物体互相堆叠,形成大量遮挡。直接拿COCO权重做零样本推理几乎不可用,我见过最典型的结果是模型把拉杆箱的金属支架框成刀具。所以这类项目的通用做法是:把COCO权重当作初始化,不用它的分类知识,再用安检X光数据做迁移学习。迁移学习的三个关键点是:第一,前几轮冻结backbone,让检测头先把X光域的统计特征学起来;第二,学习率要比从零训练低一档,一般初始学习率打到0.001到0.005之间;第三,数据增强要关闭对颜色敏感的部分,因为X光图没有自然色彩。

2.2 Python源码包解压后通常长什么样

拿到一个基于深度学习的机场安检危险品自动识别Python源码包,解压后通常不是单个脚本,而是一套工程目录。我先按常见结构列出,再解释每部分该干什么。这样做的目的是让你拿到包之后快速对号入座,不被一堆文件吓住。

目录/文件常见职责
train.py / main.py训练入口,读取数据配置、启动训练
detect.py / infer.py推理入口,加载权重输出检测结果
datasets/训练数据配置yaml、图片与标签目录
models/网络定义或模型封装层
utils/标注转换、可视化、指标统计等辅助函数
weights/存放预训练权重和训练产物
requirements.txtPython依赖清单

拿到源码包第一件事不是跑训练,而是核对requirements.txt里的依赖版本和你的Python环境是否匹配。YOLOv8这类工程对torch和torchvision版本有隐式约束,版本差太远会出现莫名其妙的算子错误。第二件事是检查datasets里那个yaml文件,看类别名和标注文件是否对得上。第三件事才是找一张样例图跑推理,确认环境通。

2.3 先用最小推理脚本确认模型能框出危险品

环境验证最直接的做法,是用包里的权重对一张X光样例图跑推理。下面这段代码是常见的YOLOv8推理写法,适合先确认模型链路是否正常:

from ultralytics import YOLO # 载入训练好的权重,路径换成自己目录下的best.pt model = YOLO("runs/detect/train/weights/best.pt") results = model.predict( source="samples/xray_001.jpg", conf=0.25, # 置信度阈值,低于这个值的框会被过滤 iou=0.45, # NMS的IoU阈值,重叠超过这个值的框会被合并 imgsz=640, # 推理分辨率,必须和训练时保持一致 device="cuda:0" # 没有GPU就改成 "cpu" ) for r in results: boxes = r.boxes for box in boxes: cls = model.names[int(box.cls[0])] conf = float(box.conf[0]) xyxy = [round(v, 1) for v in box.xyxy[0].tolist()] print(f"类别: {cls}, 置信度: {conf:.2f}, 坐标: {xyxy}")

这段代码的逻辑不复杂:模型先对输入图做letterbox缩放,再进入网络前向推理,输出候选框,最后经过NMS合并重叠框。conf和iou是两个最常调的推理参数。conf设太低会出现大量误检,安检场景里误检会严重消耗安检员注意力,所以现场部署时常常把阈值往上提到0.35以上。iou保持默认0.45即可,安检X光图里目标堆叠严重,调太高会把贴着放的刀具和打火机框成一个目标。

2.4 训练启动命令与参数表:从预训练权重开始的三件事

环境验证通过后,下一步是用自己的数据训练。YOLOv8的CLI训练命令通常长这样:

yolo detect train \ data=datasets/security_xray.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.1 \ mosaic=1.0 \ close_mosaic=10 \ patience=20 \ device=0,1

这个命令里最重要的不是epochs,而是model参数。model=yolov8s.pt表示用COCO预训练的yolov8s权重做起点,而不是随机初始化。危险品数据集普遍只有几千到几万张,从随机初始化开始训练,收敛速度和最终精度都会差一大截。freeze参数在源码包里也经常出现,用来指定前几个epoch冻结backbone层,比如freeze=10表示前10个epoch不更新backbone权重。

下面这张参数表是这类项目里最常改的几项,按调整优先级排列:

参数建议值范围作用与调整时机
imgsz640~1280决定目标像素大小;安检X光图多为1920宽以上,小目标多时优先提高它,但要留意显存
batch8~32受显存限制;batch太小loss震荡大,梯度累积可以缓解
lr00.001~0.01迁移学习用偏低值;数据量少于5000张时建议0.001起步
lrf0.01~0.1控制学习率衰减到最终值的比例
close_mosaic5~15最后N个epoch关闭mosaic增强,让模型适应真实分布
patience15~30早停轮数,监控val loss
device0 / 0,1单卡或多卡;多卡时batch会按卡数拆分

我一般建议先用yolov8n跑通整个链路,确认数据和标签没问题,再换成yolov8s或yolov8l追求精度。这个习惯能省下大量排查时间,因为模型容量太大时,数据集的错误会被学习过程掩盖,出现loss一直下降但现场表现差的怪象。

3. 数据集是天花板:X光图像特性、标注规范与VOC转YOLO脚本

模型结构解决的是“能学”,数据解决的是“学什么”。在机场安检危险品自动识别这个方向上,模型结构的差异远不如数据质量带来的差异大。这一章我会讲清楚X光图为什么让常规检测模型翻车,以及如何把已有的VOC格式标注转成YOLO能吃的格式。

3.1 为什么X光图让常规检测模型集体翻车

自然图像检测模型依赖颜色和纹理,但安检X光图像是透射成像,行李内部物品在图像上是叠加的。一瓶500毫升矿泉水在自然光下是半透明的浅蓝色,在X光下是一团低对比度的灰色区域,和衣物、书本混在一起。这是第一重翻车原因:目标与背景的对比度极低。

第二重翻车原因是动态范围大。X光机输出的原始图像里,金属物品会接近饱和变成一片亮白,而塑料和液体几乎和背景融为一体。很多源码包里的预处理只是简单resize和归一化,不做对比度拉伸,等于把最关键的灰阶信息丢掉了。常见做法是在训练前对图像做自适应直方图均衡化,或者把原始高动态范围图像分成“高密度区”和“低密度区”两个通道送进网络。这个预处理差异,往往比换一个backbone对最终mAP的影响更大。

第三重翻车来自类别不均衡。真实安检数据里,99%的行李没有危险品,有危险品的图像里,刀具和充电宝出现的频率又远高于枪支。如果直接按原始分布训练,模型会学成一个“永远输出背景”的保守模型,因为这样loss最低。这是这类项目里最容易踩的坑,后面会用专门章节展开。

3.2 标注规范与类别定义:宁可少类别,不做模糊类

公开的安检X光数据集有SIXray、OPIXray、GDXray等,但它们基本是学术用途,类别和现场设备不匹配,直接拿来训练上线不现实。实际项目还是要从现场采集图像,自己标注。标注规范决定模型上限,我踩过最大的坑是类别定义太细:把刀分成“菜刀”“弹簧刀”“折叠刀”,标注量翻了三倍,模型精度反而下降,因为类间差异小于类内差异。

常规做法是把类别收敛成最小可用集,比如:firearm、knife、lighter、liquid_bottle、battery、flammable_spray。定义原则是:“不管外观长什么样,只要在安检规则里属于需要报警的同一类,就归为一个类。”一个打火机和一把钥匙叠放在一起时,标注的边界框要尽量框住完整目标,但不强求像素级轮廓。目标被遮挡超过70%时,我建议弃标而不是硬标,硬标的模糊框会把模型训坏。

3.3 把VOC标注转成YOLO格式:转换脚本与四个边界坑

很多团队早期数据是用LabelImg标注的,导出的是VOC格式的XML文件,而YOLO训练需要每个图对应一个同名的txt文件,每行格式是“class_id x_center y_center width height”,前四个值都是归一化到0到1之间的浮点数。下面是一段常见的转换脚本,我在实际项目里会加上日志输出,方便定位问题:

import os import xml.etree.ElementTree as ET def convert_voc_to_yolo(xml_path, out_dir, class_names, img_width, img_height): """ 把单张VOC XML标注转成YOLO txt标注。 class_names: 类别列表,索引就是YOLO的class_id。 img_width/img_height: 原始图像宽高,用于归一化。 """ tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in class_names: print(f"[skip] 未定义类别: {name}") continue cls_id = class_names.index(name) box = obj.find("bndbox") xmin = max(float(box.find("xmin").text), 0) ymin = max(float(box.find("ymin").text), 0) xmax = min(float(box.find("xmax").text), img_width) ymax = min(float(box.find("ymax").text), img_height) # 过滤完全出界的框 if xmax <= xmin or ymax <= ymin: print(f"[skip] 空框: {xml_path}") continue xc = (xmin + xmax) / 2 / img_width yc = (ymin + ymax) / 2 / img_height w = (xmax - xmin) / img_width h = (ymax - ymin) / img_height # 过滤小到失去意义的框,比如小于3个像素 if w <= 0.001 or h <= 0.001: print(f"[skip] 目标过小: {name}, w={w:.4f}") continue lines.append(f"{cls_id} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}\n") txt_name = os.path.basename(xml_path).replace(".xml", ".txt") with open(os.path.join(out_dir, txt_name), "w", encoding="utf-8") as f: f.writelines(lines)

这段代码的边界处理有四个关键点,直接决定转换后的训练能否收敛。第一,坐标必须做clip,因为实际标注里经常出现框超出图像边缘的情况,不处理的话归一化值超过1,模型在计算损失时会把坐标算出图像范围,训练曲线像黑匣子一样抖动。第二,空框要跳过并打日志,否则生成的txt是空文件,YOLO训练时会报标签错误。第三,目标过小的过滤阈值要谨慎,安检场景里的打火机在整张1920宽图像上可能就是十几个像素,过滤阈值设太高会把真实小目标全删掉。第四,类别映射必须和数据集yaml里的names顺序一致,这是最常见的低级错误,错一个位子整个模型就白训了。

3.4 用合成数据补不均衡:贴片是性价比最高的增强

当某个类别只有几十张图时,靠采集新数据成本太高,常见做法是合成数据。最简单的贴片增强是把标注框内的目标抠出来,经过随机旋转、缩放后贴到正常行李图上,同时生成对应标签。下面是一个示意片段,生产环境里可以再叠加随机亮度和对比度扰动:

import cv2 import random import numpy as np def paste_object(bg_img, obj_img, bbox, img_size=640): """ bg_img: 正常行李图 obj_img: 从危险品图里抠出的目标图 bbox: 原图里的目标框 [x, y, w, h] 返回值:增强后的图 + YOLO格式标签行 """ scale = random.uniform(0.8, 1.3) obj = cv2.resize(obj_img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR) h, w = bg_img.shape[:2] max_x = max(w - obj.shape[1], 0) max_y = max(h - obj.shape[0], 0) x = random.randint(0, max_x) y = random.randint(0, max_y) # 目标区域像素直接覆盖背景,可叠加透明度来模拟透视重叠 bg_img[y:y + obj.shape[0], x:x + obj.shape[1]] = obj xc = (x + obj.shape[1] / 2) / w yc = (y + obj.shape[0] / 2) / h label = f"{class_id} {xc:.6f} {yc:.6f} " label += f"{obj.shape[1] / w:.6f} {obj.shape[0] / h:.6f}" return bg_img, label

贴片增强有个前提:被贴的目标必须是在同一类X光设备上拍的,不同安检机的能量和伪彩映射不同,跨设备贴片会在特征空间里引入不一致,模型训练出来会误检。合成数据适合用来补“有真样本但数量少”的类别,不适合完全替代真实数据。安检场景里每一类至少保留200张真实标注样本,合成数据只是补充。

4. 训练与调优:从能跑的基线到可复现的收敛曲线

数据和代码链路准备好之后,训练本身反而是一个相对机械的过程,但机械不意味着无脑。这一章我按“先跑通、再调优、最后看指标”的顺序来写,重点说明每个参数背后对应什么问题。

4.1 先建立能跑的基线,再谈调优

我接手这类源码包时,第一件事永远是先切出200张图片做一次小规模训练,而不是直接全量开跑。小规模训练的目的一是验证数据加载有没有问题,二是确认loss是否能下降,三是估算一个epoch需要多长时间。如果200张图上loss纹丝不动,先检查标签有没有正常读取,再检查数据增强是不是把目标切没了。下面是常见的小规模训练命令:

yolo detect train \ data=datasets/security_xray_small.yaml \ model=yolov8n.pt \ epochs=30 \ imgsz=640 \ batch=8 \ lr0=0.001 \ device=0

小规模训练时batch可以调小到4或8,因为不追求收敛质量,只求快速看到loss变化。yolov8n的推理速度快,在单卡上跑30个epoch通常只需要几十分钟,这个反馈速度非常重要。如果这一步的train/box_loss曲线有下降趋势,说明数据链路是通的,可以把训练扩大到全量数据。

4.2 关键参数表:按顺序调,不要同时动三个参数

很多人在训练阶段喜欢同时调整imgsz、batch、lr0和mosaic,结果模型变差了也说不清是哪个参数导致的。我一般按表格里的顺序调,一次只动一个参数,观察val loss和mAP变化。

调整顺序参数推荐范围说明
1imgsz640 / 960 / 1280安检X光图宽通常在1920以上,小目标多就往上提
2batch8~32受显存和训练速度共同限制
3lr00.001~0.01收敛慢就微调,不要直接翻倍
4mosaic0.0~1.0数据量少时保持1.0,后期用close_mosaic关闭
5hsv_h / hsv_s / hsv_v0.0~0.2X光图没有自然色彩,不建议调大hsv强度
6patience15~30监控val loss做早停

imgsz是对安检场景影响最大的参数。原图1920宽的X光图直接缩到640,一个原本30像素的打火机缩到10像素,检测头基本学不到有效特征。如果显存有限,我建议优先把imgsz提到960,模型先用yolov8n,而不是硬上yolov8l配640分辨率。这是性价比最高的一个取舍。

4.3 训练曲线怎么看:别只盯总mAP

训练结束后,源码包会输出一堆指标文件,最常见的是results.png、confusion_matrix.png和混淆矩阵相关的验证结果。新手常犯的错误是只看mAP50一个数字。这个数字在类别不均衡的数据集里极具欺骗性,背景占比99%时,模型把所有图都预测成背景也能拿到很高的整体表现。

正确做法是分三步看。第一步看每类AP,比如results.csv里按类别拆分的AP,找到拖后腿的是knife还是lighter。第二步看混淆矩阵,确认模型是不是把打火机误判成电池,这种混淆说明两类在X光灰度分布上太接近,需要通过采集更多样本来拉开类间差异。第三步看误检率,单独统计模型在300张纯正常行李图上的误报次数,这个指标比mAP更接近安检员的真实体验:机器频繁误报,安检员会逐渐不再信任系统。

4.4 增量训练的“后悔药”

项目上线后标注数据会持续增加,每次重新从COCO权重训练代价太高。常规做法是做增量训练:用已有best.pt权重继续训练新数据,并把学习率降到0.0005到0.001之间,同时加大close_mosaic的轮数。这个习惯相当于给模型吃后悔药,不需要推翻重来。

yolo detect train \ data=datasets/security_xray_v2.yaml \ model=runs/detect/train/weights/best.pt \ epochs=30 \ imgsz=960 \ batch=16 \ lr0=0.0005 \ close_mosaic=5 \ device=0

增量训练里最需要注意的是验证集不能不变,否则模型只是在记忆旧数据分布。每轮增量都要从最新采集的数据里抽出一部分当验证集,保证指标反映的是现场分布。我在实际项目里会把每次增量训练的权重导出路径按日期归档,万一新数据引入噪声导致指标下滑,还能回退到上一个版本。

5. 避坑与常见问题排查:安检X光场景的四条踩坑记录

这一章按我实际踩过的坑来写,每条都按照“现象、原因、解决”的结构展开。这些问题在自然图像检测里不常见,但在安检X光场景里几乎每个团队都会遇到。

5.1 现象一:模型把笔记本电脑整体框成可疑物

第一次上线验证时,模型对正常背包里的笔记本电脑给出了高置信度报警,框还特别大,几乎把整个电脑框住。排查后发现,电脑内部电池、硬盘等金属件在X光下形成的高密度区域,和充电宝的灰度分布高度重叠。模型学到的不再是“充电宝的结构特征”,而是“图像中存在一块高密度矩形区域”。

原因有两层:一是负样本不足,训练集里正常行李图像太少,模型没见过足够多的笔记本电脑;二是标注类别设计不合理,把充电宝单独作为一个类,但它在X光下缺乏稳定纹理特征。

解决方法是双管齐下:在训练集里加入大量正常行李图作为纯背景负样本,同时把类别粒度重新审视,如果充电宝和笔记本的争议无法在数据上拉开,就考虑把“疑似含锂电池的电子设备”作为一个报警类别交给安检员二次判断,而不是强求算法区分。

5.2 现象二:显存不够导致训练中断

训练到第7个epoch时,直接报CUDA out of memory。我原本把imgsz设为1280,batch设为24,以为双卡能承担,实际算下来每张卡要处理12张1280分辨率的图,特征图显存占用远超预期。

原因很直接:YOLOv8在训练时会缓存图像做mosaic增强,分辨率和batch相乘是显存占用的主要因素,而不是单纯看batch大小。

解决方法是优先级明确的:如果显存不足,先降batch而不是降imgsz。安检小目标对分辨率敏感,imgsz降到640会直接损失检测能力,但batch从24降到8只是增加训练轮数和时间。还可以通过梯度累积来等效大batch,用yolo detect train命令里的batch=8和accumulate参数组合,让优化器每4个batch更新一次权重,等价于batch=32。

5.3 现象三:训练loss在下降但验证集mAP纹丝不动

这是最让人困惑的现象:train/box_loss和train/cls_loss都正常下降,val loss也同步下降,但mAP50始终在0.3附近徘徊。我最初以为是模型容量不够,换了大模型依然没有变化。

最终排查发现是验证集划分泄漏。原始数据集是从几个文件夹里按顺序拷贝的,前面80%是晴天采集的X光图,后面20%是阴天调低了设备参数后采集的图,两个子集的平均灰度差异明显。训练集和验证集分布不一致,模型在训练集上“学会”的统计特征在验证集上完全不成立。

解决方法是重新划分数据集。按设备参数、采集日期、物理站点分层抽样,保证训练集和验证集里都包含不同条件下的图像。之后我又加了一条硬性规定:任何新采集的数据,先按session编号分组,再按组划分,绝对不允许随机打乱整个文件列表。

5.4 现象四:导出ONNX后推理结果与PyTorch推理不一致

训练好的模型在PyTorch里检测效果很好,导出成ONNX并用onnxruntime部署后,同样的图框出来的坐标偏移了十几像素,置信度也变了。我第一反应是ONNX导出参数不对,反复检查导出配置无果。

真正原因是预处理不一致。PyTorch推理时,ultralytics源码会先做letterbox,把图像等比缩放到模型输入尺寸并填充灰度边,然后做BGR到RGB转换和归一化;而部署代码里我直接用了OpenCV读取的BGR图像,既没有做letterbox也没有归一化,等于把完全不同分布的数据送进了模型。

解决方法是把推理前处理统一抽成一个函数,PyTorch推理和ONNX推理共用同一份预处理代码,并用一张固定图对比两边的输出。另外在导出ONNX时如果输入尺寸固定为640,部署端也必须严格用640,不能图省事直接resize成其他尺寸。经过去掉空洞补丁之后,两条推理链路的输出才完全对齐。

6. 最后一公里:固定验证包、置信度阈值与现场数据回流

模型训练完成不等于项目交付,最后这一步是把模型从“验证集指标好看”变成“现场用起来可靠”。我现在的固定做法是三个动作,几乎可以复用在任何检测类项目上。

第一个动作是建一个固定验证包。准备100张包含危险品的正样本和300张纯正常行李的负样本,这些图不参与训练,独立存放在单独目录。每次模型更新后,对验证包统一跑一遍推理,记录两个数字:漏检率和误报率。漏检率是安检场景的第一红线,误报率决定安检员愿不愿意用。固定验证包的价值在于让每次模型改动都有可对比的基线,不会出现“感觉变好了但说不出好多少”的情况。

第二个动作是用P-R曲线选置信度阈值,而不是默认用0.25。检测模型在安检场景里往往需要更保守的策略:把置信度阈值从0.25提高到0.4,可以把误报率降一半,漏检率只增加两三个百分点。这个取舍需要根据现场接受度决定,做法是在验证包上逐步扫描conf从0.1到0.5,画出每个阈值下的漏检率和误报率折线,再选业务上能接受的那个点。

第三个动作是现场数据回流与增量微调。安检机每天产生的图片里,人工复核后标记为漏检或误报的图,是最宝贵的训练数据。每周把这些图按前面第3章的标注规范补标签,并入训练集做增量训练,学习率打到0.0005即可。这样模型会随着设备使用持续进化,而不是交付那天就是它的最好状态。

这三件事里,固定验证包最容易被忽略,但对项目长期维护价值最大。说实话,这类项目毁在“算法精度刷得很高但现场跑不稳”的情况我见过太多次,现在接手任何检测项目我都先搭验证包再谈调参。希望帮到你。

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

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

工业存储选型:用MRAM解决EEPROM与Flash的寿命和写入痛点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 2:36:39

目标检测后处理核心:NMS原理、实现与优化详解

最近在折腾检测模型后处理的时候&#xff0c;有好几个朋友问我&#xff1a;NMS到底是怎么把一个目标周围那一堆框收敛成一个的&#xff1f;其实NMS&#xff08;Non-Maximum Suppression&#xff0c;非极大值抑制&#xff09;这个算法&#xff0c;是目标检测里最不起眼却又最关键…

作者头像 李华
网站建设 2026/10/4 2:36:01

MR25H40CDF + STM32F215ZG:SPI MRAM实现工业数据掉电保存

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 2:34:43

MRAM×PIC24EP:高频数据记录与掉电不丢的工业存储方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 2:33:18

Conda虚拟环境中pip安装包路径错乱?一文厘清conda与pip的安装机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 2:32:08

接口自动化测试数据构造全攻略:从静态数据到Mock与加密

接口自动化做了几年&#xff0c;踩过最多的坑不是框架选型&#xff0c;不是断言写法&#xff0c;而是测试数据的构造。很多项目自动化用例写了一大堆&#xff0c;跑起来全是红的&#xff0c;一看日志全是数据问题——要么订单状态不对&#xff0c;要么token过期&#xff0c;要么…

作者头像 李华