两个目标会不会发生冲突?我用 YOLO + ByteTrack 做了 TTC 碰撞风险分析

项目地址:

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

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

Single Image

↓

Batch Images

↓

Video Detection

↓

ByteTrack Tracking

↓

Line Crossing

↓

ROI Analysis

↓

Trajectory Heatmap

↓

Multi-ROI Flow

↓

Speed Estimation

↓

Perspective Calibration

↓

Trajectory Prediction

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

目标是谁?

目标在哪里?

目标走过哪里?

目标速度大概有多快?

目标未来几秒可能往哪里走?

那下一步自然就是:

如果两个目标正在同时运动,它们会不会在短时间内发生明显的轨迹冲突?

所以这一次,我继续在现有 YOLO + ByteTrack + Perspective Calibration 的基础上加入了:

Collision Risk Estimate

也就是基于两个目标当前的相对位置和相对速度,计算它们未来短时间内的最近接近情况。

这里要先说明:

这不是"事故预测"。

它只是一个基于运动学规则的:

短时碰撞风险估计。


一、这次到底分析什么?

对于任意两个正在跟踪的目标,例如:

Track A

Track B

系统会计算:

Current Distance

Relative Velocity

Time To Closest Approach

Minimum Predicted Distance

Risk Level

最终风险等级分为:

Low

Medium

High

所以它不只是看:

"两个目标现在离得近不近"

而是更关注:

它们是不是正在快速靠近,以及未来几秒最接近的时候会有多近。


二、为什么只看当前距离不够?

举个很简单的例子。

两个目标现在距离只有 2 米。

但如果它们正在:

互相远离

那其实当前短时风险并不高。

反过来:

两个目标现在距离 10 米

但是它们正在快速朝同一个交汇点运动,

那未来 1~2 秒反而可能出现更明显的冲突风险。

所以这次不能只看:

Current Distance

还需要同时看:

Relative Position

Relative Velocity

TCA

Minimum Distance


三、目标位置仍然使用 Bottom-center Anchor

为了和前面的:

Line Crossing

ROI

Heatmap

Speed

Trajectory Prediction

保持一致,

这次还是继续使用:

Bottom-center Anchor

计算方式:

anchor_x = (x1 + x2) / 2

anchor_y = y2

对于道路视频来说,这个点比 bbox 中心更接近目标实际所在的地面位置。

所以每一个 Track 都会保存:

Track ID

Class

Position

Velocity

Timestamp

然后再进行目标对分析。


四、Perspective 4-Point 继续参与分析

这次我仍然使用前面已经实现的:

Perspective 4-Point Calibration

也就是先在原图中选择四个道路平面点,再输入这个区域对应的真实尺寸。

这次继续使用:

Width:6 m

Height:12 m

整个空间转换过程就是:

原始视频坐标

↓

Homography

↓

Bird's-eye Plane

↓

米制坐标

这样两个目标之间的距离就可以在鸟瞰平面中计算。

如果没有 Perspective Calibration,也可以进行 Pixel-space Risk Analysis。

但这种情况下,UI 会明确显示:

Pixel-space risk only

不会把像素距离伪装成真实米制距离。


五、两个目标是怎么配对的?

假设当前有两个目标:

Track A

Track B

它们在鸟瞰平面中的位置分别是:

PA

PB

对应速度分别是:

VA

VB

那么相对位置就是:

relative_position = PB - PA

相对速度:

relative_velocity = VB - VA

当前距离:

distance = ||relative_position||

这一步其实就是把问题从:

"两个独立运动的目标"

转换成:

"B 相对于 A 在怎么运动"。


六、TCA:多久之后它们最接近?

这次最核心的指标之一就是:

TCA

也就是:

Time To Closest Approach

可以理解为:

按照当前速度继续运动,两个目标大约多久之后会达到最近位置?

计算方式:

t_closest = - dot(relative_position, relative_velocity) / ||relative_velocity||²

如果两个目标当前正在互相靠近,

那么 t_closest 通常会是一个正数。

例如:

TCA = 1.5 s

可以理解成:

如果当前运动趋势不变,大约 1.5 秒后两个目标会达到最近接近状态。


七、哪些情况不应该判高风险?

这里有几个很重要的边界情况。

如果:

relative velocity 很小

说明两个目标相对运动不明显。

或者:

t_closest <= 0

说明最近接近时刻其实已经过去了,两个目标现在更可能正在远离。

再或者:

t_closest > Risk Horizon

比如只分析未来 3 秒,但最近接近时间是 8 秒以后,

那就不应该把它判成当前短时高风险。

所以:

不是距离近就危险,也不是两个目标同时出现就危险。


八、Minimum Predicted Distance

得到 TCA 以后,还需要继续计算:

两个目标在最近接近时,究竟会离多近?

公式是:

closest_relative = relative_position + relative_velocity × t_closest

然后:

minimum_distance = ||closest_relative||

这个指标比 Current Distance 更重要。

因为它回答的是:

如果保持当前运动状态,未来最近的时候,两者预计还剩多少距离?


九、Risk Level 怎么判?

这次使用的是一套可解释的启发式规则。

默认规则:

High:

TCA <= 2 s

并且

Minimum Distance <= 1.5 m

Medium:

TCA <= 3 s

并且

Minimum Distance <= 3 m

其他情况:

Low

也就是说:

时间越短

距离越小

风险等级越高

但这里一定要强调:

Risk Level 不是事故概率。

High 并不代表:

"90% 会发生碰撞"。

它只是表示:

按照当前运动状态继续发展,两个目标在短时间内存在更明显的空间冲突趋势。


十、真实测试参数

这次还是继续使用之前一直测试的同一段道路视频。

视频信息:

Resolution:1920×1080

FPS:29.97

Total Frames:962

Duration:约 32 秒

Perspective Calibration:

Width:6 m

Height:12 m

风险设置主要包括:

Confidence Threshold

Frame Interval

Risk Horizon

Minimum Track History

Minimum Current Distance

Maximum Analysis Distance

High TCA Threshold

High Minimum Distance

Medium TCA Threshold

Medium Minimum Distance

Class Pair Filter

这次 Class Pair Filter 使用:

All

也就是让系统分析所有满足条件的目标对。


十一、962 帧全部处理完成

最终:

962 / 962 Frames

100%

真实结果:

Unique Tracks:37

Pairs Analyzed:122

Risk Events:236

High Risk Events:123

Medium Risk Events:113

Processing Time:约 61.2 s

Calibration Mode:

perspective

这说明整条链路已经实际跑通:

YOLO

↓

ByteTrack

↓

Bottom-center

↓

Perspective Homography

↓

Pair Analysis

↓

Relative Position

↓

Relative Velocity

↓

TCA

↓

Minimum Distance

↓

Risk Level


十二、122 个 Pairs Analyzed 是什么意思?

这次一共检测并跟踪到:

37 个 Unique Tracks

理论上如果全部两两组合,会有很多 pair。

但系统不会无条件分析所有组合。

它还会受到:

Minimum Track History

Maximum Analysis Distance

Class Pair Filter

Track Active State

等条件影响。

最终真正进入风险计算的是:

122 个目标对

这个数字比直接做全组合更合理,也能减少大量无意义的远距离 pair。


十三、236 个 Risk Events 不等于 236 次"险情"

这次结果中:

Risk Events:236

其中:

High:123

Medium:113

刚好:

123 + 113 = 236

说明事件统计是对得上的。

但是这里必须特别说明:

236 个 Risk Events 不等于发生了 236 次真实危险事故。

更准确的说法应该是:

系统在整段视频中生成了 236 条基于运动学规则的短时冲突风险事件,其中 123 条达到 High,113 条达到 Medium。

这些只是:

Collision Risk Estimates

不是现实事故次数。


十四、为什么需要 Debounce?

如果一个 pair 连续几十帧都保持 High,

那如果每一帧都生成一个 event,

最终日志会变成:

High

High

High

High

High

......

完全没有意义。

所以这次加入了:

Debounce / Cooldown

规则是:

同一个 pair 如果持续处于高风险状态,

只创建一次 event。

只有当:

风险解除

然后后面再次进入风险,

才会创建新的 event。


十五、Pair Key 为什么要顺序无关?

例如:

Track 12 和 Track 18

系统必须认为:

(12,18)

和:

(18,12)

是同一个目标对。

否则会出现:

A→B 算一次

B→A 又算一次

造成重复统计。

所以 pair key 会做顺序归一化。

这也是事件去重的基础。


十六、Result Video 里会显示什么?

最终 Result Video 中会保留:

Bounding Box

Track ID

Class

同时对于存在风险的目标对,还会显示:

Pair Connection

Risk Level

TCA

Minimum Distance

这样可以直接从视频中看到:

哪些目标正在形成风险 pair。

相比只看表格,这种可视化会更直观。


十七、Class Pair Summary

这次还增加了:

Class Pair Summary

也就是按类别组合统计。

例如:

car-car

car-person

car-bicycle

person-bicycle

这样后面就可以进一步分析:

哪种类别组合产生的风险事件更多?

例如:

车-车

车-人

车-自行车

这比单纯统计一个总 Risk Events 更有分析意义。


十八、Risk Table

Risk Table 中会展示每一个目标对的详细信息。

包括:

Track A

Class A

Track B

Class B

Current Distance

Relative Speed

TCA

Minimum Distance

Risk Level

这张表其实是整个功能最关键的分析区域之一。

因为它可以直接看到:

当前距离到底多远

相对速度多大

多久后最近

最近预计还剩多少距离

最终为什么被判成 High / Medium / Low


十九、Risk Events

除了实时 Pair Table 以外,

系统还会保存:

Risk Events

也就是说:

某个 pair 在什么时间进入风险状态

风险等级是什么

TCA 是多少

Minimum Distance 是多少

这些数据后面都可以导出做进一步分析。


二十、Minimum TCA = 0.00 s 怎么理解?

这次结果里:

Minimum TCA:0.00 s

看起来会很夸张。

但这并不一定代表系统出错。

因为实际内部值经过显示格式化以后,可能是:

非常接近 0 的正数

最后显示成:

0.00 s

这意味着某些目标对在某个时刻:

几乎正处于最近接近状态。

但是这个结果仍然需要结合:

检测框位置

目标类别

Homography

道路尺寸标定

一起判断。

不能单独看到 0.00 s 就说:

"马上发生碰撞"。


二十一、Minimum Predicted Distance = 0.01 m 也不能直接当真实距离

这次最小预测距离是:

0.01 m

也就是 1 cm。

对于普通街景来说,这个数字显然非常小。

它可能来自:

两个 Bottom-center 在鸟瞰平面中非常接近

Bounding Box 抖动

目标遮挡

Homography 放大误差

人工 6m × 12m 标定尺度不完全准确

所以:

0.01 m

应该理解成:

当前模型和标定条件下得到的最小预测间距估计值。

不能直接宣传成:

"真实两个目标只差 1 cm"。


二十二、这也是为什么 Perspective Calibration 很重要

如果完全在原始像素空间中做分析,

例如:

Current Distance = 80 px

这个数其实很难解释。

但经过 Perspective Calibration 后,

至少可以把问题转到:

Bird's-eye Plane

中。

这样:

Distance

Relative Velocity

Minimum Distance

就可以按米制平面进行解释。

虽然依然是估计值,

但比单纯像素分析更有实际意义。


二十三、无标定时也能运行

这一版并不是强制必须 Perspective。

如果不做四点标定,

系统仍然可以运行:

Pixel-space Risk Analysis

但这时候页面会明确告诉用户:

Pixel-space risk only

这时:

Current Distance

Minimum Distance

只能解释为像素距离,

不能写成:

m

m/s

这也是为了避免"单位看起来很真实,但实际上没标定"的问题。


二十四、过滤机制很重要

Collision Risk 最大的问题之一就是:

目标一多,pair 数量会快速增加。

所以这次加入了多种过滤条件:

Minimum Track History

Minimum Current Distance

Maximum Analysis Distance

Class Pair Filter

例如:

Maximum Analysis Distance = 30 m

那么两个目标如果已经相距很远,

就没必要继续做短时碰撞风险分析。

这样可以减少很多无意义的 pair。


二十五、为什么不直接用 Trajectory Prediction 判断?

上一篇已经做了:

Trajectory Prediction

理论上也可以看两条未来轨迹是不是交叉。

但这次选择 TCA + Minimum Distance,

有一个很大的优点:

更容易解释。

因为最终可以明确回答:

多久后最近?

最近距离多少?

当前是否正在接近?

而不是只看两条线有没有视觉交叉。

所以这次其实是:

Trajectory Prediction

进一步走向:

Relative Motion Analysis


二十六、这次测试增加到 601 个

Collision Risk 完成后:

601 pytest passed

前一版:

511

新增:

90 个后端测试

前端:

348 assertions passed

前一版:

308

新增:

40 个前端断言

测试覆盖了:

Relative Position

Relative Velocity

Current Distance

Approaching Pair

Separating Pair

Parallel Motion

Stationary Pair

TCA

Minimum Distance

Risk Horizon

Low / Medium / High

Threshold Boundary

Pair Key

Debounce

Cooldown

Zero Tracks

One Track

Perspective Coordinate

Pixel Fallback

Invalid Calibration

NaN Protection

Class Pair Filter

Export

Stale Reset

Detector Failure

之前所有模式也全部保留。


二十七、开发分支

这次使用:

Branch:

feat/collision-risk

Commit:

b965204a537cd9e1b6c3155e59bc08fe44a4d68e

主要新增:

app/collision_risk.py

static/collision.js

tests/test_collision.py

同时修改:

app/main.py

app/schemas.py

static/index.html

static/app.js

tests/test_frontend_logic.js


二十八、现在项目已经从"看见目标"走到了"分析关系"

做到这一篇以后,整个项目路线已经变成:

Detection

↓

Tracking

↓

Trajectory

↓

Speed

↓

Prediction

↓

Relative Motion

↓

Collision Risk

也就是说,系统分析的不再只是:

单个目标

而开始进入:

目标与目标之间的关系分析。


总结

这次真实实验最终得到:

962 Frames

37 Unique Tracks

122 Pairs Analyzed

236 Risk Events

123 High Risk Events

113 Medium Risk Events

Minimum TCA:0.00 s

Minimum Predicted Distance:0.01 m

Calibration Mode:perspective

Processing Time:约 61.2 s

完整技术链路:

YOLO

↓

ByteTrack

↓

Bottom-center Anchor

↓

Perspective Homography

↓

Track Position / Velocity

↓

Pair Matching

↓

Relative Position

↓

Relative Velocity

↓

TCA

↓

Minimum Predicted Distance

↓

Risk Level

↓

Risk Events

这一次系统已经不只是回答:

目标现在在哪里?

也不只是:

目标未来可能往哪里走?

而是进一步尝试回答:

两个目标按照当前运动趋势继续下去,会不会在短时间内形成明显的空间冲突?

当然,这仍然是:

Heuristic Collision Risk Estimate

不是事故概率,也不是自动驾驶级安全决策系统。

但对于一个从 YOLO 检测逐步扩展出来的视频分析项目来说,这一步已经让系统从:

Single-object Analysis

继续走向:

Multi-object Interaction Analysis

项目地址:

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

下一步如果继续做,我准备在现有 Collision Risk 基础上加入:

Near-Miss Detection

也就是不只看每一帧的瞬时 Risk Level,

而是进一步判断:

一次完整的"险些发生冲突"事件到底是怎么形成的。

相关推荐
system_error_x5 小时前
YOLOv8 研究方向及价值:从目标检测到多任务视觉基座
yolo·目标检测·目标跟踪
晨间晓5 小时前
目标下一秒会往哪里走?我用 YOLO + ByteTrack 做了轨迹预测
yolo
AI棒棒牛1 天前
YOLO26 改进:融合 LW-DETR 思想的轻量 TokenMixer,让 Neck 从局部堆叠走向局部-全局协同!嘎嘎创新!
人工智能·深度学习·yolo·目标检测
Reload.1 天前
深度学习-极验叠字点选-yolo-模型调优-高阶数学-opencv
人工智能·深度学习·opencv·yolo·计算机视觉·视觉检测
晨间晓2 天前
目标从哪个区域去了哪里?我用 YOLO + ByteTrack 做了多 ROI 区域流转分析
yolo
YOLO数据集集合2 天前
滑坡检测数据集 | 滑坡检测 地质灾害 无人机巡检 应急响应 目标检测 YOLO格式 深度学习数据集 计算机视觉10670期
深度学习·yolo·目标检测·计算机视觉·无人机·滑坡
晨间晓2 天前
目标进了这个区域多久?我用 YOLO + ByteTrack 做了 ROI 占用与停留分析
yolo
YOLO数据集集合2 天前
小麦穗检测数据集 | 小麦穗检测 植物表型 密集目标检测 农业AI9182期
人工智能·yolo·目标检测·机器学习·目标跟踪·小麦穗
FL16238631293 天前
城市道路叶子叶堆检测数据集VOC+YOLO格式351张2类别
人工智能·yolo·机器学习