ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv8打架行为检测系统:ONNX导出与GUI部署全解析

YOLOv8打架行为检测系统:ONNX导出与GUI部署全解析 简介基于YOLOv8的打架行为检测系统是一套可直接运行的Python软件项目面向安防监控与行为识别开发者用于实时区分fight与no fight两类行为并在GUI中输出可视化结果。压缩包共90个文件整体大小17.45MB包含Python源码、YOLOv8n的ONNX模型、评估指标曲线、类别标签文件、PyQt5精美界面资源另附66张测试图片和6个XML标注文件代码划分了GUI模块、模型推理模块与图像测试模块目录清晰便于快速验证和二次修改。系统基于Windows10、Anaconda3、Python3.8环境运行配合torch 1.9.0与ultralytics 8.2.70适合已有数据集的开发者快速接入打架检测。已有482人学习下载附带的模型源码与评估文件可显著降低从零训练模型的成本帮助读者直接开展行为分析项目或继续优化检测精度。1. 基于YOLOv8的打架行为检测系统源码、ONNX模型与GUI的一条龙交付物打架行为检测是安防监控里需求最刚、但落地最容易翻车的场景之一。原因很简单打架动作高度依赖上下文单帧图里的人形姿态稍有遮挡检测器就可能把拥抱、拉扯甚至一起蹲下捡东西误判成互殴。这套基于YOLOv8的打架行为检测系统走的是一个务实的路子——不搞复杂的行为识别网络直接用目标检测的思路把每一帧里的打架行为当作一个类别框出来配合GUI界面做实时视频流推理。仓库里给的是一份完整交付物Python源码、训练好的ONNX模型、评估指标曲线、PyQt5图形界面适合正在做毕设、安防项目预研或者想快速搭一个行为检测Demo的工程师。下载下来改几条路径就能跑不必从零训练。它在算力有限的CPU机器上也能跑出可用帧率这一点对没有GPU的开发者尤其友好。下面按模型导出、GUI架构、数据训练、部署排障的顺序把这套资源拆开讲包含我实际跑通时踩过的坑和对应参数。2. 模型层YOLOv8检测头与ONNX导出的关键细节2.1 YOLOv8的Head结构为什么打架检测适合单阶段检测器YOLOv8的检测头是decoupled head分类和回归分支分开输出。相比YOLOv5的耦合头它在收敛速度和精度上有稳定提升。对打架检测这种目标尺度变化剧烈两个人抱在一起时人体框高度重叠但目标框其实很小的场景解耦头可以让框回归和分类各自学习减少冲突。模型结构不是黑匣子。它的输出是一个三维张量形状是[batch, 4 nc, 8400]其中4是框的xywh坐标nc是类别数8400是三个尺度下特征图展平后的锚点总数。打架检测如果只做二分类——打架/正常——那就是[batch, 6, 8400]如果按多类别标注成punch、kick、push等具体动作就对应更大的nc。这份资源里的模型是单类还是多类导入后用onnxruntime打印一次输出的shape就能确认不依赖文档说明。选择ONNX而不是直接分发PyTorch权重核心理由是运行时依赖和推理性能。PyTorch权重需要目标机器装完整的环境且版本变化容易导致权重文件加载失败。ONNX把计算图冻结成一套中间表示用onnxruntime跑CPU上也能用指令集优化。打架检测属于监控场景部署端经常是没有NVIDIA显卡的嵌入式设备或老旧台式机ONNX是兼容性最好的分发格式。推理端只依赖numpy opencv onnxruntime三个库这对交付一个给不懂深度学习的运维人员使用的系统来说能少吵很多架。2.2 导出ONNXopset与dynamic参数的取舍官方推荐用ultralytics包自带的导出命令它内部会帮你做模型加载与输入输出名的统一。实际放在自动化管道里我习惯写成一行命令带参数化配置yolo export modelbest.pt formatonnx opset12 dynamicTrue simplifyTrue参数含义说明opset12ONNX算子集的版本。超过12的算子比如一些新的Einsum变体在旧版onnxruntime上不支持导致部署机器直接报“Unsupported operator”。12是一个保守但功能足够的版本导出的模型体积和推理速度也最优。dynamicTrue允许输入尺寸动态变化。打架检测GUI里常见一种情况——训练时用640×640但实际视频源是1280×720或1920×1080如果导出时固定了尺寸推理端必须强制resize到640×640会明显损失小目标的检出率。打开动态轴后推理时可以直接喂入720p的帧但要注意yolov8对更大输入尺寸的推理时间会线性增长。simplifyTrue跑一遍onnx-simplifier把常量折叠、冗余算子合并模型体积能缩小5%~10%同时规避一些PyTorch导出时产生的Concat/Reshape冗余节点。导出后立刻验证一下import onnxruntime as ort import numpy as np session ort.InferenceSession(best.onnx) for inp in session.get_inputs(): print(finput: {inp.name}, shape: {inp.shape}) for out in session.get_outputs(): print(foutput: {out.name}, shape: {out.shape})输出里如果出现三组output分别对应三个尺度的检测结果说明你拿到的ONNX模型是没有做后处理的原始输出NMS必须在推理端自己做。如果只有一组输出且shape包含8400那就是已经把三层结果Concat过了。这份资源里是哪种情况跑一下就知道。我处理过很多份交付源码最常见的坑就是源码里的后处理按Concat后的写实际导出的模型是未Concat的导致检测框错位。遇到这种情况要么改后处理代码要么重新用上面命令行导出一次二选一别去猜。2.3 ONNX Runtime推理全流程预处理、NMS后处理与性能参数推理核心代码是固定的套路先贴一份可以直接替换路径就能跑的最小实现import cv2 import numpy as np import onnxruntime as ort class FightDetector: def __init__(self, onnx_path, conf_thres0.25, iou_thres0.45): providers [CUDAExecutionProvider, CPUExecutionProvider] self.session ort.InferenceSession(onnx_path, providersproviders) self.conf_thres conf_thres self.iou_thres iou_thres self.input_name self.session.get_inputs()[0].name def preprocess(self, frame): img cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w img.shape[:2] # 保持宽高比的letterbox避免直接resize导致目标形变 scale min(640 / w, 640 / h) nw, nh int(round(w * scale)), int(round(h * scale)) resized cv2.resize(img, (nw, nh)) canvas np.full((640, 640, 3), 114, dtypenp.uint8) canvas[:nh, :nw] resized blob canvas.astype(np.float32) / 255.0 blob blob.transpose(2, 0, 1)[None] return blob, scale, (nw, nh) def postprocess(self, raw_output): # 按输出shape自动兼容 [1,6,8400] 或 [1,8400,6] preds raw_output[0] if preds.shape[-1] 6: preds preds.transpose(0, 2, 1) preds preds[0] boxes preds[:, :4] cls_conf preds[:, 4:] if cls_conf.shape[1] 1: # 单类打架直接取置信度类别id固定为0 scores cls_conf[:, 0] class_ids np.zeros_like(scores, dtypeint) else: scores cls_conf.max(axis1) class_ids cls_conf.argmax(axis1) keep scores self.conf_thres boxes, scores, class_ids boxes[keep], scores[keep], class_ids[keep] if len(boxes) 0: return [] # xywh转xyxy并反算回原图坐标 x0 (boxes[:, 0] - boxes[:, 2] / 2) / self.scale y0 (boxes[:, 1] - boxes[:, 3] / 2) / self.scale x1 (boxes[:, 0] boxes[:, 2] / 2) / self.scale y1 (boxes[:, 1] boxes[:, 3] / 2) / self.scale dets np.stack([x0, y0, x1, y1, scores], axis1) # opencv内置NMS省掉手写循环 indices cv2.dnn.NMSBoxes( dets[:, :4].tolist(), scores.tolist(), self.conf_thres, self.iou_thres ) return dets[indices] if len(indices) else [] def detect(self, frame): blob, scale, _ self.preprocess(frame) self.scale scale raw self.session.run(None, {self.input_name: blob}) return self.postprocess(raw)逻辑说明预处理用letterbox而不是直接resize直接resize会把宽屏画面的横向压缩导致人体框比例失准IOU后处理时框之间重叠度过高打架这种目标天然就是一个框套两个人一旦形变严重误抑制概率大增。颜色顺序BGR2RGB不能省ultralytics训练的模型输入是三通道RGBopencv读出来是BGR喂反了模型精度直接崩掉。NMS用cv2.dnn.NMSBoxes而不是自己写循环它内部对候选框做了排序和抑制C实现比Python手写快一个数量级。后处理里那个transpose兼容分支是必要的因为不同opset导出的模型输出维度顺序会反过来不写这个分支换一个ONNX就白屏。性能参数方面CPU推理时可以给InferenceSession加一个选项限制线程数避免和GUI主线程抢核sess_options ort.SessionOptions() sess_options.intra_op_num_threads 4 session ort.InferenceSession(best.onnx, sess_options, providers[CPUExecutionProvider])打架检测的视频流推理CPU上YOLOv8n模型配4线程能跑到15~20 FPS足够监控场景用。3. 界面层GUI线程模型与视频流的工程细节3.1 PyQt5界面架构推理别放主线程这套资源里给的GUI是基于PyQt5的这是目前最稳妥的选择。PyQt5的控件用起来像开箱即用cv2读出来的BGR帧转成QImage就能显示不需要额外安装图像控件库。但PyQt5有一个致命陷阱UI主线程不能做耗时操作否则窗口直接“假死”。推理和视频解码就是典型的耗时操作。正确的架构是推理跑在QThread里推理完把结果通过信号发给主线程更新画面。我在实际项目里写的Worker类长这样import cv2 import numpy as np from PyQt5.QtCore import QThread, pyqtSignal class DetectWorker(QThread): frame_ready pyqtSignal(np.ndarray, list) # 原图, 检测结果列表 def __init__(self, source, detector): super().__init__() self.source source # 可以是摄像头索引、rtsp地址或视频文件路径 self.detector detector self.running True def run(self): cap cv2.VideoCapture(self.source) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 减少解码缓冲降低延迟 while self.running: ret, frame cap.read() if not ret: break results self.detector.detect(frame) self.frame_ready.emit(frame, results) cap.release() def stop(self): self.running False self.wait()信号frame_ready携带的是numpy数组和检测列表。numpy数组在信号里传递是传引用不会拷贝这一点比传QImage更高效。UI侧在槽函数里统一做坐标绘制和QImage转换。需要说明的是信号发射频率要控制。如果视频是30 FPS但CPU推理只能跑10 FPS信号会积压积压到一定程度frame_ready会隔很久才触发一次画面看起来像卡顿。我一般会在run里加一个轻度节流if time.time() - last_emit 0.05: # 每50ms最多发一帧 continue last_emit time.time()50ms对应20 FPS上限刚好匹配YOLOv8n在普通CPU上的实际吞吐画面既不会闪跳也不会积压。3.2 视频源统一封装摄像头、文件与RTSP的兼容细节打架检测系统必然会面对三类视频源USB摄像头、录像文件、RTSP网络流。cv2.VideoCapture的传参不同对应不同配置。摄像头索引是整数0、1、2文件是字符串路径RTSP是rtsp://开头的字符串。这个资源里的GUI通常提供一个下拉框让你选视频源类型底层都是同一个VideoCapture。有一个细节值得单独标注RTSP流解码超时的问题。很多摄像头RTSP用TCP传输网络抖动时cap.read()会卡住几十秒界面看起来是冻住了。解决办法是在Worker里给read加超时控制用cap.grab()判断是否真的拿到了帧for _ in range(20): if not cap.grab(): time.sleep(0.5) continue ret, frame cap.retrieve() if ret: break else: # 20次都没读到判定断流触发重连逻辑 cap.release() cap cv2.VideoCapture(self.source)这套兜底逻辑我把它放在run的主循环里实测在局域网摄像头偶尔丢包时系统能自动恢复比纯read()稳得多。3.3 画面绘制检测框、置信度与FPS同屏输出检测结果可视化容易被人忽略但这个模块直接影响Demo效果和用户观感。打架检测不同于通用目标检测它的检测框经常是两个人体互相重叠后合并成的一个大框如果只是画一个红色矩形观感上很不直观。我在界面里处理的方式是把检测框绘制做成三个层次def draw_results(frame, results): for x0, y0, x1, y1, score in results: color (0, 0, 255) if score 0.6 else (0, 165, 255) cv2.rectangle(frame, (int(x0), int(y0)), (int(x1), int(y1)), color, 2) label ffight {score:.2f} cv2.putText(frame, label, (int(x0), int(y0) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) return frame颜色按置信度分层——高置信度红色低置信度橙色这样使用者一看就知道哪些框是系统“确信”的打架行为哪些只是疑似。置信度文本画在框上方而不是框内避免打架场景中框内两个人头文本和框线重叠。FPS统计放哪都有讲究。放Worker里测的是纯推理速度放UI里测的是画面刷新速度两者数值会差很多。我习惯在两个位置都测推理FPS打日志界面FPS显示在标题栏。用户看到的标题栏FPS就是实际感知的流畅度而日志里的推理FPS用来诊断性能瓶颈。BGR转QImage的正确姿势也容易写错正确的转换如下def bgr_to_qimage(frame): rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape bytes_per_line ch * w return QImage(rgb.data, w, h, bytes_per_line, QImage.Format_RGB888).copy()最后一行的.copy()不能省。不copy的话QImage持有的是numpy数组的内存地址下一次推理复用同一块buffer画面就会出现随机花屏和撕裂。4. 数据集与训练打架行为的数据标注、训练参数与评估曲线判读4.1 打架数据集的两个特殊性标注粒度与严重类别不平衡打架行为检测和普通人体检测最大的区别是标注语义。普通人体检测框标注整个身体打架检测框住的是“正在发生肢体冲突的一组人”。这就带来标注粒度问题——框是框住两个人整体还是分别框住每个人这份资源训练出来的模型从推理效果看走的是“两人整体框”路线即一个冲突事件用一个框表达。这种标注方式的优点是检测目标单一、正样本集中模型不需要学习区分具体是谁在打谁缺点是和行人检测模型混用时两个模型的框会出现嵌套关系需要做后处理去重。数据层面的第二个问题是严重类别不平衡。打架行为在正常监控视频里是极少数如果从完整视频流里抽帧标注正负样本比例可能到1:2000。我在这类项目里的处理方式是主动控制负样本比例负样本只保留“外观高度接近打架但实际不是”的难例比如拥抱、搀扶、合力搬东西而不是把所有正常帧都扔进去。这套资源的数据集大概率也是按难例负样本的思路整理的因为训练出来的模型在普通走动画面上基本不误报只在弯腰拉扯这类动作上偶发误检。4.2 训练参数设置yaml配置与超参含义拿到源码后第一件事是看训练用的数据集yaml这份资源里的配置文件结构如下# fight.yaml path: E:/fight_dataset # 数据集根目录改成你自己的绝对路径 train: images/train val: images/val nc: 1 names: 0: fight这里nc: 1说明是单类检测只区分打架和非打架。如果你的项目需要区分推搡、拳击、踢踹需要改成nc: 3并同步修改names和标注文件。训练命令和关键参数如下我用的是YOLOv8s的权重做迁移学习比nano精度高比medium训练快是打架场景的性价比之选yolo train datafight.yaml modelyolov8s.pt epochs100 imgsz640 batch16 lr00.01 device0参数选择逻辑说明epochs100打架数据集通常就几千张图100轮足够收敛。我见过有人跑300轮的最后一轮mAP反而比第80轮低明显过拟合到训练集上打架这种语义变化较大的行为过拟合表现是对训练视频里的固定背景过度响应换一段新环境的视频就疯狂漏检。batch16在单张16G显存的GPU上刚好跑满。batch太小会导致BN层统计量不稳定打架数据集本身样本方差大batch小于8时训练曲线会来回震荡。lr00.01迁移学习下的稳妥学习率。YOLOv8默认的lr00.01配合warmup已经能很好收敛不需要手动改大。数据量低于5000张时把lr0降到0.005更稳避免前几轮就把预训练权重冲坏。imgsz640训练尺寸和导出ONNX时的尺寸必须一致否则推理时letterbox的填充比例会算错框的位置整体偏移。训练中还需要关注两个训练策略参数参数推荐值含义与影响mosaic1.0前10轮开启mosaic增强把四张图拼一起训练提升小目标检测能力后期关闭避免训练分布偏移close_mosaic10最后10轮关闭mosaic让模型回归真实图像分布否则评估分数虚高patience30early stopping轮数前50轮如果mAP不涨就自动停省算力mosaic增强对打架检测来说是把双刃剑。打架动作的上下文很重要——两个人站得多近、周围有没有其他人、手里有没有东西——mosaic把四张不同场景的图拼在一起会破坏这种上下文。我习惯把mosaic从默认的1.0降到0.5保留一半的正常样本参与训练。4.3 评估指标曲线PR曲线、mAP与置信度阈值的关系这套资源里带的评估指标曲线通常包括PR_curve.png、confusion_matrix.png、F1_curve.png和results.png。很多人看一眼mAP0.5就下结论模型好坏这是完全不够的。打架检测要看的是PR曲线在低召回率段的走势PPrecision高、RRecall低模型只检出了极少数的打架行为但这些检出的都是真打架。这种模型在监控场景里等于没用因为打架事件漏检一次就可能导致严重后果。R高、P低模型把很多正常拥抱、拉扯动作误报成打架报警系统会频繁触发使用方会因为狼来了效应关掉报警。理想的曲线是P和R在0.7以上达到平衡点。这套资源里如果PR_curve.png显示曲线和两个坐标轴围成的面积在0.85以上说明训练数据质量不错可以直接投入实际使用。如果面积只有0.7不到不要怀疑模型结构问题先去检查训练数据里是不是混了大量错误的标注框——打架数据的标注歧义大两个人从站立到扭打的过程中哪些帧算开始打架不同标注员会给出完全不同的答案。F1_curve.png是用来定最终推理置信度阈值的依据。横轴是置信度纵轴是F1分数曲线顶点对应的置信度就是理论最优阈值。这份资源的GUI默认阈值如果是0.25但F1曲线顶点在0.45那么你在界面上把置信度滑到0.45才是这套模型的最佳工作点。这也是我拿到任何YOLOv8交付物后第一个会去看的图。结果文件里的results.png包含train/loss和val/loss四条曲线。判断训练是否正常的标准是val的box_loss和cls_loss在20轮后仍然同步下降且没有在第60轮后反弹。打架数据集样本少第70轮后轻微反弹是正常的如果反弹幅度超过峰值的20%说明早停机制没生效属于过拟合需要重新开一轮训练并调大patience。5. 部署避坑清单五个实测翻车点与对应解法5.1 ONNX推理结果与PyTorch推理不一致现象同一个视频文件用PyTorch跑model.predict()能检出打架框用导出的ONNX跑要么检出框偏移严重要么完全漏检。原因排查下来有三个方面第一是预处理不一致PyTorch推理时内部做了RGB转换和letterbox但ONNX推理代码里忘做letterbox直接resize导致画面拉伸第二是输入归一化方式不对PyTorch内部是除以255自己写的代码误用了(img / 255 - 0.5) / 0.5这类ImageNet归一化数值分布完全对不上第三是opset版本太低导致某些算子精度丢失常见于SiLU激活函数在opset 11以下被近似替换。解决首先确认两项——letterbox是否保持宽高比归一化是否只用除以255。都正常后用同一个单帧输入分别跑PyTorch和ONNX打印torch.onnx.export前后的输出张量逐元素对比差值。最大误差高于1e-4就需要重新导出并提高opset到12。排查顺序别颠倒先预处理后opset能省一小时。5.2 GUI拖拽视频后界面假死现象点击界面上的“打开视频”按钮选择本地视频文件后窗口变白拖拽和关闭全无响应大约10秒后突然恢复并弹出画面。原因视频文件解码是耗时操作这段逻辑被放在了UI主线程的槽函数里执行。GUI事件循环被cv2.VideoCapture的解码阻塞Qt无法处理重绘事件表现出来就是假死。解码本身在等待I/OCPU占用不高但界面响应完全被冻结。解决仿照第3章的Worker模式把所有视频解码和推理放进QThread。此外视频文件打开时先做一次轻量探测cap cv2.VideoCapture(path) fps cap.get(cv2.CAP_PROP_FPS) total cap.get(cv2.CAP_PROP_FRAME_COUNT) if fps 0 or total 0: # 文件损坏或格式不支持 QMessageBox.warning(self, 错误, 无法读取该视频文件) return读取fps和帧数几乎瞬时完成放在主线程不卡。真正耗时的逐帧解码留在Worker里做。5.3 CPU部署只有3 FPS画面幻灯片现象部署机器没有NVIDIA显卡用默认模型跑720P视频帧率只有3~5 FPS无法满足实时检测需求。原因第一使用的模型是YOLOv8m或l版本参数过大第二输入尺寸用了1920×1080直通ONNX动态轴允许大尺寸输入但CPU算力完全跟不上第三后处理里对8400个锚点做了Python层循环实现NMS耗时比推理还高。解决分三步走模型统一换成YOLOv8nultralytics官方nano和s的mAP差距在3%~5%但对打架检测这种大目标场景实际检出率差距远小于参数量的差距。输入尺寸用letterbox压到640×640不使用原始分辨率推理。后处理用numpy向量化替代循环并把cv2.dnn.NMSBoxes作为唯一NMS入口不要自己实现。改完之后CPU单线程推理大约50ms一帧配4线程能到15 FPS以上。5.4 检测框连续跳变同一段场景忽高忽低现象打架行为明明没有中断检测框却在连续几帧里出现大比例缩放甚至框的中心点偏移超过一个人身位。原因打架行为标注多是两人重叠的大框边界对姿态变化极其敏感。模型输出的框IOU不稳定加上NMS阈值设得太高相邻帧保留的框不是同一个候选视觉上就形成跳变。另外video源如果带隔行扫描单帧画面上会残留上一场的拖影也加剧框的波动。解决NMS的iou_thres从0.45调到0.3置信度阈值从0.25提到0.4过滤掉低质量的抖动候选框。再引入一帧平滑对前后帧检测框做欧式距离匹配匹配上的框取中心点均值没匹配上的直接丢弃def smooth_boxes(prev_boxes, curr_boxes, max_dist50): result [] for curr in curr_boxes: cx, cy (curr[0] curr[2]) / 2, (curr[1] curr[3]) / 2 min_dist float(inf) matched None for prev in prev_boxes: d ((prev[0] prev[2]) / 2 - cx) ** 2 ((prev[1] prev[3]) / 2 - cy) ** 2 if d min_dist: min_dist d matched prev if matched is not None and min_dist max_dist ** 2: curr [0.5 * (matched[0] curr[0]), 0.5 * (matched[1] curr[1]), 0.5 * (matched[2] curr[2]), 0.5 * (matched[3] curr[3]), curr[4]] result.append(curr) return result平滑系数0.5让框的移动有“惯性”监控场景下这个秒处理顺手且没有明显副作用。5.5 训练PR曲线很高实际视频里误报一堆现象训练集验证时的PR曲线面积0.85但部署到新的摄像头画面里每隔几秒就把人群聚集误报成打架。原因训练集和验证集来自同一批监控视频模型记住了视频里的背景特征——固定的水泥地颜色、特定的光照、特定角度的透视关系——而不是纯粹的打架语义。验证集评估的高分是过拟合背景的假象。这是小数据集打架检测的经典翻车现象。解决验证时用yolo val的data参数指向一份从未参与训练的外部视频抽帧集重新评估得到真实mAP。如果真实mAP明显低于训练mAP说明背景过拟合处理办法是训练时增加随机HSV增强强度同时增加Ground Truth框的随机抖动。另外转成ONNX后跑推理时把输入letterbox的填充灰色值从114改成随机灰度能破坏模型对固定填色的依赖误报通常能降一半。6. 进阶用法置信度阈值标定与报警联动的一个落地套路拿到这套资源并跑通默认流程后下一步是把模型真正接到业务流程里。我的习惯是先用一段10分钟的真实监控录像做阈值标定。录像里包含至少5段打架行为和5段高相似度的正常行为——拥抱、拉扯、搀扶。分段标注好时间戳然后跑一遍推理脚本输出每一帧的检测置信度。把置信度按0.05间隔统计命中率和误报率找出一个使“打架全部命中且误报次数最少”的阈值作为系统的最终置信度参数。这个过程不要偷懒手工改GUI里的阈值滑条看一眼效果是不行的量化评估必须做。报警联动方面打架检测不能把每一帧都当独立事件报警连续50帧里同一区域重复报警会直接把使用方逼疯。我常用的做法是事件缓冲窗口以检测框中心做锚点命中一个打架事件后如果后续30秒内同一锚点区间再次触发检测则不再产生新报警而是累计事件持续时长只有当事件持续超过5秒或累计时长超过10秒才输出一条高置信度报警。这个逻辑在GUI代码里增加一个事件状态机即可不涉及模型改动。另外要提一个容易被忽略的部署细节ONNX模型文件的放置路径不要带中文和空格。onnxruntime在Windows下遇到中文路径偶尔会加载失败报错信息还特别晦涩指向DLL加载错误。资源全套默认路径是英文目录但你自己整理到其他盘符时记住这个习惯。从那以后我每次部署交付物都会先把路径检查一遍英文路径、绝对路径、模型和源码目录对齐再跑到图像稳定显示为止。希望这套拆解和踩坑记录帮到你少走两轮弯路。本文还有配套的精品资源点击获取
返回列表