Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -177,8 +177,8 @@ def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_m
|
|
| 177 |
state["rcnn"] = round(float(np.max(prob_3d)) * 100, 1)
|
| 178 |
|
| 179 |
# 🚨 FIX: Strict Dual-Consensus checks to prevent IP camera frame-drop false positives!
|
| 180 |
-
# Requires
|
| 181 |
-
if confidence >
|
| 182 |
state["final_decision"] = True
|
| 183 |
state["label"] = f"Incident Logged: {severity.capitalize()}"
|
| 184 |
threading.Thread(target=process_accident_async, args=(stream_id, raw_frame, location, confidence, severity)).start()
|
|
@@ -186,7 +186,7 @@ def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_m
|
|
| 186 |
state["label"] = f"Analyzing... ({severity.capitalize()})"
|
| 187 |
|
| 188 |
except Exception as e:
|
| 189 |
-
print(f"AI Error: {e}", flush=True)
|
| 190 |
finally:
|
| 191 |
if state: state["is_analyzing"] = False
|
| 192 |
|
|
@@ -204,9 +204,9 @@ def init_upload():
|
|
| 204 |
active_streams[stream_id] = {
|
| 205 |
"label": "Initializing...", "final_decision": False, "confidence": 0, "severity": "--",
|
| 206 |
"plates": [], "show_tracking": True, "paused": False, "seek_to": None, "skip_val": 0, "progress": 0,
|
| 207 |
-
"cnn": 0, "rcnn": 0, "force_update": False
|
| 208 |
}
|
| 209 |
-
return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": file_time})
|
| 210 |
|
| 211 |
@app.route('/init_stream', methods=['POST'])
|
| 212 |
def init_stream():
|
|
@@ -234,9 +234,9 @@ def init_stream():
|
|
| 234 |
active_streams[stream_id] = {
|
| 235 |
"label": "Connecting...", "final_decision": False, "confidence": 0, "severity": "--",
|
| 236 |
"plates": [], "show_tracking": True, "paused": False, "seek_to": None, "skip_val": 0, "progress": 0,
|
| 237 |
-
"cnn": 0, "rcnn": 0, "force_update": False
|
| 238 |
}
|
| 239 |
-
return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": v_time})
|
| 240 |
|
| 241 |
@app.route('/video_control/<stream_id>', methods=['POST'])
|
| 242 |
def video_control(stream_id):
|
|
@@ -279,7 +279,7 @@ def video_stream_gen(stream_id, source, location):
|
|
| 279 |
|
| 280 |
force_read = False
|
| 281 |
|
| 282 |
-
if state.get('skip_val', 0) != 0:
|
| 283 |
target = max(0, min(current_frame_idx + (state['skip_val'] * fps), total_frames - 1))
|
| 284 |
cap.set(cv2.CAP_PROP_POS_FRAMES, target)
|
| 285 |
current_frame_idx = int(target)
|
|
@@ -288,7 +288,7 @@ def video_stream_gen(stream_id, source, location):
|
|
| 288 |
frames_3d.clear(); yolo_probs.clear()
|
| 289 |
force_read = True
|
| 290 |
|
| 291 |
-
if state.get('seek_to') is not None:
|
| 292 |
target = int(state['seek_to'] * total_frames)
|
| 293 |
cap.set(cv2.CAP_PROP_POS_FRAMES, target)
|
| 294 |
current_frame_idx = target
|
|
@@ -336,7 +336,9 @@ def video_stream_gen(stream_id, source, location):
|
|
| 336 |
h, w = frame.shape[:2]
|
| 337 |
if w > 1280: frame = cv2.resize(frame, (1280, int(h * 1280 / w)))
|
| 338 |
|
| 339 |
-
if
|
|
|
|
|
|
|
| 340 |
state['progress'] = (current_frame_idx / total_frames) * 100
|
| 341 |
|
| 342 |
try:
|
|
@@ -363,7 +365,7 @@ def video_stream_gen(stream_id, source, location):
|
|
| 363 |
yolo_probs.append(probs)
|
| 364 |
if len(yolo_probs) > 10: yolo_probs.pop(0)
|
| 365 |
|
| 366 |
-
#
|
| 367 |
if len(yolo_probs) > 0:
|
| 368 |
curr_max = np.max(yolo_probs, axis=0)
|
| 369 |
acc_conf = float(np.max(curr_max[:3])) * 100 if len(curr_max) >= 3 else float(np.max(curr_max)) * 100
|
|
@@ -373,15 +375,16 @@ def video_stream_gen(stream_id, source, location):
|
|
| 373 |
|
| 374 |
f_3d = cv2.resize(frame, (112, 112))
|
| 375 |
frames_3d.append(cv2.cvtColor(f_3d, cv2.COLOR_BGR2RGB))
|
| 376 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 377 |
|
| 378 |
-
if len(frames_3d)
|
| 379 |
state["is_analyzing"] = True
|
| 380 |
|
| 381 |
analysis_frames = list(frames_3d)
|
| 382 |
-
while len(analysis_frames) < 16:
|
| 383 |
-
analysis_frames.append(analysis_frames[-1])
|
| 384 |
-
|
| 385 |
p_max = np.max(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
| 386 |
p_mean = np.mean(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
| 387 |
p_min = np.min(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
|
@@ -427,8 +430,7 @@ def predict_traffic_risk():
|
|
| 427 |
except Exception as e: return jsonify({"error": str(e)}), 500
|
| 428 |
|
| 429 |
@app.route('/favicon.ico')
|
| 430 |
-
@app.route('/
|
| 431 |
-
@app.route('/logo.PNG')
|
| 432 |
def serve_logo():
|
| 433 |
static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
|
| 434 |
if os.path.exists(os.path.join(static_dir, 'logo.png')):
|
|
|
|
| 177 |
state["rcnn"] = round(float(np.max(prob_3d)) * 100, 1)
|
| 178 |
|
| 179 |
# 🚨 FIX: Strict Dual-Consensus checks to prevent IP camera frame-drop false positives!
|
| 180 |
+
# Requires 75% overall confidence AND at least 50% spatial confirmation from YOLO of an actual object collision.
|
| 181 |
+
if confidence > 75 and yolo_max_conf > 50.0:
|
| 182 |
state["final_decision"] = True
|
| 183 |
state["label"] = f"Incident Logged: {severity.capitalize()}"
|
| 184 |
threading.Thread(target=process_accident_async, args=(stream_id, raw_frame, location, confidence, severity)).start()
|
|
|
|
| 186 |
state["label"] = f"Analyzing... ({severity.capitalize()})"
|
| 187 |
|
| 188 |
except Exception as e:
|
| 189 |
+
print(f"AI Error in Temporal Engine: {e}", flush=True)
|
| 190 |
finally:
|
| 191 |
if state: state["is_analyzing"] = False
|
| 192 |
|
|
|
|
| 204 |
active_streams[stream_id] = {
|
| 205 |
"label": "Initializing...", "final_decision": False, "confidence": 0, "severity": "--",
|
| 206 |
"plates": [], "show_tracking": True, "paused": False, "seek_to": None, "skip_val": 0, "progress": 0,
|
| 207 |
+
"cnn": 0, "rcnn": 0, "force_update": False, "is_live": False
|
| 208 |
}
|
| 209 |
+
return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": file_time, "is_live": False})
|
| 210 |
|
| 211 |
@app.route('/init_stream', methods=['POST'])
|
| 212 |
def init_stream():
|
|
|
|
| 234 |
active_streams[stream_id] = {
|
| 235 |
"label": "Connecting...", "final_decision": False, "confidence": 0, "severity": "--",
|
| 236 |
"plates": [], "show_tracking": True, "paused": False, "seek_to": None, "skip_val": 0, "progress": 0,
|
| 237 |
+
"cnn": 0, "rcnn": 0, "force_update": False, "is_live": True
|
| 238 |
}
|
| 239 |
+
return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": v_time, "is_live": True})
|
| 240 |
|
| 241 |
@app.route('/video_control/<stream_id>', methods=['POST'])
|
| 242 |
def video_control(stream_id):
|
|
|
|
| 279 |
|
| 280 |
force_read = False
|
| 281 |
|
| 282 |
+
if state.get('skip_val', 0) != 0 and not is_live:
|
| 283 |
target = max(0, min(current_frame_idx + (state['skip_val'] * fps), total_frames - 1))
|
| 284 |
cap.set(cv2.CAP_PROP_POS_FRAMES, target)
|
| 285 |
current_frame_idx = int(target)
|
|
|
|
| 288 |
frames_3d.clear(); yolo_probs.clear()
|
| 289 |
force_read = True
|
| 290 |
|
| 291 |
+
if state.get('seek_to') is not None and not is_live:
|
| 292 |
target = int(state['seek_to'] * total_frames)
|
| 293 |
cap.set(cv2.CAP_PROP_POS_FRAMES, target)
|
| 294 |
current_frame_idx = target
|
|
|
|
| 336 |
h, w = frame.shape[:2]
|
| 337 |
if w > 1280: frame = cv2.resize(frame, (1280, int(h * 1280 / w)))
|
| 338 |
|
| 339 |
+
if is_live:
|
| 340 |
+
state['progress'] = 100 # Hide for live
|
| 341 |
+
elif total_frames > 0:
|
| 342 |
state['progress'] = (current_frame_idx / total_frames) * 100
|
| 343 |
|
| 344 |
try:
|
|
|
|
| 365 |
yolo_probs.append(probs)
|
| 366 |
if len(yolo_probs) > 10: yolo_probs.pop(0)
|
| 367 |
|
| 368 |
+
# LIVE update of Spatial UI data
|
| 369 |
if len(yolo_probs) > 0:
|
| 370 |
curr_max = np.max(yolo_probs, axis=0)
|
| 371 |
acc_conf = float(np.max(curr_max[:3])) * 100 if len(curr_max) >= 3 else float(np.max(curr_max)) * 100
|
|
|
|
| 375 |
|
| 376 |
f_3d = cv2.resize(frame, (112, 112))
|
| 377 |
frames_3d.append(cv2.cvtColor(f_3d, cv2.COLOR_BGR2RGB))
|
| 378 |
+
|
| 379 |
+
# FIX: Removed artificial frame padding. It now strictly waits for 16 genuine frames.
|
| 380 |
+
# This prevents network stutters from being interpreted as "crashes" by the 3D-CNN.
|
| 381 |
+
if len(frames_3d) > 16:
|
| 382 |
+
frames_3d.pop(0)
|
| 383 |
|
| 384 |
+
if len(frames_3d) == 16 and frame_count % 10 == 0 and not state.get("is_analyzing"):
|
| 385 |
state["is_analyzing"] = True
|
| 386 |
|
| 387 |
analysis_frames = list(frames_3d)
|
|
|
|
|
|
|
|
|
|
| 388 |
p_max = np.max(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
| 389 |
p_mean = np.mean(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
| 390 |
p_min = np.min(yolo_probs, axis=0) if len(yolo_probs) > 0 else np.zeros(4)
|
|
|
|
| 430 |
except Exception as e: return jsonify({"error": str(e)}), 500
|
| 431 |
|
| 432 |
@app.route('/favicon.ico')
|
| 433 |
+
@app.route('/app_logo')
|
|
|
|
| 434 |
def serve_logo():
|
| 435 |
static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
|
| 436 |
if os.path.exists(os.path.join(static_dir, 'logo.png')):
|