ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

无人机视角下高速公路违章检测:目标检测、跟踪与规则判定实战

无人机视角下高速公路违章检测:目标检测、跟踪与规则判定实战 简介面向无人机巡检与高速公路违章检测的完整项目源码包定位为计算机视觉方向的工程实战参考适合算法工程师、交通信息化开发者及有一定基础的学习者。项目以YOLOv3为检测主干结合Deep SORT多目标跟踪逻辑覆盖图像预处理、车辆检测、车道识别、超速与占用应急车道等违章行为判断环节同时包含训练配置、模型权重和推理所需文件便于从数据输入到检测结果完整跑通。资源包共103个文件47个Python脚本用于流程控制和算法实现29个pyc文件为编译生成模块另有4个XML文件、3个ipynb演示笔记、模型配置文件及道路与检测效果图片素材压缩后约21.97MB结构清晰且便于二次开发。已有420人学习下载适合希望理解目标检测与多目标跟踪在真实场景落地的读者。1. 无人机视角的高速公路违章检测到底比固定摄像头难在哪节假日高速一堵应急车道、导流区和弯道就成了人工和杆件摄像头的双重盲区。把巡检无人机拉起来补位是目前智慧交通里落地最多、也最能直接见效的方向。这篇笔记要讲的这套高速公路违章检测算法核心是把无人机巡检视频里的车辆目标变成“占用应急车道、违停、逆行”这类可直接上报的事件而不是只输出一堆检测框。很多人觉得无人机视角只是把地面监控算法换个输入源其实差别很大地面摄像头里车辆通常占画面十分之一无人机在60到150米高度俯拍一辆轿车常常只有几十个像素固定点位可以画ROI判违章无人机在飞视角在变算法结构和阈值体系都要重设计。适合正在做地面交通检测想迁到无人机场景的工程师也适合刚接触无人机视觉感知、想跑通完整项目的新手。看完至少能少走我走过的弯路。2. 任务拆解与算法选型违章检测不是单一模型而是一条感知链路2.1 从“看到车”到“判定违章”检测、跟踪与行为规则的分工违章行为本质上是一个时空语义问题不是静态画面能直接判断的。一辆车停在应急车道上单帧画面里它和一辆缓行的车没有区别只有把连续十几帧串起来看它有没有位移才能下结论。所以我把这套系统拆成三块目标检测负责空间定位多目标跟踪负责时间关联规则判定负责业务解释。检测网络输出的是“哪里有车、是什么车”跟踪器把前后帧的同一个车绑定成一个轨迹最后由一段带业务逻辑的规则代码按“轨迹是否移动、是否在应急车道ROI内、持续了多久”来生成违章事件。我习惯把行为规则和检测模型分开而不是训练一个端到端的“违停分类网络”。原因有两个一是这类违章的样本天然稀有一个路段一个月可能只有几次分类网络很难学够二是规则可以被审查和微调交警和业主方问“你为什么判定这是违停”时你拿轨迹和阈值就能说清楚黑匣子模型没法交代。规则代码也便宜一行if就能改重新训练模型的成本就大了。这个分工决定了后面每一步怎么做所以放在最前面讲。这里有个很容易犯的错把违章检测当成一个分类任务给模型加一个“违章”类别去训练。我见过不少团队这么干结果上线一周就崩溃。原因很简单标注阶段“违停车辆”和“正常车辆”的边界在无人机俯视视角下模棱两可两个类别在特征空间高度重叠更不用说“占用应急车道”基本无法用静态类别表达。检测器只输出实体行为交给时序规则这套边界如果一开始没有守住后面数据增强和调参都会变形。2.2 平台约束倒逼算法选型算力、尺度与无人机飞控的匹配算法选型不只是选模型先看机载平台的约束。巡检无人机常见的是商用机挂载边缘计算盒子Jetson、昇腾NPU之类或者把视频通过图传链路回传地面站处理。机载方案要求模型轻量回传方案要求链路带宽和时延控制但两者对算法的约束方向是一样的目标尺度小、场景光照变化大、抖动频繁。检测模型我会优先选YOLO系列里能在边缘设备上跑得动的轻量版本而不是一上来就上大模型。FLOPs低不代表端到端快还要看推理框架对算子的支持程度。跟踪器在ByteTrack和DeepSORT之间我多数场景选ByteTrack无人机视角下目标经常被遮挡、检测置信度波动大ByteTrack对低分检测框更宽容ID切换比DeepSORT少一些DeepSORT有外观特征做二次匹配适合目标密集且外观稳定的场景代价是要多调一个特征提取器在轻量设备上不划算。下面是这套任务里我常用的选型对应关系。环节常见做法理由注意点目标检测YOLO轻量系列、小目标友好的变体精度/速度平衡好边缘设备部署成熟只追求mAP会选成大模型端上跑不动多目标跟踪ByteTrack / DeepSORT无人机视角遮挡多低分框处理要稳目标密集时DeepSORT更稳但要调外观特征行为判定规则状态机违章定义清楚可审计不要用LSTM硬套样本少且难解释任务调度航线分段定点悬停配合无人机路径规划的拍照节奏连续推流时算法跟不上就改成定时抓拍这个表里最后一行容易被忽略。巡检无人机不会像地面摄像头一样24小时连续盯着一个点它的任务调度是由无人机路径规划来定的升空、巡航、悬停、返航。很多团队算法做完了挂在机载设备上一测发现帧率不够于是开始换轻量模型其实更划算的做法是调整采集策略——把连续视频流改成关键点位悬停抓拍几秒既降低算法压力又天然对齐“停车持续N秒”的判定条件。另外选检测模型时我会关注特征金字塔结构不只是看参数量。无人机画面的小目标问题很突出标准模型的特征图下采样倍数从8倍起步一个30像素的车在P3层上只有不到4个像素特征已经非常稀薄。优先选带有更高分辨率特征输出比如P2层的变体或者自己改检测头把浅层特征接进来。输入分辨率也要同步提高这是后面第四章会展开的参数但在选型阶段就要预留这种可能性。2.3 先定性能预算再定模型帧率、时延与检测精度的三角关系有时我接手一个项目对方第一句话是“我要99%准确率”。做无人机的都知道这是不可能的因为帧率、时延和精度三者互相牵制。先做一个简单估算机载边缘设备上跑一个640输入的单阶段检测器推理大概在20到40毫秒跟踪器再吃掉几毫秒整条链路帧率能到15到25帧如果把输入分辨率提到1280推理时延可能翻一倍帧率掉到10帧以下。违章判定里的“持续停了多少秒”依赖帧率帧率太低停车事件的时间戳就不准。所以我的做法是先定业务指标再选模型要求违停检测的时间误差在3秒以内按15帧算判定窗口至少要留45帧的余量要求无人机巡检一个标准路段在10分钟内飞完那么单帧处理时延不能超过80毫秒。把这些数字写进需求文档再去挑模型而不是先在排行榜上找第一名。这个顺序反过来的话后面所有调参都会被性能预算卡死前期的模型选型就白做了。无人机视角还有一个地面监控不常遇到的麻烦相机姿态不是恒定的。巡检时无人机会因风向、飞控调姿产生偏航和横滚画面里的车道方向、车辆朝向都在缓慢旋转。地面监控的模型见过大量水平视角的车到了俯视场景车的长宽比和特征分布都变了同一个车可能是0度也可能是45度方向出现。所以数据增强里旋转不要只做小角度训练时要把大角度旋转和透视变换放进去同时这也意味着你不能依赖“车头朝左就是逆行”这种简单的图像判断必须回归到轨迹方向。这部分我在第三章的数据策略里展开。3. 数据准备把无人机航拍整理成算法能学懂的标注格式3.1 数据来源与标注策略先标“车”再标“上下文”训练数据通常有两个来源。第一是自采用带差分定位的无人机在自己负责的高速路段飞几趟收集不同时段、不同天气、不同高度的视频这是最贴近实际场景的数据也是决定算法在你这儿能不能用的关键。第二是公开数据集像UAVDT、DroneVehicle这类学术上常见的无人机车辆数据集名字可以直接检索它们的场景和拍摄姿态可以作为预训练或补充数据。公开数据好拿但要注意它的地理环境和拍摄高度未必和你一致直接当成主力数据训练会导致上线后水土不服。标注策略上我坚持一个原则标注对象是“车”不是“违章”。比如一辆车停在应急车道上标注脚本里只标一个“车辆”框最多加一个“双闪/事故停驶”的属性而不是单独建一个“违停车辆”类别。前面2.1已经说过行为语义用规则判断比用分类网络判断靠谱标注上也一样如果类别里出现“违停车辆”和“正常行驶车辆”标注员自己都会打架同一辆车换个角度就换类别最后交回来的标注数据噪声极大。但“标什么”不完全只有车辆本身还要标上下文。上下文不是指背景分割而是指给后续规则用的地理语义应急车道边界线、车道分隔线、导流区等我习惯在数据集目录里额外存一份ROI配置把路段走向、主车道方向、应急车道区域用折线先画好。这些折线与检测框更配因为违章判定规则比如“车在应急车道区域内”需要它们在固定的地理坐标系里而不是每一帧都靠模型现场找。3.2 VOC/JSON转YOLO标注格式转换脚本与坐标边界坑拿到标注后第一件事是转格式。标注软件导出的是VOC的XML或LabelMe的JSON而训练框架通常要YOLO格式的txt每行一个目标五个数字分别是类别索引、归一化中心点x、归一化中心点y、归一化宽、归一化高。写一个VOC转YOLO的小脚本# voc2yolo.py # 将Pascal VOC XML标注转为YOLO txt标注 import xml.etree.ElementTree as ET class_map {car: 0, truck: 1, bus: 2} # 按你的工程实际调整 def convert_voc(xml_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 注意像素坐标系y轴向下y2可能小于y1要取绝对值 w abs(x2 - x1) h abs(y2 - y1) if w 1 or h 1: continue cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h nw w / img_w nh h / img_h # 越界防御个别标注框超出画面边界时做clip cx, cy, nw, nh clip_coords(cx, cy, nw, nh) lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) def clip_coords(cx, cy, nw, nh): # 把归一化坐标限制在[0,1]内 cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) nw min(max(nw, 0.0), 1.0) nh min(max(nh, 0.0), 1.0) return cx, cy, nw, nh这段代码有三个容易翻车的地方我每次写都提醒自己。第一y坐标方向图像坐标系y轴向下如果标注工具记录的ymax比ymin小直接把y2减y1会得到负的框高训练时要么报错要么框消失所以上面统一取abs。第二归一化时中心点用的是(x1x2)/2除以图像宽宽是abs(x2-x1)除以图像宽很多人会把宽高写反或者把中心点坐标除以框宽出来的标注全部偏移画框时才发现。第三越界目标无人机视角里目标经常出现在画面边缘标注框可能超出图像边界转出来的归一化坐标会大于1或小于0训练框架在mosaic增强时会出nan上面顺手做了clip。3.3 数据增强与切图小目标场景的标配操作无人机视频最典型的问题是目标小整张4K画面直接resize到训练分辨率通常是1280或640一辆轿车占几个像素模型几乎没有特征可以学。常见做法是先把大图切成patch再做mosaic等增强。切图有两个参数要调patch大小和重叠率。patch太小车辆目标被切成两半标注框大量丢失重叠率太低跨patch的目标上下文信息不足。我一般用1280的patch配合200像素的重叠切到画面底边再上移时保底高度和宽度不小于patch一半否则丢弃。下面这个切片脚本是我常用版本的简化# slice_patch.py # 把大图切成重叠patch并按偏移量改写标注框坐标 import cv2 def slice_image(image, boxes, patch_size1280, overlap200): h, w image.shape[:2] stride patch_size - overlap patches, out_boxes [], [] for y in range(0, h, stride): for x in range(0, w, stride): x2 min(x patch_size, w) y2 min(y patch_size, h) # 边缘patch太小时丢弃避免学习到大量空白 if (x2 - x) patch_size // 2 or (y2 - y) patch_size // 2: continue patch image[y:y2, x:x2] new_boxes [] for x1, y1, x2_, y2_, cls in boxes: nx1, ny1 max(x1, x) - x, max(y1, y) - y nx2, ny2 min(x2_, x2) - x, min(y2_, y2) - y # 框剩余面积太小时直接丢弃 if (nx2 - nx1) 10 or (ny2 - ny1) 10: continue new_boxes.append((nx1, ny1, nx2, ny2, cls)) patches.append(patch) out_boxes.append(new_boxes) return patches, out_boxes切图逻辑里要理解一个关键点标注框的坐标要跟着patch的偏移量一起改写也就是减去patch左上角的坐标同时把超出patch边界的部分裁掉。上面的变量命名有点绕x2_是原始标注框的右下角x坐标x2是patch的右下角x坐标min(x2_, x2)取到框在patch内的实际右下角再减去x基准。如果裁剪后剩余框的宽度小于10像素说明这个目标已经完全出图不保留。增强参数我给一组不容易出错的参考值mosaic关闭或只在小epoch阶段开因为无人机透视关系下拼接图的语义比较怪HSV色调扰动选h0.015、s0.5、v0.4随机缩放放到0.5到1.5之间配合随机平移旋转增强的角度范围要放宽到±30度以上因为无人机在飞行过程中画面朝向不是固定的。还有一个专门服务无人机场景的增强运动模糊。用3到7像素的随机方向高斯模糊模拟旋翼振动和飞行位移我实测对降低推理时的误检很有帮助。这组参数不是标准答案只是我习惯的起点你的飞行高度不同小目标尺度不同增强强度要重新调。4. 训练、推理与违章判定落地一条最小可复现的流水线4.1 训练前必须卡死的参数输入分辨率、batch、anchor与epoch拿到整理好的数据集进入训练阶段。对无人机高速巡检这个场景训练参数里输入分辨率优先级最高。前面说过车辆在整张航拍图里只有几十像素640的输入会让目标特征被下采样抹掉。我的起点是1280条件允许直接上1600如果显存不够不要先降分辨率优先降batch配合梯度累积。# 以通用YOLO工程为例具体路径以你的框架为准 python train.py \ --data highway_drone.yaml \ --weights yolov8n.pt \ --img 1280 \ --batch 8 \ --epochs 100 \ --patience 15 \ --workers 8 \ --cache ram这里的batch8对应单卡16GB显存附近不同框架算子差异大如果OOM就把batch降到4同时检查训练框架是否支持梯度累积有些支持--accumulate 2用两步小batch模拟大batch的效果。workers8是磁盘加载和预处理并行的线程数并不是越大越好太大容易把CPU内存吃满在服务器上用现成环境先试默认值。patience15是早停等待轮数无人机数据本身噪声大指标曲线会抖动等15个epoch再决定停不停比较稳。训练时我会额外关注小目标指标而不是只看整体mAP。大多数训练框架会在验证集上按尺度分类报告小目标精度比如mAP50-small。如果这个数和大目标差10个点以上说明检测头对浅层特征利用不够回去查模型结构或者增强策略而不是继续加epoch。另外说句实在话训练参数不是玄学但每换一组数据都要重新试继续沿用上一套数据调好的参数并不保证有效。4.2 推理与跟踪串联从检测框到稳定轨迹训练完成后进入推理阶段。检测模型单独跑只能输出一帧一帧的框要变成轨迹必须接跟踪器。下面的伪代码表达的是完整链路真实使用时把加载检测器和跟踪器的两行换成你自己的工程接口# inference_pipeline.py # 检测 - 跟踪 - 事件判定 的串联逻辑 import numpy as np def center_dist(box_a, box_b): # 两个框中心点的像素距离 ca ((box_a[0] box_a[2]) / 2, (box_a[1] box_a[3]) / 2) cb ((box_b[0] box_b[2]) / 2, (box_b[1] box_b[3]) / 2) return np.hypot(ca[0] - cb[0], ca[1] - cb[1]) def run_pipeline(video_path, road_angle, roi_polygon): detector load_model() # 替换为你的检测模型实例 tracker byte_track() # 替换为你的跟踪器实例 states {} # track_id - 轨迹状态对象 events [] for idx, frame in enumerate(video_frames(video_path)): dets detector(frame) # [(x1,y1,x2,y2,score,cls)] tracks tracker.update(dets) # [(track_id,x1,y1,x2,y2)] for tid, box in tracks: if tid not in states: states[tid] {box: box, stop_frames: 0, history: []} continue prev states[tid][box] states[tid][history].append(box) states[tid][history] states[tid][history][-20:] # 违停核心逻辑中心位移小于阈值则累计静止帧 if center_dist(prev, box) 3.0: states[tid][stop_frames] 1 else: states[tid][stop_frames] 0 # 静止超过N帧且中心点位于应急车道ROI内 if states[tid][stop_frames] 30 and in_polygon(center(box), roi_polygon): events.append((illegal_parking, tid, box, idx)) prev box return events def in_polygon(pt, polygon): # 点是否在多边形内可用cv2.pointPolygonTest实现 pass这段伪代码有三个关键细节。第一静止阈值3.0像素是原图尺度下的绝对值但无人机飞行高度不同同样3像素像素位移对应的实际速度差很多所以严格参数应该按当前高度换算成米每秒我习惯先按一个固定高度校准然后写一个按图像上网格换算的辅助函数。第二stop_frames的判定窗口依赖帧率25帧的机器和15帧的机器同样的30帧代表的时间完全不同部署前要把帧率写进配置而不是写死在代码里。第三跟踪器不是完美的它可能把一个车跟丢再分配一个新ID这时候状态机的stop_frames归零重新计数所以“违章事件”最终要设置一个确认码比如连续两次事件上报才输出避免一次ID跳变就误报。4.3 违章判定规则与阈值违停、应急车道占用、逆行怎么判在轨迹数据上叠加业务规则就得到最终的违章事件。违停的规则刚才已经写了目标中心保持静止超过阈值时间且中心点在应急车道ROI内。这里“静止”的判断不要用单帧中心距离小于阈值因为无人机自身的漂移也会让静止车辆的框位置抖动更好的做法是取最近5帧的中心点取值去掉最大最小值再算平均位移。应急车道占用比较复杂分两种占用行驶和占用停车。占用行驶看轨迹是否整体位于ROI内且持续有位移占用停车则退化为违停判定。注意不要把一个正常变道超车的轨迹误判成应急车道占用要加上“轨迹在ROI内的连续帧数”这个条件。逆行判定我一般用轨迹方向角。取最近10帧的中心点做一阶差分求平均方向然后跟ROI配置里的道路主方向比较# rule_reverse.py # 用轨迹方向判断逆行 import numpy as np def normalize_angle(angle): while angle 180: angle - 360 while angle -180: angle 360 return angle def is_reverse(history, road_angle): # history: 最近若干帧中心点列表 if len(history) 3: return False pts np.array(history) dx np.mean(np.diff(pts[:, 0])) dy np.mean(np.diff(pts[:, 1])) move_angle np.degrees(np.arctan2(dy, dx)) diff abs(normalize_angle(move_angle - road_angle)) return diff 120 # 与主方向夹角超过120度判定逆行这里的road_angle不是随便拍的它在ROI配置阶段按道路实际走向标定比如一段东西向高速主方向是0度或180度。阈值120度是经验值正常行驶时轨迹方向角跟道路方向差在30度以内跨车道变道时也不会长期超过这个值真正逆行的车夹角会接近180度。需要注意的事这个规则依赖跟踪器的轨迹稳定如果轨迹被ID切换打断history会混入另一个车的点所以我在入参前用跟踪器自带的置信度做了过滤只有连续出现的帧才进history。5. 无人机场景的5个高频踩坑现象、原因与解决方案5.1 小目标漏检训练指标“看起来不差”一上无人机就露馅现象验证集mAP有0.85但是把模型接到无人机实拍视频上画面里30像素以下的车辆几乎全部漏检只有贴近摄像头的车能框出来。原因训练时把4K原图直接resize成1280像素原图中30像素的车在训练图上只剩下不到10个像素特征金字塔最浅层也拿不到有效特征加上验证集里小目标占比低mAP被大目标拉高了小目标段的精度根本没在指标里体现。解决把训练流程改成“原图切patch高分辨率输入”用前面第三章的切片逻辑把车辆至少保持在40像素以上评估时单独看小目标段的AP而不是只看总mAP。还有一个经验如果标注数据里有不少目标框宽度小于10像素那这些框基本是噪声建议直接过滤掉不要指望模型能学到。5.2 跟踪ID跳变违停误报的元凶现象一辆车明明停在应急车道上事件上报系统却一会儿报“违停”一会儿报“正常”交替出现翻看历史轨迹发现同一个物理车辆被跟踪器分配了多个ID。原因无人机悬停不稳车辆遮阳挡风玻璃反光导致检测框时有时无跟踪器在检测框丢失后会把目标删掉下一帧重新检出时分配新ID状态机的stop_frames被重置静止状态中断。解决给跟踪器加一个“记忆帧”参数目标短时间丢失比如5帧内不要立即删除轨迹同时调低检测置信度阈值让低分框先进入跟踪器做二次判定避免“检测框消失→重分配ID”。如果仍无效考虑给跟踪器加外观特征但机载算力有限优先把“记忆帧”和低分框处理做扎实。5.3 运动模糊与逆光阴影、护栏、树影都来凑热闹现象识别结果里出现大量车辆框打在护栏阴影、桥墩影子和树影上逆光路段车辆自身检测框和阴影框同时存在导致目标数量翻倍。原因训练数据大多是晴天正午拍的光照干净没有包含阴影和模糊样本无人机巡航速度下运动模糊让车辆边缘特征消失模型只能靠颜色块猜而阴影和车身的颜色块在某些光照下高度相似。解决在训练增强中加入运动模糊和HSV强扰动让模型见过“模糊的车”和“带阴影的车”数据采集时专门挑早晚时段飞几个架次把逆光样本放进训练集。注意不要把ROI的阴影区域直接屏蔽因为阴影覆盖的地方恰恰是违停高发区屏蔽会漏检真实事件。5.4 弯道、桥梁遮挡漏检不可怕漏判才麻烦现象弯道路段车辆被防眩板、桥墩短暂遮挡检测框丢失几帧跟踪器把目标删掉后重新检出轨迹断成两截原本正在发生的“应急车道缓行”被漏报。原因遮挡问题在固定摄像头场景也存在但无人机视角下遮挡物更杂、遮挡时间更随机而且无人机在飞行中本身也会让视野移动遮挡窗口变得更难预测。解决对于遮挡导致轨迹中断的情况最有效的不是换更强的检测器而是让事件上报具备“时间容忍度”在一段连续时间窗口内同一位置附近出现同一特征的车辆检测就视为同一事件延续。规则上可以记录“最后检出位置”当新检测框出现在旧事件位置周边若干米内时续接该事件而不是开新事件。这个续接逻辑用代码写起来只有几十行但能救回不少被遮挡场景下的漏报。5.5 直接搬运地面预训练模型小目标分支被锁死现象用COCO或地面监控数据集预训练出来的权重直接接着训练无人机数据loss降得很慢小目标召回率始终上不来。原因COCO等预训练特征是在水平视角、大目标为主的分布上学出来的检测头的高层特征对小目标响应很弱无人机俯视小目标需要P2层这类高分辨率特征很多预训练模型默认不保留或权重初始化得太随机。解决优先选择自带P2层输出的模型结构或者手动将检测头增加更浅的层训练策略上采用“分阶段解冻”前10个epoch冻结主干只训练检测头让新数据的特征分布逐渐适应再解冻整个网络联合微调。如果模型不支持就直接训练完整模型但要把学习率调低一个数量级给它更长的收敛时间。6. 验证要狠一点从单段视频的偶然成功到长期巡检稳定算法在一条视频上跑通不算数巡检场景要求的是连续几十架次不出大问题。我一般会建一个灰度验证集覆盖不同时段、天气、飞行高度和路段类型分别记录误报率和漏报率而不是只记录mAP。验证维度建议覆盖内容我常用的通过线时段白天/黄昏/夜间夜间漏报率不超过5%天气晴/阴/雾/雨后雨天误报率低于2次/km高度60m/100m/150m不同高度漏报率差异小于3%路段直线/弯道/跨线桥弯道误报不超过直线1.5倍另一个我踩过坑才养成的习惯是回放对比。固定航线飞同一段路白天飞、夜晚飞、阴天飞把所有推理日志落盘包括每帧检测框、轨迹ID、事件触发时间。算法调整后用同一批日志重新回放输出事件再做差分对比。这样能快速找出“随机抖动”带来的误报因为正常的物理事件在差分里应该是稳定的。有条件时给算法接上仿真环境测长序列比如凤凰无人机模拟器、硬件在环仿真的链路让算法连续跑几百分钟的空场景统计无中生有的事件数量。这种长时间稳定性测试成本低能暴露很多只靠较短实测发现不了的状态机问题。上真机后我个人习惯是前两周只跑“观察模式”算法判出事件但不推送人工复核确认率稳定到90%以上再放开。最后说一个教训有一次某路段误报率高到不敢上线排查了三轮才发现是那个路段的树影方向特殊训练集里没有类似样本后来在增强里专门加了一组逆光阴影样本误报率直接降下来。这类小问题数据上一个小处理就能解决但前提是真的去一级一级查了。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进