新增真起步速度門檻 depart_min_speed: 排隊龜速剪掉、真起步保留

使用者規則: 剪到『穩定起步』為止,之前的停車+龜速蠕動全剪;從穩定起步開始保留。
作法: 把移動段串起來(橋接 <STOP_SECONDS 的 OCR 瞬斷),若整段最高速 < depart_min_speed(15)
表示只是排隊龜速從未真正騎走 → 整段改判停止剪掉;有加速到真速度的(真起步)才保留,
且連龜速起點一起留。
實測 02: #4 由 05:14~07:41 延伸為 05:14~08:13(07:42~08:13 排隊龜速正確剪掉,
原 #5/#6 碎片消失);#3 真起步保留。
(註: creep 起點受平滑視窗 ±3s 影響會有數秒邊界誤差,屬 OCR 雜訊下取捨)

本次調整由 Claude Opus 4.8 (1M context) 協助處理。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 22:39:03 +08:00
parent a972976e71
commit df85116088
3 changed files with 33 additions and 0 deletions
+1
View File
@@ -88,6 +88,7 @@ python auto_remove_redlight.py 01.MOV 03.MOV 05.MOV
| `min_confidence` | `0.7` | OCR 信心低於此值視為「讀不到」(交給平滑用前後判斷)|
| `smooth_window` | `5` | 中位數濾波視窗(取樣點數) |
| `depart_seconds` | `8.0` | 起步門檻(秒):兩段停車間「持續行駛」需達到(滿)此秒數才算起步成功並保留(含這 8 秒);不足者(起步 N 秒內又停)視為仍在等待,連同短暫蠕動一起剪掉(處理車陣走走停停) |
| `depart_min_speed` | `15` | 真起步速度門檻(km/h):一段移動要「加速到」此速度才算真起步/行駛而保留(連同前面龜速起點一起留);若整段最高速都低於此(只是排隊龜速、從未真正騎走),整段改判停止剪掉 |
| `cut_before_stop` | `2.0` | 進入紅燈端(速度到 0)移除起點再往前幾秒,連減速進站一起砍 |
| `keep_after_stop` | `2.0` | 綠燈起步端(速度從 0 開始跑)移除終點提早幾秒,多留卡達起步畫面 |
| `min_keep` | `0.8` | 保留片段短於此秒數即丟棄 |
+31
View File
@@ -106,6 +106,10 @@ SMOOTH_WINDOW = 7 # 中位數濾波視窗(取樣點數,奇數)
DEPART_SECONDS = 8.0 # 起步門檻(秒): 兩段停車中間「持續行駛」需『達到(滿)』此秒數,
# 才算真正起步成功並保留(含這 8 秒);不足者(起步 N 秒內又停)
# 視為仍在等待,連同那段短暫蠕動一起剪掉(處理車陣走走停停)。
DEPART_MIN_SPEED = 15 # 真起步速度門檻(km/h): 一段移動要「加速到」此速度才算真起步/行駛
# 而保留(連同前面的龜速起點一起留);若整段移動最高速都低於此
# (只是排隊龜速、從未真正騎走),則整段改判為停止一起剪掉。
# 這能分辨「龜速後加速騎走(留)」vs「龜速後又停(剪)」。
# --- 剪輯 / 輸出參數 ----------------------------------------
# 紅燈移除段的頭尾「不對稱」微調:
@@ -342,6 +346,32 @@ def find_keep_intervals(samples: List[Sample], duration: float, interval: float
smoothed = smooth_speeds(samples, SMOOTH_WINDOW)
stopped = [v <= SPEED_THRESHOLD for v in smoothed]
# 0) 龜速重新歸類: 把「從未加速到真正速度」的移動段改判為停止(會被剪)。
# 先把移動段串起來(中間 < STOP_SECONDS 的短暫停頓視為 OCR 瞬斷,併入同一段),
# 若整段最高速 < DEPART_MIN_SPEED → 只是排隊龜速,整段改判停止;
# 有加速到 DEPART_MIN_SPEED 的(真起步/行駛)才保留,且連龜速起點一起留。
stop_gap = max(1, int(round(STOP_SECONDS / interval))) # 可橋接的最大停頓取樣數
i = 0
while i < n:
if not stopped[i]:
j = i
while True:
while j + 1 < n and not stopped[j + 1]:
j += 1
k = j + 1 # 數一數後面連續停了幾格
while k < n and stopped[k]:
k += 1
if k < n and (k - (j + 1)) < stop_gap: # 短暫停頓 → 橋接,移動繼續
j = k
else:
break
if max(smoothed[i:j + 1]) < DEPART_MIN_SPEED: # 整段都沒加速到真速度
for x in range(i, j + 1):
stopped[x] = True # → 龜速排隊,改判停止
i = j + 1
else:
i += 1
# 1) 先抓出所有「原始連續停止」區段(不論長短)
raw_runs: List[List[float]] = []
i = 0
@@ -1014,6 +1044,7 @@ _CONFIG_KEYS = {
"min_confidence": "MIN_CONFIDENCE",
"smooth_window": "SMOOTH_WINDOW",
"depart_seconds": "DEPART_SECONDS",
"depart_min_speed": "DEPART_MIN_SPEED",
"cut_before_stop": "CUT_BEFORE_STOP",
"keep_after_stop": "KEEP_AFTER_STOP",
"min_keep": "MIN_KEEP",
+1
View File
@@ -12,6 +12,7 @@
"min_confidence": 0.7,
"smooth_window": 7,
"depart_seconds": 8.0,
"depart_min_speed": 15,
"cut_before_stop": 2.0,
"keep_after_stop": 2.0,
"min_keep": 0.8,