From a972976e7139acc9e820ffbc93d5454b6aa2df5a Mon Sep 17 00:00:00 2001 From: JianMiau Date: Wed, 3 Jun 2026 22:07:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B3=E6=BB=91=E6=94=B9=E7=82=BA=E3=80=8E?= =?UTF-8?q?=E5=8F=AA=E5=B0=8D=E5=8F=AF=E4=BF=A1=E8=AE=80=E6=95=B8=E5=8F=96?= =?UTF-8?q?=E4=B8=AD=E4=BD=8D=E6=95=B8=E3=80=81=E7=A9=BA=E7=99=BD=E8=B7=B3?= =?UTF-8?q?=E9=81=8E=E3=80=8F+=20=E4=BF=A1=E5=BF=83=E9=96=80=E6=AA=BB=200.?= =?UTF-8?q?7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原本『讀不到一律當0』會把行駛中的慢速起步(creep, 如3/7/12km/h)+空白蓋成停, 誤剪掉起步畫面(實例: 02 的 03:25 起步被剪到 03:32)。 改為: 平滑時跳過空白/低信心,只對可信讀數取中位數;整個視窗都讀不到才當0。 停車段空白被周圍0判成停、行駛段空白被周圍車速判成動,兩者兼顧。 信心門檻 0.5->0.7,濾掉停車時的低信心誤讀(如把0看成70@0.57)。 實測 02: #3 由 03:11~03:32 縮為 03:13~03:20(creep 保留)。 本次調整由 Claude Opus 4.8 (1M context) 協助處理。 Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 4 ++-- auto_remove_redlight.py | 24 ++++++++++++------------ config.json | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 227a3ee..f2755d9 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ python auto_remove_redlight.py 01.MOV 03.MOV 05.MOV | `progress_every` | `60` | 進度回報間隔(秒),純顯示用,不影響效能 | | `stop_seconds` | `4.0` | 連續停車超過幾秒判定為紅燈 | | `speed_threshold` | `0` | 時速 ≤ 此值視為停止 | -| `min_confidence` | `0.5` | OCR 信心低於此值視為雜訊 | +| `min_confidence` | `0.7` | OCR 信心低於此值視為「讀不到」(交給平滑用前後判斷)| | `smooth_window` | `5` | 中位數濾波視窗(取樣點數) | | `depart_seconds` | `8.0` | 起步門檻(秒):兩段停車間「持續行駛」需達到(滿)此秒數才算起步成功並保留(含這 8 秒);不足者(起步 N 秒內又停)視為仍在等待,連同短暫蠕動一起剪掉(處理車陣走走停停) | | `cut_before_stop` | `2.0` | 進入紅燈端(速度到 0)移除起點再往前幾秒,連減速進站一起砍 | @@ -139,7 +139,7 @@ python auto_remove_redlight.py 01.MOV 03.MOV 05.MOV 1. 用 OpenCV 每隔 N 秒抽一幀 2. 裁切出畫面上時速表的固定像素區域(ROI) 3. 用 EasyOCR 只辨識數字,讀出當下時速 -4. 對逐秒時速做平滑濾波(**讀不到一律當 0** + 中位數),壓掉停車時的跳動雜訊與誤讀 +4. 對逐秒時速做平滑濾波(**只對可信讀數取中位數、空白跳過;整個視窗都讀不到才當 0**),停車段的空白被周圍的 0 判成停、行駛段的空白被周圍車速判成動,避免誤剪慢速起步 5. 時速持續為 0 超過門檻 → 判定為等紅燈,標記移除(走走停停會合併、結尾停車砍到底) 6. 用 FFmpeg 切割保留片段並拼接(可選淡出淡入轉場 + 音量處理),輸出去紅燈影片 7. 另輸出 `*_cut_log.txt` 剪輯紀錄,記下哪些片段被剪、原因 diff --git a/auto_remove_redlight.py b/auto_remove_redlight.py index cdce1c8..5e0469f 100644 --- a/auto_remove_redlight.py +++ b/auto_remove_redlight.py @@ -91,8 +91,8 @@ SAMPLE_INTERVAL = 1.0 # 每隔幾秒辨識一次 (秒)。1.0 = 每 STOP_SECONDS = 4.0 # 時速為 0 連續超過幾秒,才算等紅燈 (秒) SPEED_THRESHOLD = 0 # 時速 <= 此值視為「停止」。0 = 只有讀到 0 才算停 # 若想把「龜速 1~2 km/h」也當停止,可改成 1 或 2 -MIN_CONFIDENCE = 0.50 # OCR 信心低於此值的結果視為「未知」(交給平滑補值) - # 提高到 0.5 可濾掉停車時偶發的低信心雜訊(如 60@0.39) +MIN_CONFIDENCE = 0.70 # OCR 信心低於此值的結果視為「未知」(交給平滑用前後判斷) + # 0.7 可濾掉停車時的低信心誤讀(如把 0 看成 70@0.57) MAX_SPEED = 300 # 合理時速上限,超過視為誤判(雜訊),當成未知 # --- 平滑濾波(關鍵!解決停車時 OCR 在 0 與雜訊間跳動的問題)---- @@ -306,27 +306,27 @@ def is_stopped(s: Sample) -> bool: def smooth_speeds(samples: List[Sample], window: int) -> List[int]: """ - 對逐秒速度做「讀不到當 0 + 中位數濾波」,壓掉停車時的跳動雜訊。 - 1. 讀不到(None/??)一律當作 GPS=0(停止)。停車時 OCR 常讀不到或誤讀成小數字, - 當 0 處理後,孤立的誤讀(如把 0 看成 70)會被中位數吃掉,避免假性「起步」。 - 2. 中位數濾波: 每個點取前後 window//2 範圍的中位數,孤立雜訊(單格 6/60/70)會被吃掉。 + 對逐秒速度做平滑,壓掉停車時的跳動雜訊,同時不誤殺慢速起步(creep)。 + 做法:每個取樣點取前後 window//2 範圍內「可信讀數(speed 不為 None)」的中位數; + 空白/低信心(None)『跳過不計』,而不是當 0。 + - 讀不到時改由前後決定: 前後都在停(0)→中位數 0(停);前後在動→中位數非0(動)。 + 這樣停車段的空白會被周圍的 0 判成停,行駛段的空白會被周圍的車速判成動。 + - 整個視窗都讀不到才視為 0(停止)。 + - 孤立的誤讀(被高信心門檻 + 中位數雙重過濾)會被周圍多數吃掉。 回傳與 samples 等長的整數速度陣列。 """ n = len(samples) if n == 0: return [] - # --- 1) 讀不到(None)一律當 0 --- - filled: List[int] = [s.speed if s.speed is not None else 0 for s in samples] - - # --- 2) 中位數濾波 --- half = max(0, window // 2) smoothed: List[int] = [0] * n for i in range(n): lo = max(0, i - half) hi = min(n, i + half + 1) - win = sorted(filled[lo:hi]) - smoothed[i] = win[len(win) // 2] + vals = sorted(samples[k].speed for k in range(lo, hi) + if samples[k].speed is not None) + smoothed[i] = vals[len(vals) // 2] if vals else 0 # 全讀不到 → 視為停止 return smoothed diff --git a/config.json b/config.json index b1a55ae..6a17e20 100644 --- a/config.json +++ b/config.json @@ -9,7 +9,7 @@ "progress_every": 60, "stop_seconds": 4.0, "speed_threshold": 0, - "min_confidence": 0.5, + "min_confidence": 0.7, "smooth_window": 7, "depart_seconds": 8.0, "cut_before_stop": 2.0,