Improved + Stable + Confidence (#15)
Browse files- Improved + Stable + Confidence (9c32c096d1949df40ca23c870d86970a8799f79c)
app.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# ============================================================
|
| 2 |
-
# π¦ Stage 3 β Wrong Direction Detection (Improved +
|
| 3 |
# ============================================================
|
| 4 |
|
| 5 |
import os, cv2, json, tempfile, numpy as np, gradio as gr
|
|
@@ -32,6 +32,8 @@ class Track:
|
|
| 32 |
self.history = []
|
| 33 |
self.frames_seen = 0
|
| 34 |
self.status = "OK"
|
|
|
|
|
|
|
| 35 |
|
| 36 |
def update(self, bbox):
|
| 37 |
self.kf.predict()
|
|
@@ -43,8 +45,20 @@ class Track:
|
|
| 43 |
self.frames_seen += 1
|
| 44 |
return [x, y]
|
| 45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
# ============================================================
|
| 47 |
-
# βοΈ
|
| 48 |
# ============================================================
|
| 49 |
def compute_cosine_similarity(v1, v2):
|
| 50 |
v1 = v1 / (np.linalg.norm(v1) + 1e-6)
|
|
@@ -120,29 +134,25 @@ def process_video(video_file, stage2_json, show_only_wrong=False):
|
|
| 120 |
for i in range(1, len(pts)):
|
| 121 |
cv2.line(frame, tuple(np.int32(pts[i-1])), tuple(np.int32(pts[i])), (0, 0, 255), 1)
|
| 122 |
|
| 123 |
-
# compute smooth direction
|
| 124 |
motion = smooth_direction(pts)
|
| 125 |
if motion is None:
|
| 126 |
continue
|
| 127 |
if np.linalg.norm(motion) < MIN_FLOW_SPEED:
|
| 128 |
continue
|
| 129 |
|
| 130 |
-
# cosine similarity
|
| 131 |
sims = [compute_cosine_similarity(motion, f) for f in lane_flows]
|
| 132 |
best_sim = max(sims)
|
| 133 |
|
| 134 |
-
# only classify after some frames
|
| 135 |
if trk.frames_seen > DELAY_FRAMES:
|
| 136 |
-
if best_sim < SIM_THRESH
|
| 137 |
-
|
| 138 |
-
else:
|
| 139 |
-
trk.status = "OK"
|
| 140 |
|
| 141 |
-
# draw
|
| 142 |
if (not show_only_wrong) or (trk.status == "WRONG"):
|
| 143 |
color = (0, 0, 255) if trk.status == "WRONG" else (0, 255, 0)
|
| 144 |
-
|
| 145 |
-
|
| 146 |
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
|
| 147 |
|
| 148 |
out.write(frame)
|
|
@@ -155,11 +165,13 @@ def process_video(video_file, stage2_json, show_only_wrong=False):
|
|
| 155 |
# ποΈ Gradio Interface
|
| 156 |
# ============================================================
|
| 157 |
description = """
|
| 158 |
-
### π¦ Stage 3 β Wrong Direction Detection (Improved)
|
| 159 |
- β
Cosine similarity instead of raw angle
|
| 160 |
- β
Lane-wise flow support for curved roads
|
| 161 |
- β
Temporal smoothing & delayed classification
|
| 162 |
-
- β
|
|
|
|
|
|
|
| 163 |
"""
|
| 164 |
|
| 165 |
demo = gr.Interface(
|
|
@@ -169,8 +181,8 @@ demo = gr.Interface(
|
|
| 169 |
gr.File(label="Stage 2 Flow JSON"),
|
| 170 |
gr.Checkbox(label="Show ONLY Wrong Labels Overlay", value=False)
|
| 171 |
],
|
| 172 |
-
outputs=gr.Video(label="Output
|
| 173 |
-
title="π Stage 3 β
|
| 174 |
description=description
|
| 175 |
)
|
| 176 |
|
|
|
|
| 1 |
# ============================================================
|
| 2 |
+
# π¦ Stage 3 β Wrong Direction Detection (Improved + Stable + Confidence)
|
| 3 |
# ============================================================
|
| 4 |
|
| 5 |
import os, cv2, json, tempfile, numpy as np, gradio as gr
|
|
|
|
| 32 |
self.history = []
|
| 33 |
self.frames_seen = 0
|
| 34 |
self.status = "OK"
|
| 35 |
+
self.status_history = [] # πΈ maintain recent decision history
|
| 36 |
+
self.confidence = 1.0
|
| 37 |
|
| 38 |
def update(self, bbox):
|
| 39 |
self.kf.predict()
|
|
|
|
| 45 |
self.frames_seen += 1
|
| 46 |
return [x, y]
|
| 47 |
|
| 48 |
+
def stable_status(self, new_status, new_conf, window=6, agree_ratio=0.7):
|
| 49 |
+
"""Debounce flicker using recent window consensus."""
|
| 50 |
+
self.status_history.append(new_status)
|
| 51 |
+
if len(self.status_history) > window:
|
| 52 |
+
self.status_history.pop(0)
|
| 53 |
+
# majority consensus
|
| 54 |
+
if self.status_history.count(new_status) >= int(agree_ratio * len(self.status_history)):
|
| 55 |
+
self.status = new_status
|
| 56 |
+
self.confidence = new_conf
|
| 57 |
+
return self.status, self.confidence
|
| 58 |
+
|
| 59 |
+
|
| 60 |
# ============================================================
|
| 61 |
+
# βοΈ Utilities
|
| 62 |
# ============================================================
|
| 63 |
def compute_cosine_similarity(v1, v2):
|
| 64 |
v1 = v1 / (np.linalg.norm(v1) + 1e-6)
|
|
|
|
| 134 |
for i in range(1, len(pts)):
|
| 135 |
cv2.line(frame, tuple(np.int32(pts[i-1])), tuple(np.int32(pts[i])), (0, 0, 255), 1)
|
| 136 |
|
|
|
|
| 137 |
motion = smooth_direction(pts)
|
| 138 |
if motion is None:
|
| 139 |
continue
|
| 140 |
if np.linalg.norm(motion) < MIN_FLOW_SPEED:
|
| 141 |
continue
|
| 142 |
|
| 143 |
+
# cosine similarity vs lane flows
|
| 144 |
sims = [compute_cosine_similarity(motion, f) for f in lane_flows]
|
| 145 |
best_sim = max(sims)
|
| 146 |
|
|
|
|
| 147 |
if trk.frames_seen > DELAY_FRAMES:
|
| 148 |
+
new_status = "WRONG" if best_sim < SIM_THRESH else "OK"
|
| 149 |
+
trk.stable_status(new_status, new_conf=best_sim)
|
|
|
|
|
|
|
| 150 |
|
| 151 |
+
# draw if toggle allows
|
| 152 |
if (not show_only_wrong) or (trk.status == "WRONG"):
|
| 153 |
color = (0, 0, 255) if trk.status == "WRONG" else (0, 255, 0)
|
| 154 |
+
label = f"ID:{tid} {trk.status} ({trk.confidence:.2f})"
|
| 155 |
+
cv2.putText(frame, label, tuple(np.int32(pos)),
|
| 156 |
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
|
| 157 |
|
| 158 |
out.write(frame)
|
|
|
|
| 165 |
# ποΈ Gradio Interface
|
| 166 |
# ============================================================
|
| 167 |
description = """
|
| 168 |
+
### π¦ Stage 3 β Wrong Direction Detection (Improved + Stable + Confidence)
|
| 169 |
- β
Cosine similarity instead of raw angle
|
| 170 |
- β
Lane-wise flow support for curved roads
|
| 171 |
- β
Temporal smoothing & delayed classification
|
| 172 |
+
- β
Flicker-free labels using consensus window
|
| 173 |
+
- β
Confidence score display (cosine similarity)
|
| 174 |
+
- β
Toggle to show only WRONG overlays
|
| 175 |
"""
|
| 176 |
|
| 177 |
demo = gr.Interface(
|
|
|
|
| 181 |
gr.File(label="Stage 2 Flow JSON"),
|
| 182 |
gr.Checkbox(label="Show ONLY Wrong Labels Overlay", value=False)
|
| 183 |
],
|
| 184 |
+
outputs=gr.Video(label="Output Video"),
|
| 185 |
+
title="π Stage 3 β Stable Wrong-Direction Detection (with Confidence)",
|
| 186 |
description=description
|
| 187 |
)
|
| 188 |
|