简介:基于YOLOv8的无人机交通监控系统,是一套面向智能交通与深度学习应用开发的完整示例项目。它以YOLOv8实时目标检测算法为核心,结合无人机高清摄像头采集的道路画面,实现对行人、自行车、汽车、卡车等交通参与者的自动识别与分类,可服务于交通管理、毕业设计、算法学习等场景。压缩包内含27个文件,主体为12个Python脚本和9个编译缓存文件,另附YAML配置文件、依赖清单、模型示例图片与说明文档,覆盖模型调用、车牌检测、速度估算、目标追踪等环节。包体仅94KB,代码架构清晰,适合有一定Python和深度学习基础、希望快速上手目标检测项目的开发者。目前已有35人学习,项目中提供了主程序、工具函数、配置目录等模块,能够帮助读者理清目标检测系统的完整流程,掌握数据处理、模型推理与结果输出的实现思路,具有较强的参考与复用价值。
1. 先把系统拆开:无人机交通监控不只是“飞起来跑个YOLOv8”
一架四旋翼无人机悬停在十字路口上空80米,往下看到的不是“路面”,而是一堆几像素到几十像素的小方块。把画面里的小方块识别成小轿车、货车、行人,再把每秒25帧的结果算成车道流量、拥堵事件和告警记录,这套链路就是常见的基于YOLOv8的无人机交通监控系统。很多人被“无人机+YOLOv8”这个组合迷惑,以为把模型权重丢进飞控里就完事,实际做下来你会发现:目标尺度、机载算力、标注数据、跟踪平滑、坐标换算,每一环都能让系统翻车。这篇文章不是讲YOLOv8本身,而是顺着“航拍交通监控”这个具体场景,把模型选型、数据准备、训练、部署和避坑一次说透。
这套路线适合三类人:做深度学习或无人机相关毕业设计的学生,需要快速拿到一套能演示、能复现的系统雏形;做交通流量统计或智慧城市试点的工程师,需要评估无人机视觉方案的边界;以及刚接触机载视觉、想搞清楚“模型之外还有什么坑”的开发者。读完你会得到一个明确结论:这套系统的瓶颈通常不在模型精度,而在数据分布和工程闭环。
2. 模型选型与运行环境:为什么机载默认YOLOv8n,地面才跑m
2.1 无人机视角下的目标特点:小、密、角度刁
地面监控摄像头高度通常只有3到8米,平视角度为主,一辆车在画面里能占到几百像素,侧面特征清清楚楚。无人机交通监控完全是另一个尺度:飞行高度普遍在50米到120米,正俯视或大角度斜视,一辆小轿车在1080p画面里往往只有16×16到30×30像素,行人可能只有10像素左右。这个尺度差异会直接影响模型选择和数据增强策略,也是很多人在第一个Demo里“模型什么都检不出来”的根本原因。
除了目标小,航拍画面还有三个特点。第一是密集遮挡,早晚高峰路口的车辆彼此紧贴,检测框大量重叠,普通NMS阈值很容易把相邻车吞掉。第二是尺度变化快,无人机爬升或下降过程中,同一个目标在几秒内从50像素变成120像素,模型需要适应多尺度输入。第三是视角单一但背景复杂,树木阴影、路面标线、车顶反光都会成为误检来源。直接用COCO预训练权重跑航拍视频往往效果很差,因为COCO里的车是地面平视视角,特征分布完全不同,必须用航拍数据微调,这一点几乎没有例外。
这里可以做一个简单对比,能帮你快速理解为什么不能照搬地面监控方案:
| 维度 | 地面监控 | 无人机航拍监控 |
|---|---|---|
| 视角 | 平视或小角度俯视 | 正俯视或大角度斜视 |
| 目标尺寸 | 通常100像素以上 | 10到40像素为主 |
| 背景复杂度 | 固定机位、背景静止 | 地面纹理、阴影、树冠变化 |
| 算力位置 | 机柜或边缘盒子,供电稳定 | 机载电池供电,散热受限 |
| 运动状态 | 静止 | 悬停或慢速移动,存在振动 |
2.2 机载算力与模型档位的匹配
YOLOv8官方提供了n、s、m、l、x五档模型,参数量和计算量依次上升。就无人机交通监控来说,我的选择原则很固定:机载端只用n或s,地面站离线复核才考虑m。原因很简单,n档参数量在3M量级、计算量大约8.7GFLOPs,能够在Jetson Orin Nano、RK3588这类边缘设备上跑到接近实时;s档精度更高但推理时间翻倍,适合图传链路稳定、允许一定延迟的场景。
很多初学者一上来就选YOLOv8m甚至x,理由是“精度高”,但在无人机上跑会发现两个现实问题:一是机载功耗和散热撑不住,电池续航被明显压缩;二是检测延迟变大,飞机姿态一动,画面里的目标位置早就漂移了。做实时监控不是做离线评测,帧率就是精度的一部分,掉帧等于漏检。如果确实需要更高精度,我的建议是机载跑n做“预筛”,把ROI区域的帧抽出来传回地面站,用s或m再精检一遍,而不是让飞机背一个跑不动的模型。
如果是RK3588这类带有NPU的板子,还要考虑模型转换和量化。常见做法是先导出ONNX,再用rknn-toolkit2转成RKNN格式,最后做INT8量化。量化后模型体积缩小、推理速度提升,但小目标精度会有不同程度的下降,所以转换完必须用航拍验证集重新评估mAP,不能只跑两张测试图看效果。
2.3 运行环境:Ubuntu 20.04 CPU版本也能跑通,但只适合调试
很多人在没有GPU的笔记本上也想先跑通流程,这完全可行。Ubuntu 20.04下搭建YOLOv8 CPU环境非常简单,不需要编译源码,直接用ultralytics这个Python包即可。下面是一套最小可复现的步骤:
python3 -m venv yolov8-env source yolov8-env/bin/activate pip install --upgrade pip pip install ultralytics # 下载权重并跑一次推理验证环境 yolo predict model=yolov8n.pt source=test.jpg device=cpu这段命令的逻辑是:先创建一个独立的Python虚拟环境,避免和系统Python环境互相污染;然后安装ultralytics包,它会自动拉起PyTorch CPU版本和所需依赖;最后用官方权重跑一次预测,如果能正常输出结果图,说明链路通了。这里有两个副作用需要提前知道:CPU推理一张1080p图片可能要几百毫秒到几秒,完全达不到实时;如果要训练自己的数据集,CPU训练一个epoch都会慢到让人怀疑人生。所以环境验证用CPU没问题,正式训练还是建议用云GPU或者本地NVIDIA显卡。
如果你要在这台机器上准备训练数据,还可以顺手把标注工具装上。LabelMe是最常用的开源标注工具之一,支持矩形框和多边形标注,导出的JSON格式后面需要自己做转换。这一步没有太多玄学,耐心标几百张航拍图就够了,关键是每个目标的边界要压准,遮挡严重的车辆宁可稍微框大一点,也不要框到一半就截断。
3. 数据与训练:从LabelMe标注到YOLOv8跑通自己的数据集
3.1 数据来源与标注工具选型
训练无人机交通监控模型,数据来源通常有三条路。第一条是直接用公开航拍数据集,比如VisDrone、DOTA这类,里面有大量无人机视角的车辆、行人、自行车标注,适合做预训练或者补充样本;第二条是自采数据,用无人机在目标路口悬停拍摄几十段视频,然后抽帧标注,这是和最终部署场景最匹配的数据,精度上限最高;第三条是公开数据+自采数据混合训练,一般也是效果最稳的做法。
自采数据时要注意一个容易被忽略的问题:按视频片段划分训练集和验证集,而不是按帧随机划分。如果你把同一段视频的连续帧一半放进训练集、一半放进验证集,验证指标会非常好看,因为相邻帧几乎一样,模型等于开卷考试。等飞到新路段时才会发现真实效果差得远。正确做法是按架次或按路段切分,保证验证集里的场景和训练集没有重叠。
标注类别建议控制在5到8类,交通监控场景我一般只标person、car、truck、bus、motorcycle五类。类别太少不够统计,类别太多会加剧样本不均衡,比如“ambulance”这类稀有类别样本量很难凑够,训练出来基本等于摆设。标注工具就用LabelMe,记得把所有标注导出成JSON文件,和对应图片放在同一个目录下。
3.2 LabelMe JSON转YOLO格式:转换脚本与参数说明
LabelMe保存的是多边形顶点坐标,而YOLO训练需要的是归一化后的中心点坐标和宽高。这个转换没有捷径,只能写脚本批量处理。如果你的标注全是矩形框,下面的脚本可以直接用;如果是多边形,先用cv2.boundingRect算出外接矩形再转换。
import json import os from PIL import Image def labelme2yolo(json_path, save_dir, class_names): with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) # 通过JSON里的imagePath定位原图,读取宽高用于归一化 img_path = os.path.join(os.path.dirname(json_path), data['imagePath']) img = Image.open(img_path) w, h = img.size lines = [] for shape in data['shapes']: label = shape['label'] if label not in class_names: continue cls_id = class_names.index(label) pts = shape['points'] # 只处理两点矩形框,polygon需要额外算外接矩形 x1, y1 = pts[0] x2, y2 = pts[1] bw = abs(x2 - x1) bh = abs(y2 - y1) cx = (x1 + x2) / 2.0 cy = (y1 + y2) / 2.0 # YOLO格式:class cx cy w h,全部除以图片尺寸归一化 lines.append(f"{cls_id} {cx / w:.6f} {cy / h:.6f} {bw / w:.6f} {bh / h:.6f}") out_txt = os.path.join(save_dir, os.path.basename(json_path).replace('.json', '.txt')) with open(out_txt, 'w', encoding='utf-8') as f: f.write("\n".join(lines)) # 使用示例 class_names = ['person', 'car', 'truck', 'bus', 'motorcycle'] labelme2yolo('data/annotations/001.json', 'data/labels/train', class_names)这段脚本的核心逻辑是:读JSON、取原图尺寸、遍历每个标注对象、把两点坐标换算成归一化的中心点和宽高。需要注意PIL读取的图片宽高必须和标注时的图片一致,否则所有坐标会整体偏移。另外,如果你的标注文件里有“points”超过两个点的多边形,当前代码会出错,需要先算最小外接矩形,这也是把LabelMe数据转给YOLO训练时最常见的坑。
转换完成后,把图片和txt文件按如下结构组织,训练时直接指向目录即可:
drone-traffic/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml3.3 训练自己的数据集:命令与关键参数
训练前需要写一个data.yaml文件,告诉ultralytics数据集在哪里、有哪些类别。我的示例配置如下:
path: /home/user/drone-traffic train: images/train val: images/val names: 0: person 1: car 2: truck 3: bus 4: motorcycle这里的path建议写绝对路径,写相对路径容易出现“dataset not found”的报错,尤其是在不同机器之间搬运项目的时候。names的编号顺序必须和转换脚本里的class_names一致,否则训练时标签会错位,模型再怎么调参也不会收敛。
确认数据集结构无误后,执行训练命令:
yolo detect train \ data=drone-traffic/data.yaml \ model=yolov8n.pt \ epochs=100 \ batch=16 \ imgsz=640 \ device=0先解释一下这条命令里每个参数的含义。model=yolov8n.pt表示从官方n档预训练权重开始微调,而不是随机初始化,这能明显加快收敛并提高最终精度;epochs=100是起步值,航拍数据量通常不大,100个epoch后根据results曲线再增减;batch=16取决于显卡显存,8G显存跑n档建议8或16,显存溢出就减半;imgsz=640是训练分辨率,但针对航拍小目标,我一般建议训练时直接提到1280,代价是训练速度变慢、显存需求变大,好处是小目标召回率明显提升。
另外几个参数值得单列说明。optimizer我用AdamW偏多,SGD也能收敛但需要更多epoch;lr0如果数据量小建议从0.01降到0.005,避免前期震荡;patience=30表示30个epoch验证集没有提升就早停,能省时间;cache=True可以把图片缓存到内存,大幅减少数据读取时间,前提是内存够大。还有一个容易被忽视的参数是close_mosaic,它控制训练最后10个epoch是否关闭马赛克增强,我一般保留默认值,因为航拍小目标需要靠马赛克增强来丰富背景组合。
训练结束后,模型权重保存在runs/detect/train/weights/目录下,best.pt代表验证集上表现最好的权重,last.pt是最后一个epoch的权重。两个都要留,best.pt用于部署,last.pt可以用于分析训练最后阶段是否过拟合。
3.4 从损失曲线到验证:判断模型是不是真的能上线
训练完成后不要急着把best.pt拷到无人机上,先跑一次验证集评估:
yolo detect val \ model=runs/detect/train/weights/best.pt \ data=drone-traffic/data.yaml \ imgsz=640验证输出会给出mAP50、mAP50-95、各类别的精度和召回率。对交通监控场景,不要只盯着mAP50这个数字,还要看小目标类别的AP。如果car的AP很高但person的AP很低,说明数据不均衡或者标注样本不足,比总指标更能反映问题。
这一步还必须看ultralytics自动生成的混淆矩阵图,路径在runs/detect/train/confusion_matrix.png。混淆矩阵能清晰告诉你哪些类别互相混淆,最常见的航拍问题是“truck”和“bus”互相认错,因为正俯视视角下两者外形非常接近。如果这种混淆严重,要么增加两类样本,要么干脆合并成一个“heavy_vehicle”类,牺牲细粒度类别换取整体准确率。
顺手提一句,网上很多人讨论“YOLOv8改进加协调注意力机制”对小目标有效,如果你训练后确认小目标AP上不去,可以在网络结构上尝试,但我会建议先把切图训练和分辨率调优做完。数据层面的收益通常比改结构来得快,也更容易排查。
4. 系统部署闭环:检测只是中间件,跟踪和统计才是监控
4.1 机载推理还是图传地面推理
模型训练完,下一个问题是在哪里跑推理。无人机交通监控有三种常见部署形态,各自适用不同场景。
机载推理是把模型跑在飞机上的计算板卡里,比如Jetson Orin Nano、RK3588。优点是没有图传延迟,检测结果直接在机载端产生,适合边缘事件触发;缺点是算力受限,只能跑n或s档量化模型,而且调试一次要反复拆装设备,很费时间。图传地面推理则相反,飞机只负责把视频推流回地面站,检测在地面服务器上跑,可以用m甚至l档模型,精度更高、迭代更容易,但对图传链路质量和延迟敏感。第三种是混合模式,机载跑轻量模型做关键事件判断,地面跑大模型做复核,工程复杂度最高,一般试点项目用不上。
| 部署方式 | 延迟 | 模型上限 | 开发效率 | 适用场景 |
|---|---|---|---|---|
| 机载推理 | 低 | n/s | 低 | 实时告警、断连场景 |
| 图传地面推理 | 中高 | m/l | 高 | 试点验证、离线统计 |
| 机载+地面混合 | 低 | n+s | 中 | 正式系统 |
如果你是做毕业设计或第一个Demo,我强烈建议先选图传地面推理。开发效率高,调模型、调参数都不需要碰飞机,踩坑成本低。等系统逻辑跑通了,再把模型压到机载端。
4.2 视频流入口与检测服务化
无人机的视频输出通常走RTSP或RTMP协议。地面站拉流使用的就是OpenCV的VideoCapture,指定URL地址即可。下面是一段最基础的推理循环:
import cv2 from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture("rtsp://192.168.1.10:8554/live") while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model( frame, conf=0.35, iou=0.45, classes=[1, 2, 3, 4], imgsz=640, device=0 ) for r in results: for box in r.boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() cls_id = int(box.cls[0]) conf = box.conf[0].item() print(f"{cls_id} {conf:.2f} {x1:.0f} {y1:.0f} {x2:.0f} {y2:.0f}")这段代码里几个参数值得注意。conf=0.35是置信度阈值,航拍小目标置信度普遍比地面监控低,建议设在0.3到0.4之间;iou=0.45是NMS阈值,车辆密集场景建议降到0.35,否则相邻车辆容易合并;classes=[1,2,3,4]表示只检测car、truck、bus、motorcycle,过滤掉person可以明显减少行人引起的高频噪音。device=0是显卡编号,如果是CPU改成cpu。
实际工程里不要把画框和推理写在同一个循环里,OpenCV的imshow窗口会阻塞主线程,导致推理帧率被拖到个位数。常见做法是推理线程只把结果写入一个共享队列,显示线程独立从队列里取帧渲染,两者解耦。
4.3 目标跟踪与交通参数统计
单帧检测只能告诉你“这一帧有什么”,交通监控要的是“车往哪走、有多少辆、哪里拥堵”,这需要帧间关联。最简单的方案是IOU匹配:如果当前帧检测框和上一帧某个目标框的IOU大于阈值,认为是同一个目标;连续多帧匹配成功,才对目标分配一个稳定ID。
def iou(a, b): ax1, ay1, ax2, ay2 = a bx1, by1, bx2, by2 = b inter_w = max(0.0, min(ax2, bx2) - max(ax1, bx1)) inter_h = max(0.0, min(ay2, by2) - max(ay1, by1)) inter_area = inter_w * inter_h area_a = (ax2 - ax1) * (ay2 - ay1) area_b = (bx2 - bx1) * (by2 - by1) union_area = area_a + area_b - inter_area return inter_area / union_area if union_area > 0 else 0.0IOU阈值一般取0.3到0.5。无人机悬停时画面相对稳定,0.4够用;如果飞机云台在转动或画面有抖动,可以降到0.3,或者改用中心点欧氏距离匹配。需要注意的是,只做IOU匹配在目标密集时很容易发生ID Switch,也就是两辆车交错后ID互换。要上强度就得换带轨迹预测的跟踪器,比如ByteTrack或DeepSort,但它们的依赖会复杂一些,核心逻辑仍然是从关联匹配出发。
有了稳定目标ID,就能计算交通参数。虚拟线计数是最常见的做法:在画面中按行车方向画一条线,车辆中心点跨过这条线时计数加一,就可以统计车流量;区域停车检测是判断目标中心点进入某个ROI后停留帧数超过阈值,常用于违停识别;拥堵检测可以直接统计某条道路区域内的车辆密度,当帧车辆数超过设定值且持续十几秒,就触发拥堵事件。
4.4 告警输出与坐标回传
检测、跟踪、统计的结果,最后要变成可以被地面站或Web平台消费的消息。最简单的方式是HTTP回调或MQTT,把事件以JSON格式推送出去:
import requests event = { "type": "traffic_jam", "vehicles": 23, "loc": [116.391, 39.905], "timestamp": "2025-06-01T08:30:00+08:00" } requests.post("http://127.0.0.1:8000/event", json=event)这里写loc时值得多说一句。如果这个经纬度是直接把无人机飞控的经纬度填进去,那它表示的是“飞机在哪”,不是“事件发生地”。要估算目标的位置,需要把检测框的像素坐标结合无人机的经纬度、高度、云台俯仰角做投影近似,这属于坐标系标定问题。低精度需求下,用针孔相机模型的中心投影直接估算偏移;高精度需求必须依赖RTK和相机内参标定。
5. 避坑:无人机交通监控里最常见的5个翻车点
5.1 小目标漏检:下采样太快,行人变成几个像素
现象:模型在验证集上mAP不低,可飞到现场后行人和摩托车频繁漏检,回看检测结果时画面里只有大车。
原因:YOLOv8的下采样倍数较高,小目标经过多层卷积后特征图上的有效信息只剩几个像素,难以分类。很多人在训练时沿用默认的imgsz=640,航拍场景下这是不够的。
解决:首选把imgsz提到1280,模型输入分辨率变大,小目标对应像素增多,检测率会有肉眼可见的提升;如果显存不够,做切图训练,把1080p画面切成四块分别推理,再把检测框映射回原图坐标。这两种方法比换模型结构更直接。
5.2 验证集虚高:模型开卷考试,换条路就失灵
现象:训练时的val/测试集mAP高达0.85,但把模型部署到之前没飞过的路段,表现断崖式下降。
原因:数据集划分不当。很多人按帧随机划分train和val,导致同一段视频的连续帧同时在训练集和验证集里,模型等于记住了画面,而不是学到了“车”这个概念。
解决:数据集按视频片段或按飞行架次切分。每段视频只进一个集合,保证验证集里的场景、道路、光照和训练集尽量不同。这是航拍数据划分的血泪经验,表面看起来数据集更大,实际泛化能力很差。
5.3 类别不平衡:满路都是车,行人没人权
现象:训练后car的AP值很高,但person和motorcycle的精确率、召回率都偏低,模型基本只输出车辆。
原因:标注样本中车辆占了大头,行人样本少,模型对少数类学习不足。这在早晚高峰的航拍素材里非常典型。
解决:先在数据集上统计每个类别的目标数量,如果差别超过5倍,就得处理。一是增加少数类样本,单独补一批行人密集的航拍帧;二是用ultralytics的cls参数调整分类损失权重;三是给少数类做过采样,把行人样本复制并加上轻微旋转和亮度扰动。别指望模型自动平衡类别,目标检测没有免费的类别均衡。
5.4 抖动与模糊:悬停不等于静止,单帧检测全是碎框
现象:无人机悬停时画面依旧周期性抖动,检测框忽大忽小,车辆ID频繁跳变,统计车流量时数字乱跳。
原因:旋翼振动会传导到云台,加上快门速度不足,某些帧出现运动模糊。单帧检测对模糊非常敏感,一个模糊帧可能把一辆车切成两个碎片框。
解决:采集端开启电子防抖并固定云台增稳;部署端不逐帧检测,而是按关键帧抽帧,比如每3帧检测一次,中间帧用最后一次检测结果保持。如果模糊无法避免,就在跟踪器里加多帧确认逻辑,一个检测结果连续出现3帧以上才计入统计,靠时间去换稳定性。
5.5 坐标换算翻车:画面像素不等于经纬度
现象:目标在画面中央,系统上报的经纬度却偏到隔壁建筑物上,中心点越靠近画面边缘偏移越严重。
原因:直接用画面中心坐标当经纬度,或者忽略无人机姿态角做粗略换算。无人机实时位置来自飞控遥测,但相机光轴和飞机机身之间存在夹角,没有姿态补偿误差会非常大。
解决:低精度场景使用“针孔相机近似投影”,把检测框中心点像素坐标结合飞控的经纬度、海拔、云台俯仰角和航向角,换算成地面水平偏移;高精度场景上RTK和相机标定,标定内容包括内参、畸变、云台安装角。坐标换算这一块是整个系统里最玄学的环节,建议先接受“低精度可用、高精度很难”的现实,不要一上来就承诺米级定位。
6. 进阶技巧:用轨迹管理把单帧误报压下去
单帧检测难免存在误检,比如树影被当成车、路面反光被当成目标。这些误检有一个共同特点:它们在时间上不连续,这一帧出现、下一帧就消失。相反,真实车辆会稳定出现在连续几帧里。利用这个差异,可以给跟踪器加一个“轨迹有效性”判断,让误报根本没有机会进入计数系统。
from collections import deque, defaultdict class TrackFilter: def __init__(self, max_age=5, min_track_len=3): self.max_age = max_age self.min_track_len = min_track_len self.tracks = defaultdict(deque) # track_id -> 中心点队列 def update(self, detections): # detections: {track_id: (cx, cy)} current_ids = set(detections.keys()) for tid in list(self.tracks.keys()): if tid not in current_ids: self.tracks[tid].append(None) # 标记丢失帧 if len(self.tracks[tid]) > self.max_age: del self.tracks[tid] for tid, center in detections.items(): self.tracks[tid].append(center) def valid_ids(self): valid = [] for tid, buffer in self.tracks.items(): real_frames = sum(1 for p in buffer if p is not None) if real_frames >= self.min_track_len: valid.append(tid) return valid这段代码的逻辑是:每个目标ID维护一个最近的轨迹队列,队列里记录每一帧的中心点坐标;如果某个ID连续5帧没有出现,就直接删除,避免无限膨胀;只有真实出现超过3帧的目标才被标记为有效。配置上要注意两点,min_track_len太低起不到过滤作用,太高会漏掉慢速或遮挡多的目标,我一般取3到4帧;max_age则取决于你的推理帧率,25帧率下取5到10比较合适。
这个做法看似简单,却是把检测精度转化为系统精度的关键一环。很多人花大量时间调模型参数,想让单帧置信度提升两三个百分点,却忽略了跟踪层面的稳定化——后者带来的收益往往大得多。我自己的习惯是先把轨迹管道、虚拟线计数、告警推送跑通,让整个业务闭环先转起来,再回头优化模型本身;否则很容易出现一种情况:模型调了三个月,最后发现系统卡在视频流断连和坐标偏移上。
这套“轻量跟踪+轨迹过滤”的思路同样适用于无人机巡检、安防监控等场景,核心思想是一致的:检测结果是带噪音的观测,系统输出才是真正有价值的结论。希望帮到你。
本文还有配套的精品资源,点击获取