news 2026/10/23 5:04:52

目标到底移动得有多快?我用 YOLO + ByteTrack 做了视频速度估计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
目标到底移动得有多快?我用 YOLO + ByteTrack 做了视频速度估计

项目地址:
yolo-object-detection-lab:基于 FastAPI 与 Ultralytics YOLO 的图像目标检测实验项目 - AtomGit

前面几篇里,这个项目已经从目标检测一路做到:

Single Image → Batch Images → Video → Tracking → Line Crossing → ROI Analysis → Trajectory Heatmap → Multi-ROI Flow

做到这里之后,已经可以回答:

目标是什么?
是不是同一个目标?
有没有经过某条线?
进入了哪个区域?
在区域里停留多久?
从哪个区域去了哪里?

但还有一个很自然的问题:

这个目标到底移动得有多快?

所以这一次,我继续在 YOLO + ByteTrack 的基础上加入第九种模式:

Speed Estimation

用 Track ID 的连续位置变化,估计目标在视频中的运动速度。


一、这次做的不是“直接算车速”

先说明一个很重要的问题。

普通单目视频里,如果没有真实世界尺度标定,就不能直接把像素位移写成:

30 km/h 50 km/h

因为图像里:

100 px

到底代表 1 米还是 10 米,取决于摄像机位置、透视关系和目标所在区域。

所以这次我把速度分成两种:

Pixel Speed

单位:

px/s

以及完成尺度标定之后才允许使用的:

m/s km/h

这次真实运行结果主要使用的是px/s 模式,这样不会为了得到“看起来像真实车速”的数字而强行换算。


二、速度怎么从 ByteTrack 轨迹算出来?

ByteTrack 已经能够给每个目标一个稳定的 Track ID。

例如:

person #13 car #15 car #16

每一帧都会得到这个目标新的位置。

和前面 ROI、Line Crossing 一样,这次仍然使用:

Bottom-center Anchor

也就是 Bounding Box 底部中心:

anchor_x = (x1 + x2) / 2 anchor_y = y2

原因也很直接:

对于行人,它更接近脚落在地面的位置;

对于车辆,它也更接近车辆在道路上的实际位置。


三、Pixel Speed 的计算

假设同一个 Track 在两帧中的位置分别是:

P1 = (x1, y1) P2 = (x2, y2)

像素位移:

distance_px = sqrt((x2 - x1)^2 + (y2 - y1)^2)

再根据两帧时间差:

delta_time

计算:

speed_px_s = distance_px / delta_time

最终单位就是:

px/s

比如:

80 px/s

表示这个目标在图像平面中,每秒大约移动 80 个像素。


四、为什么不能直接显示单帧速度?

目标检测框不是完全稳定的。

即使目标实际运动很平滑,bbox 也可能出现:

左抖一下 右抖一下 突然跳几像素

如果直接拿每两帧的位置算速度,就很容易出现:

30 42 38 160 35 40

这种明显抖动。

所以这次加入了:

Smoothing Window

我实际使用:

5

并采用:

Moving Average

也就是用最近 5 个速度样本求平均。

最终页面主要展示的是:

Smoothed Speed

而不是完全依赖单帧瞬时值。


五、还需要过滤异常位移

除了普通抖动,还有一种更严重的情况:

Track 在某一帧突然跳到了很远的位置。

这种情况可能来自:

检测框变化 遮挡 Track 重关联 目标重新出现

所以这次增加了:

Max Pixel Jump

真实测试设置为:

200 px

如果单帧位置跳变超过这个范围,就不会直接把这次异常位移纳入正常速度统计。

这样可以避免一个异常帧把整个 Track 的平均速度拉得特别高。


六、真实测试参数

这次继续使用前面几篇一直测试的道路视频:

Resolution: 1920×1080 FPS: 29.97 Total Frames: 962 Duration: 32.10 s

实际参数:

Confidence Threshold: 0.55 Frame Interval: Every Frame Smoothing Window: 5 Smoothing Method: Moving Average Max Pixel Jump: 200 px Speed Threshold: 0 Display Unit: px/s Show Track Trails: ON Trail Length: 30


七、962 帧完整跑完

最终运行结果:

962 / 962 Frames 100%

处理时间:

74.9 s

Tracking 得到:

Unique Tracks: 37 Tracks With Speed: 34

也就是说:

整个视频一共识别到 37 个不同 Track,其中 34 个拥有足够连续的位置数据,可以计算速度。


八、真实速度统计结果

最终 Speed Summary:

Unique Tracks: 37 Tracks With Speed: 34 Average Pixel Speed: 80.8 px/s Max Pixel Speed: 2047.1 px/s

这里要注意:

2047.1 px/s

不是:

2047 km/h

它只是图像平面中的像素速度峰值。

像素速度会受到:

透视关系 目标距离摄像机远近 检测框尺寸变化 目标运动方向

等因素影响。

所以它更适合:

同一视频 同一区域 相同摄像机条件

下的相对速度分析。


九、每一个 Track 都能单独看速度

这次页面还增加了:

Track Speed Table

每个目标都会记录:

Track ID Class Frames Average Speed Max Speed Distance Duration

例如一个 Car Track 可以看到:

Average: xx px/s Max: xx px/s Distance: xxx px Duration: x.xx s

而 Person、Car 等不同类别也可以分别查看。

这就比单纯显示:

Current Speed

更有用,因为它能够看完整个 Track 生命周期中的运动情况。


十、结果视频里可以直接看实时速度

最终 Result Video 中仍然保留:

Bounding Box Track ID Class Confidence Trajectory Speed

这样在视频播放过程中,就能看到目标位置变化和速度统计同步更新。

相比只看最后的表格,视频更容易判断:

为什么这个 Track 某一段速度突然变快?

某个目标是不是因为靠近摄像机导致像素速度明显增加?


十一、为什么有 37 个 Track,但只有 34 个能算速度?

因为速度至少需要:

两个有效时间点

如果某个目标只出现很短时间,例如:

1 帧

或者缺乏连续有效位置,那么就没有办法计算:

Δdistance / Δtime

所以:

Unique Tracks

和:

Tracks With Speed

本来就不应该完全相同。

这次实际是:

37 ↓ 34

属于正常结果。


十二、还加入了两点尺度标定

除了 px/s,这次也实现了一个简单的:

Two-point Calibration

用户可以在视频首帧上点击:

P1 P2

然后输入这两个点在真实世界中的已知距离。

例如:

5 m

系统就可以得到一个局部近似比例:

meters_per_pixel

之后理论上可以把:

px/s

转换为:

m/s km/h

不过这种两点标定需要谨慎使用。

因为道路视频存在明显透视:

远处 100 px

和:

近处 100 px

通常并不代表相同的真实距离。

所以这种方法更适合:

在比较小的局部平面区域内做近似尺度估计。

如果需要更严格的真实速度,还应该进一步加入:

Homography Perspective Transform Bird's-eye View

做道路平面标定。


十三、为什么这篇主要展示 px/s?

这也是我这次刻意保留的设计。

如果没有足够可靠的标定信息,程序就只显示:

px/s

而不是自动生成一个:

xx km/h

因为后者看起来更“高级”,但很容易产生误导。

这次真实测试中:

Average Pixel Speed = 80.8 px/s

这个数字虽然不是实际道路车速,但它是从真实 Track 位置和真实视频 FPS 中计算出来的。

它可以用于:

同一场景下比较快慢 发现异常运动 轨迹行为分析 后续标定前的数据验证


十四、Speed Threshold

这次还预留了:

Speed Threshold

可以设置:

100 px/s

或者标定以后设置:

10 km/h

当 Track 超过阈值时,可以生成:

SPEED_THRESHOLD Event

不过这次实际测试中设置为:

0

所以:

Speed Events = 0

没有启用阈值事件。

这里也没有把它写成:

“超速事件”

因为除非用户提供真实道路限速和可靠标定,否则这里只能叫:

Speed Threshold Event

而不是交通意义上的“超速”。


十五、支持结果导出

Speed Estimation 也支持:

Export Speed JSON Export Tracks CSV Export Speed Events CSV

JSON 可以保存:

video metadata settings calibration speed summary tracks events

Tracks CSV 则适合后续用:

Excel Pandas

继续统计:

平均速度 最大速度 运动距离 持续时间

而且导出使用的是当前已经完成的结果,不会重新跑 YOLO。


十六、391 个测试全部通过

加入 Speed Estimation 以后,项目完整测试增加到:

391 pytest passed

前端:

257 assertions passed

新增测试主要覆盖:

Bottom-center Anchor Pixel Distance px/s delta_time Moving Average Median Outlier Filter Track History Average / Max Speed Distance Calibration m/s km/h Threshold Event 0 Track Stale Result Reset YOLODetectorError

而之前所有模式:

Single Image Batch Images Video Tracking Line Crossing ROI Heatmap Multi-ROI

都没有回归。


十七、现在这个项目已经有 9 种模式

做到这里以后,整个项目已经变成:

Single Image ↓ Batch Images ↓ Video Detection ↓ ByteTrack Tracking ↓ Line Crossing ↓ ROI Occupancy & Dwell ↓ Trajectory Heatmap ↓ Multi-ROI Flow ↓ Speed Estimation

每一步其实都在回答一个新的问题。

最开始:

这是什么?

后来:

它是不是刚才那个目标?

再后来:

它去了哪里?

经过了哪里?

在哪里停留?

最常走哪些区域?

从哪个区域去了哪个区域?

而现在:

它移动得有多快?


总结

这次真实运行结果:

962 Frames 37 Unique Tracks 34 Tracks With Speed Average Pixel Speed: 80.8 px/s Max Pixel Speed: 2047.1 px/s Processing Time: 74.9 s

整个速度估计链路可以概括成:

YOLO ↓ ByteTrack ↓ Track ID ↓ Bottom-center Anchor ↓ Frame-to-frame Distance ↓ delta_time ↓ Pixel Speed ↓ Smoothing ↓ Outlier Filtering ↓ Speed Statistics

同时还加入了可选的两点尺度标定,为后续:

px/s → m/s → km/h

预留了接口。

项目地址:

yolo-object-detection-lab:基于 FastAPI 与 Ultralytics YOLO 的图像目标检测实验项目 - AtomGit

下一步如果继续往下做,我准备进一步加入:

Perspective Calibration + Bird's-eye View

把现在的像素速度估计继续往更接近真实世界尺度的运动分析推进。

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

看懂IEC 62619:2022:工业锂电安全测试与BMS设计要点

简介:IEC 62619:2022(Edition 2.0 2022-05)是国际电工委员会发布的工业用二次锂电池和蓄电池安全要求标准,面向电池设计、制造、测试及使用环节的工程师与合规人员,适合动力电池、储能系统、工业设备等领域的研发和质量…

作者头像 李华
网站建设 2026/10/22 6:57:10

手调格式一小时 vs 科迅捷AI十分钟,哪个更省心

写论文的同学都体会过手调格式的痛苦:标题字号不对、行距不统一、目录页码错乱、图表编号断开、参考文献格式参差。如果你完全靠手动调,一小时能完成的工作量,往往只够你把第一章的标题统一一下。今天我们就来对比一下,手调一小时…

作者头像 李华
网站建设 2026/10/21 5:46:56

NOC指导教师认证真题拆解:递归、二分与机器人巡线核心考点

简介:这份资料围绕全国中小学信息技术创新与实践大赛(NOC)指导教师认证真题整理而成,面向备考该认证的指导教师及竞赛辅导人员,覆盖编程基础、机器人、人工智能、算法与数据结构等核心考点,适合用于考前自测…

作者头像 李华
网站建设 2026/10/23 5:04:51

从shp到sumo:路网转换链路与netconvert参数实战

1. 从shp到osm再到sumo:这条链路到底在解决什么问题 做交通仿真的人迟早会撞上一个很现实的问题:手头拿到的路网数据是shp格式的。可能是从某个地理信息平台下载的,也可能是合作方给的,甚至是从CAD图纸转出来的。但sumo这个仿真工…

作者头像 李华
网站建设 2026/10/23 5:04:34

UML动态视图:系统行为的可执行说明书

1. 什么是UML动态视图:它不是画给老板看的流程图,而是写给系统“听”的行为说明书很多人第一次接触UML动态视图,是在某次需求评审会上——产品经理在白板上画了个带箭头的框图,说这是“时序图”,然后转头问开发&#x…

作者头像 李华
网站建设 2026/10/22 8:09:56

Unity中如何准确判断GameObject是否源自磁盘Prefab

1. 为什么“判断对象是不是预制体”这件事,连资深Unity开发者都常踩坑在某次跨团队协作的项目重构中,我接手了一套运行了三年的UI系统。上线前夜,测试同学突然反馈:部分界面在热更后出现按钮点击无响应、文本错位、甚至整个Panel直…

作者头像 李华