nishanth-saka commited on
Commit
6d8fa7a
Β·
verified Β·
1 Parent(s): 50d4a37

Improved + Stable + Confidence (#15)

Browse files

- Improved + Stable + Confidence (9c32c096d1949df40ca23c870d86970a8799f79c)

Files changed (1) hide show
  1. app.py +28 -16
app.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================================
2
- # 🚦 Stage 3 β€” Wrong Direction Detection (Improved + Toggle)
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
- # βš™οΈ Utility Functions
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 to closest lane flow
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
- trk.status = "WRONG"
138
- else:
139
- trk.status = "OK"
140
 
141
- # draw depending on toggle
142
  if (not show_only_wrong) or (trk.status == "WRONG"):
143
  color = (0, 0, 255) if trk.status == "WRONG" else (0, 255, 0)
144
- cv2.putText(frame, f"ID:{tid} {trk.status}",
145
- tuple(np.int32(pos)),
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
- - βœ… Toggle to show only WRONG vehicles
 
 
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 (with WRONG/OK labels)"),
173
- title="πŸš— Stage 3 – Improved Wrong-Direction Detection",
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