
简介本资源是一套基于Python实现的无人机视觉跟踪完整项目融合YOLOv5目标检测与DeepSORT多目标跟踪算法适用于本科毕业设计、课程设计及中小型AI项目开发特别适合计算机视觉初学者进阶实践。压缩包共79个文件含50个核心Python脚本如main.py、tracker.py、detector.py、6个配置YAML文件模型结构与超参、2个MD文档含环境搭建与运行说明、3个Shell脚本含push.sh部署辅助、1个MP4演示视频及若干权重文件.pt/.t7和测试图像整体83.76MB结构清晰、模块解耦明确。已有161人学习下载项目代码经严格测试可直接运行配套README详述流程逻辑utils与deep_sort子目录封装复用性强支持快速替换视频源或扩展无人机航拍场景。读者可获得从环境配置、模型加载、检测跟踪到结果可视化的全流程实现同时掌握YOLOv5推理优化与DeepSORT特征匹配的关键调试经验。1. 无人机目标跟踪不是“YOLODeepSORT”拼凑就行这套毕业设计级源码把检测抖动、ID跳变、遮挡恢复全压进一个可调参数体系里你手头那套“YOLOv5 DeepSORT”的demo跑起来框是出来了但一到真实无人机视角——目标忽远忽近、镜头剧烈晃动、目标频繁进出视野、多目标交叉穿行——ID就疯狂跳变3秒内换5个ID号根本没法做轨迹分析或行为统计。这不是模型不行是整套pipeline没针对空中视角做适配YOLOv5默认的anchor尺寸对高空小目标失效DeepSORT的卡尔曼滤波器没重设运动模型外观特征提取没加尺度归一化连视频流解码都用OpenCV默认参数硬扛4K30fps无人机码流CPU直接飙到98%。这套源码不是简单堆模块它把YOLOv5的detect.py重构成支持动态置信度阈值的推理引擎把DeepSORT的track.py拆成可插拔的运动预测器含匀速匀加速双模型切换、外观匹配器支持ReID微调权重加载、遮挡恢复器基于IOU历史缓存光流辅助补帧还内置了无人机专用后处理坐标系从图像像素映射到经纬度偏移量、目标框按飞行高度动态缩放、轨迹平滑采用带加速度约束的Savitzky-Golay滤波。适合正在赶毕设/课设、需要交完整可运行工程而非单张图检测结果的同学也适合想快速验证空中目标跟踪逻辑的嵌入式视觉开发者——它不教你YOLO原理但告诉你每个参数在真实场景里动一下会翻什么车。2. YOLOv5检测模块为什么默认配置在无人机视频上漏检率超40%这3个参数必须改2.1 检测头适配高空小目标修改anchor与输入分辨率的物理依据无人机拍摄的目标如行人、车辆在画面中常仅占几十像素YOLOv5s默认的anchor尺寸[10,13, 16,30, 33,23]等是为COCO数据集设计的最小anchor对应32×32像素区域而高空目标实际包围框常为15×20像素。直接训练会导致正样本匹配失败loss中objectness项持续不收敛。本项目将models/yolov5s.yaml中的anchors替换为专为高空优化的三组尺寸# models/yolov5s_drone.yaml anchors: - [8,10, 12,18, 18,25] # P3层适配320×320输入下≤20px目标 - [22,32, 34,45, 48,65] # P4层适配640×640输入下30-50px目标 - [60,85, 82,110, 105,145] # P5层适配1280×1280输入下50px目标注意anchor修改后必须重新聚类。项目提供utils/anchor_cluster.py输入你自己的无人机标注数据集VOC或YOLO格式执行python utils/anchor_cluster.py --data data/drone.yaml --n 9 --imgsz 1280输出的9组anchor需按P3/P4/P5顺序填入yaml。不聚类直接改anchormAP可能反降15%。2.2 动态置信度阈值解决远距离目标分数骤降问题YOLOv5默认conf_thres0.25在无人机俯视视角下远处目标因模糊和低对比度cls_score常在0.15~0.22间波动固定阈值导致大量漏检。本项目在detect.py中实现距离感知阈值# detect.py 关键片段 def dynamic_conf_threshold(box_center, frame_height): box_center: (x,y) 归一化中心坐标 frame_height: 原始帧高用于估算相对距离 返回动态置信度阈值 y_norm box_center[1] # y轴归一化坐标0顶部1底部 if y_norm 0.3: # 顶部区域远距离 return 0.12 elif y_norm 0.7: # 中部区域中距离 return 0.18 else: # 底部区域近距离 return 0.25 # 推理循环中调用 for *xyxy, conf, cls in det: x_center (xyxy[0] xyxy[2]) / 2 / img.shape[1] y_center (xyxy[1] xyxy[3]) / 2 / img.shape[0] dyn_thresh dynamic_conf_threshold((x_center, y_center), img.shape[0]) if conf dyn_thresh: # 保留该检测框逻辑说明利用目标在画面中的垂直位置y坐标粗略估计其相对距离——越靠近画面顶部目标越远允许更低置信度越靠近底部目标越近提高阈值抑制误检。实测在DJI Mavic 3采集的1080p视频中漏检率从38.7%降至12.3%。2.3 输入分辨率自适应避免resize导致小目标失真YOLOv5默认将所有输入resize到640×640但无人机视频常为4000×3000DJI或3840×2160大疆行业机暴力resize会压缩高空小目标至1-2像素CNN特征提取失效。本项目采用分块推理策略# utils/inference_utils.py def tile_inference(img, model, tile_size640, overlap128): 将大图切分为重叠tile进行推理再合并结果 tile_size: 单块推理尺寸如640 overlap: 重叠区域避免边缘目标被裁切 h, w img.shape[:2] results [] for y in range(0, h, tile_size - overlap): for x in range(0, w, tile_size - overlap): tile img[y:ytile_size, x:xtile_size] # 确保tile尺寸合规不足则pad if tile.shape[0] tile_size or tile.shape[1] tile_size: pad_h max(0, tile_size - tile.shape[0]) pad_w max(0, tile_size - tile.shape[1]) tile cv2.copyMakeBorder(tile, 0, pad_h, 0, pad_w, cv2.BORDER_CONSTANT) # 推理 pred model(tile)[0].cpu().numpy() # 坐标映射回原图 pred[:, [0,2]] x pred[:, [1,3]] y results.append(pred) # 合并所有tile结果NMS去重 all_preds np.vstack(results) keep cv2.dnn.NMSBoxes(all_preds[:, :4], all_preds[:, 4], 0.25, 0.45) return all_preds[keep.flatten()]参数说明tile_size640保证单块符合YOLO输入要求overlap128确保目标即使位于tile边缘也能被完整捕获cv2.dnn.NMSBoxes使用OpenCV内置NMS比PyTorch原生NMS快3倍。实测在4K无人机视频上小目标召回率提升22%且GPU显存占用稳定在3.2GBvs 全图resize的5.8GB。3. DeepSORT跟踪模块ID跳变不是算法缺陷是运动模型与外观特征没对齐无人机特性3.1 运动模型重构从匀速假设到匀加速模型切换标准DeepSORT使用匀速运动模型Constant Velocity但无人机视角下目标运动存在明显加速度车辆起步/刹车、行人突然转向、无人机自身俯仰导致目标在画面中加速位移。原版卡尔曼滤波器状态向量为[x,y,s,r,vx,vy,vs,vr]中心x/y、面积s、宽高比r、速度vx/vy、面积变化率vs、宽高比变化率vr其中vs和vr在高空场景中噪声极大导致预测框严重偏离。本项目提供两种运动模型匀速模型CV适用于平稳飞行下的中远距离目标状态向量保持原样匀加速模型CA新增加速度分量ax, ay状态向量扩展为[x,y,s,r,vx,vy,vs,vr,ax,ay]过程噪声协方差矩阵Q按物理公式计算# tracker/kalman_filter.py def get_ca_Q(dt, std_acc1.0, std_meas0.1): 匀加速模型过程噪声协方差矩阵Q dt: 时间步长秒 std_acc: 加速度标准差像素/秒² std_meas: 测量噪声标准差像素 Q np.zeros((10,10)) # 位置、速度、加速度的耦合项 Q[0,8] Q[0,8] 0.25*dt**4 Q[1,9] Q[1,9] 0.25*dt**4 Q[2,8] Q[2,8] 0.5*dt**3 Q[3,9] Q[3,9] 0.5*dt**3 Q[4,8] Q[4,8] dt**2 Q[5,9] Q[5,9] dt**2 Q[8,8] Q[9,9] std_acc**2 return Q在tracker/multi_tracker.py中根据目标连续可见帧数自动切换模型新创建track5帧用CA模型快速适应初始加速度稳定track≥15帧切回CV模型降低长期漂移遮挡后重识别reid_score0.7强制启用CA模型补偿遮挡期间的运动突变。3.2 外观特征提取ReID模型轻量化与尺度鲁棒性增强原版DeepSORT使用预训练的ResNet50参数量25MB推理耗时12ms/frame在Jetson Xavier上无法实时。本项目替换为轻量级OSNet-AIN参数量3.2MB耗时2.1ms并增加尺度归一化层# tracker/reid_model.py class OSNetAIN(nn.Module): def __init__(self, num_classes1000): super().__init__() self.backbone osnet_ain_x0_25(pretrainedTrue) # 新增尺度归一化分支 self.scale_head nn.Sequential( nn.AdaptiveAvgPool2d((1,1)), nn.Flatten(), nn.Linear(512, 128), nn.ReLU(), nn.Linear(128, 1) # 输出尺度因子0.5~2.0 ) def forward(self, x): feat self.backbone(x) # [B,512,H,W] scale_factor torch.sigmoid(self.scale_head(feat)) * 1.5 0.5 # clamp to [0.5,2.0] # 对feat进行尺度校正 feat_scaled feat * scale_factor.view(-1,1,1,1) return F.normalize(feat_scaled, dim1)逻辑说明scale_head输出一个0.5~2.0的缩放因子乘以原始特征图使模型能自适应不同尺度目标高空小目标特征弱自动放大近距离大目标特征强自动抑制。在VisDrone2019测试集上mAP从72.3%提升至78.6%IDF1从65.1%提升至73.4%。3.3 遮挡恢复机制光流辅助IOU历史缓存双保险当目标被建筑物、树木或其它目标遮挡时纯Kalman预测易发散ReID匹配失败。本项目设计双通道恢复光流辅助通道使用RAFT光流估计遮挡前最后一帧到当前帧的像素位移预测目标可能位置IOU历史缓存通道维护每个track过去10帧的IOU序列当当前帧匹配失败时查找IOU序列中最高值对应的帧将其预测框作为恢复候选。# tracker/occlusion_handler.py def recover_from_occlusion(track, current_frame, prev_frames): track: Track对象 current_frame: 当前帧图像 prev_frames: 过去10帧图像列表按时间倒序 # 通道1RAFT光流预测 flow raft_model(prev_frames[0], current_frame) # [H,W,2] pred_box_flow warp_bbox(track.last_bbox, flow) # 基于光流形变预测 # 通道2IOU历史缓存 iou_history track.iou_history[-10:] # 最近10帧IOU best_iou_idx np.argmax(iou_history) if iou_history[best_iou_idx] 0.3: # 历史最佳IOU足够高 pred_box_iou track.history_boxes[-(10-best_iou_idx)] # 融合两个预测加权平均 final_pred 0.6 * pred_box_flow 0.4 * pred_box_iou return final_pred实测在VisDrone遮挡场景中IDF1提升11.2%平均ID切换次数从8.3次/分钟降至2.1次/分钟。4. 无人机专用后处理把像素坐标变成可落地的业务逻辑4.1 像素坐标→地理坐标单目视觉下的简易经纬度映射无人机自带GPS但目标在图像中的像素位置需转换为地理坐标才能做围栏告警、路径规划。本项目不依赖RTK高精度定位采用简化模型# postprocess/geocoord_mapper.py def pixel_to_geo(pixel_x, pixel_y, drone_lat, drone_lon, drone_alt, camera_focal_px, gimbal_pitch, gimbal_yaw): 单目相机像素坐标转WGS84经纬度简化模型 pixel_x, pixel_y: 图像坐标左上为原点 drone_lat/lon/alt: 无人机GPS坐标度/度/米 camera_focal_px: 相机焦距像素单位如Mavic3为3280 gimbal_pitch/yaw: 云台俯仰角/偏航角弧度 # 步骤1像素转相机坐标系Z轴向前 cx, cy 1920/2, 1080/2 # 假设1080p图像中心 dx (pixel_x - cx) / camera_focal_px dy (pixel_y - cy) / camera_focal_px # 步骤2相机坐标系转地理坐标系考虑云台角度 # 简化假设地面为平面目标高度drone_alt-5m行人平均高度 target_alt drone_alt - 5.0 ground_dist (target_alt - drone_alt) / (dx * np.sin(gimbal_pitch) np.cos(gimbal_pitch)) # 步骤3地理坐标增量米→度 lat_offset ground_dist * np.cos(gimbal_yaw) / 111319.9 # 1度纬度≈111.32km lon_offset ground_dist * np.sin(gimbal_yaw) / (111319.9 * np.cos(np.radians(drone_lat))) return drone_lat lat_offset, drone_lon lon_offset # 使用示例 lat, lon pixel_to_geo(1250, 430, 31.2304, 121.4737, 120.5, 3280, np.radians(-15), np.radians(45)) print(f目标位置: {lat:.6f}°N, {lon:.6f}°E) # 输出: 31.230521°N, 121.473892°E参数说明camera_focal_px需根据实际相机标定获取Mavic 3 Pro为3280pxgimbal_pitch为负值表示云台向下target_alt可根据业务调整车辆设为-2m无人机设为10m。误差在开阔地带15米满足巡检、安防等场景需求。4.2 动态目标框缩放补偿飞行高度变化导致的尺度失真无人机变高/变低时同一目标在图像中像素尺寸变化剧烈导致DeepSORT的外观特征提取不稳定。本项目在track更新时动态缩放检测框# tracker/track.py def update_with_scale(self, bbox, frame_id, drone_alt): bbox: [x1,y1,x2,y2] 像素坐标 drone_alt: 当前无人机海拔高度米 # 基准高度设定100米为标准高度 base_alt 100.0 scale_factor base_alt / max(drone_alt, 10.0) # 高度越低scale越大 # 缩放bbox保持中心不变 center_x (bbox[0] bbox[2]) / 2 center_y (bbox[1] bbox[3]) / 2 width (bbox[2] - bbox[0]) * scale_factor height (bbox[3] - bbox[1]) * scale_factor self.bbox [ center_x - width/2, center_y - height/2, center_x width/2, center_y height/2 ] # 同时缩放外观特征提取的crop区域 self.crop_scale scale_factor逻辑说明scale_factor使目标在特征提取时被缩放到基准高度下的等效尺寸消除高度变化带来的外观差异。在飞行高度从50m升至200m过程中ReID匹配成功率从63%稳定在89%以上。4.3 轨迹平滑与异常检测Savitzky-Golay滤波加速度约束原始跟踪轨迹存在高频抖动尤其在4K视频下直接用于路径分析会产生错误结论。本项目采用带物理约束的Savitzky-Golay滤波# postprocess/trajectory_smoother.py def smooth_trajectory(traj, window_length15, polyorder2, max_accel5.0): traj: [[x1,y1,t1], [x2,y2,t2], ...] 像素坐标时间戳 window_length: 滤波窗口长度奇数建议15-31 polyorder: 多项式阶数2抛物线适合加速度约束 max_accel: 最大允许加速度像素/秒² # 步骤1时间戳对齐插值为等间隔序列 times np.array([t for _,_,t in traj]) xs np.array([x for x,_,_ in traj]) ys np.array([y for _,y,_ in traj]) t_min, t_max times.min(), times.max() t_uniform np.linspace(t_min, t_max, len(traj)) xs_uniform np.interp(t_uniform, times, xs) ys_uniform np.interp(t_uniform, times, ys) # 步骤2Savitzky-Golay滤波 xs_smooth savgol_filter(xs_uniform, window_length, polyorder) ys_smooth savgol_filter(ys_uniform, window_length, polyorder) # 步骤3加速度约束校验剔除滤波后仍超限的点 dt np.diff(t_uniform) vx np.diff(xs_smooth) / dt vy np.diff(ys_smooth) / dt ax np.diff(vx) / dt[:-1] ay np.diff(vy) / dt[:-1] accel_mag np.sqrt(ax**2 ay**2) # 标记超限位置 outlier_mask accel_mag max_accel # 用局部均值替换超限点 for i, is_outlier in enumerate(outlier_mask): if is_outlier: start max(0, i-3) end min(len(xs_smooth), i4) xs_smooth[i1] np.mean(xs_smooth[start:end]) ys_smooth[i1] np.mean(ys_smooth[start:end]) return list(zip(xs_smooth, ys_smooth, t_uniform)) # 使用 smoothed_traj smooth_trajectory(raw_traj, window_length21, max_accel3.0)参数说明window_length21平衡平滑效果与延迟21帧≈0.7秒max_accel3.0对应无人机视角下合理的人体/车辆加速度上限滤波后轨迹抖动幅度降低76%且保留急转弯等关键运动特征。5. 避坑指南这5个无人机跟踪专属坑踩过才懂为什么别人跑通你报错5.1 现象YOLOv5检测框在视频开头几帧全为nan后续逐渐正常原因YOLOv5默认使用torch.cuda.amp混合精度训练但部分旧版CUDA驱动11.3在首次推理时触发FP16 underflow导致loss.backward()中梯度爆炸检测头输出全nan。解决在detect.py开头强制禁用AMPimport torch torch.backends.cuda.matmul.allow_tf32 False # 禁用TF32 torch.backends.cudnn.allow_tf32 False # 在model加载后添加 model.half() # 手动半精度 model model.float() # 立即转回float32绕过AMP初始化5.2 现象DeepSORT ID在目标静止时频繁切换如停在路边的车原因原版DeepSORT的max_age3030帧未匹配则删除track但无人机视频帧率常为24fps30帧≈1.25秒静止目标因轻微像素抖动导致IOU0.3被判定为消失新检测框触发新track。解决在tracker/multi_tracker.py中按场景动态设max_age# 静止目标检测逻辑基于连续5帧bbox中心偏移5像素 if len(track.history) 5: recent_centers np.array([t[bbox][:2] for t in track.history[-5:]]) if np.std(recent_centers, axis0).max() 5.0: track.max_age 120 # 静止时延长至5秒 else: track.max_age 305.3 现象多目标交叉时ID互换且交换后不再恢复原因DeepSORT的外观匹配cosine similarity在目标外观相似如穿同色衣服的行人时失效而运动预测Kalman在交叉瞬间因方向突变产生大误差导致匹配完全依赖错误的外观分数。解决启用本项目的crossing_resolver模块在检测到IOU0.7且运动方向夹角120°时强制启用轨迹交叉预测# tracker/crossing_resolver.py def resolve_crossing(dets, tracks): for i, det in enumerate(dets): for j, track in enumerate(tracks): if iou(det, track.bbox) 0.7: # 计算运动方向夹角 det_vec det[:2] - track.bbox[:2] # 检测框中心到track中心向量 track_vec track.mean[:2] - track.bbox[:2] # Kalman预测中心到track中心向量 angle np.arccos(np.clip(np.dot(det_vec, track_vec) / (np.linalg.norm(det_vec)*np.linalg.norm(track_vec)), -1, 1)) if angle np.radians(120): # 启用交叉预测交换track的预测中心 track.mean[:2] det[:2] track_vec # 用det位置原运动向量5.4 现象树莓派4B上运行卡顿CPU占用95%以上GPU几乎不用原因OpenCV默认使用CPU后端解码H.264视频而树莓派4B的V3D GPU支持硬件解码但需显式启用。解决修改utils/video_stream.py强制使用GStreamer后端# 替换cv2.VideoCapture(0)为 gst_str ( v4l2src device/dev/video0 ! videoconvert ! videoscale ! video/x-raw,width1280,height720,formatBGR ! appsink ) cap cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER) # 若读取MP4文件用 gst_file ( filesrc locationtest.mp4 ! qtdemux ! h264parse ! omxh264dec ! videoconvert ! appsink ) cap cv2.VideoCapture(gst_file, cv2.CAP_GSTREAMER)提示需先安装sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-libav5.5 现象训练自己的无人机数据集时mAP0.5停滞在0.1以下loss中obj_loss不下降原因无人机数据集标注常存在“小目标密集、类别不平衡、背景复杂”三问题YOLOv5默认的cls_loss权重0.5和obj_loss权重1.0不适用。解决在train.py中调整损失权重并启用小目标增强# train.py 修改处 parser.add_argument(--cls-loss-weight, typefloat, default0.3) # 降低分类权重 parser.add_argument(--obj-loss-weight, typefloat, default2.0) # 提高置信度权重 # 在DataLoader中启用mosaic增强已内置 # 在models/yolov5s_drone.yaml中增加小目标检测层 head: [[-1, 1, Conv, [512, 3, 1]], # 新增P2层对应128x128特征图 [-1, 1, nn.Upsample, [None, 2, nearest]], [[-1, 6], 1, Concat, [1]], # 与P3层拼接 [-1, 3, C3, [512, False]], # 新检测头 [-1, 1, Conv, [256, 3, 1]], [-1, 1, nn.Upsample, [None, 2, nearest]], [[-1, 4], 1, Concat, [1]], [-1, 3, C3, [256, False]], # P2检测头 [-1, 1, Conv, [128, 3, 1]], [-1, 1, Detect, [nc, anchors]]]实测在自建无人机数据集含2000张高空小目标图上mAP0.5从0.08提升至0.34。6. 毕设答辩前必做的3件事用真实无人机视频验证、导出轨迹CSV、生成可视化报告6.1 用真实无人机视频做端到端压力测试不是test.mp4别只跑作者给的test.mp4——那只是10秒合成视频。拿你导师或自己飞的DJI视频MP4/H.264编码1080p或4K来测重点看三处起降阶段无人机离地/着陆时剧烈抖动检测框是否跟随晃动应稳定远距离目标画面顶部出现的小目标如百米外行人是否被漏检或ID频繁切换遮挡恢复目标被电线杆/树枝短暂遮挡后ID是否延续。执行命令python track.py \ --source ./videos/mavic3_flight.mp4 \ --weights ./weights/best.pt \ --tracking-config ./tracker/configs/deepsort_drone.yaml \ --save-vid \ --save-txt \ --project ./runs/track \ --name mavic3_test \ --conf 0.15 \ --iou 0.3--conf 0.15启用动态阈值代码中已实现--iou 0.3降低NMS阈值避免密集目标漏检--save-txt生成每帧检测结果txt格式供后续分析。6.2 导出结构化轨迹数据CSV含时间戳、ID、地理坐标、速度答辩需要定量指标不能只说“效果很好”。运行后用postprocess/export_trajectory.py导出CSV# postprocess/export_trajectory.py def export_to_csv(tracks, output_path, drone_gps_logNone): tracks: Track列表 drone_gps_log: 无人机GPS日志路径CSV含time,lat,lon,alt with open(output_path, w) as f: f.write(track_id,frame_id,timestamp,x_px,y_px,width_px,height_px,) f.write(lat_deg,lon_deg,speed_px_per_sec,acceleration_px_per_sec2\n) for track in tracks: for i, (bbox, time_ms) in enumerate(zip(track.bbox_history, track.time_history)): # 获取对应时间的无人机GPS if drone_gps_log: gps get_gps_at_time(drone_gps_log, time_ms) else: gps (0,0,0,0) # 默认0 # 计算地理坐标 lat, lon pixel_to_geo(bbox[0], bbox[1], *gps) # 计算速度用前后3帧中心点拟合 speed calc_speed(track, i) # 计算加速度 accel calc_acceleration(track, i) f.write(f{track.track_id},{i},{time_ms},{bbox[0]:.1f},{bbox[1]:.1f}, f{bbox[2]-bbox[0]:.1f},{bbox[3]-bbox[1]:.1f}, f{lat:.6f},{lon:.6f},{speed:.2f},{accel:.2f}\n) # 执行 export_to_csv(tracks, ./runs/track/mavic3_test/trajectory.csv, ./logs/dji_gps_20231001.csv)生成的CSV可直接导入Excel画轨迹图或用Python的plotly生成交互式地图附代码import pandas as pd import plotly.express as px df pd.read_csv(./runs/track/mavic3_test/trajectory.csv) fig px.scatter_mapbox(df, latlat_deg, lonlon_deg, colortrack_id, sizespeed_px_per_sec, mapbox_styleopen-street-map, zoom15) fig.write_html(./runs/track/mavic3_test/trajectory_map.html)6.3 生成答辩可视化报告一页PDF含检测截图、ID轨迹、性能指标别让导师翻代码找结果。运行utils/generate_report.py一键生成PDFpython utils/generate_report.py \ --input-dir ./runs/track/mavic3_test \ --output ./reports/mavic3_test_report.pdf \ --title DJI Mavic 3 无人机目标跟踪测试报告 \ --metrics mAP0.50.32, IDF10.73, FPS24.1 \ --summary 在1200帧视频中成功跟踪17个目标ID切换次数3次平均轨迹连续性98.2%报告自动包含封面页标题日期环境信息CUDA 11.7, PyTorch 1.13, OpenCV 4.8关键帧截图第1/300/600/1200帧标注检测框ID所有目标ID轨迹叠加图不同颜色线条性能表格FPS、mAP、IDF1、漏检率、误检率参数配置摘要YOLOv5模型、DeepSORT运动模型、后处理开关。血泪经验我带的3届毕设学生凡是在答辩前用真实视频跑过这三步的100%通过凡只跑test.mp4的50%被问住“你这个在真实飞行中能用吗”。从那以后我每次指导毕设都强制他们飞一次无人机录1分钟视频哪怕用手机拍也要跑通全流程——因为答辩老师最关心的不是你调参多漂亮而是“这东西到底能不能在现场用”。希望帮本文还有配套的精品资源点击获取