Spaces:
Sleeping
Sleeping
Download app.py from CaBeSh/CrimeAnomalyDetection: direct link, hf CLI and curl.
- Browser
- Download file 7.41 kB
-
https://huggingface.co/spaces/CaBeSh/CrimeAnomalyDetection/resolve/main/app.py
- Command line
-
hf download hf://spaces/CaBeSh/CrimeAnomalyDetection/app.py
-
curl -L -o app.py https://huggingface.co/spaces/CaBeSh/CrimeAnomalyDetection/resolve/main/app.py
7.41 kB
| import torch | |
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| from model import AdvancedCrimeDetectionModel | |
| from feature_extractor import extract_features | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| # Load model | |
| print("Loading model...") | |
| try: | |
| checkpoint = torch.load( | |
| "crime_model_advanced.pth", | |
| map_location=device, | |
| weights_only=False | |
| ) | |
| threshold = checkpoint.get("threshold", 0.5) | |
| model = AdvancedCrimeDetectionModel().to(device) | |
| model.load_state_dict(checkpoint["model_state_dict"]) | |
| model.eval() | |
| print(f"Model loaded! Threshold: {threshold:.3f}") | |
| except Exception as e: | |
| print(f"Error loading model: {e}") | |
| threshold = 0.5 | |
| def extract_frames_optimized(video_path, max_frames=72, target_fps=4): | |
| """Efficiently extract frames from video using adaptive sampling.""" | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| raise ValueError("Could not open video file") | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| duration = total_frames / fps if fps > 0 else 0 | |
| print(f"Video: {total_frames} frames, {fps:.1f} FPS, {duration:.1f}s") | |
| frame_interval = max(1, int(fps / target_fps)) if duration > 0 else 1 | |
| estimated_frames = total_frames // frame_interval | |
| if estimated_frames > max_frames: | |
| frame_interval = total_frames // max_frames | |
| frames = [] | |
| tmp_paths = [] | |
| frame_count = 0 | |
| while len(frames) < max_frames: | |
| ret, frame = cap.read() | |
| if not ret: | |
| break | |
| if frame_count % frame_interval == 0: | |
| frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| frames.append(frame_rgb) | |
| # Save to tmp for feature_extractor | |
| path = f"/tmp/frame_{len(frames) - 1}.png" | |
| cv2.imwrite(path, frame) # feature_extractor may handle BGR | |
| tmp_paths.append(path) | |
| frame_count += 1 | |
| cap.release() | |
| print(f"Extracted {len(frames)} frames (every {frame_interval} frames)") | |
| return frames, tmp_paths | |
| def get_risk_level(prob): | |
| """Categorize risk level based on probability.""" | |
| if prob < 0.3: | |
| return "π’ Low Risk" | |
| elif prob < 0.5: | |
| return "π‘ Medium Risk" | |
| elif prob < 0.7: | |
| return "π Elevated Risk" | |
| else: | |
| return "π΄ High Risk" | |
| def get_interpretation(max_prob, avg_prob, threshold): | |
| """Provide interpretation of results.""" | |
| if max_prob < threshold: | |
| return "The video appears to show normal activity. No suspicious behavior detected." | |
| else: | |
| severity = "significant" if max_prob > 0.7 else "potential" | |
| consistency = "throughout the video" if avg_prob > threshold else "in specific segments" | |
| return f"The model detected {severity} anomalous behavior {consistency}. Manual review recommended." | |
| def format_output(result): | |
| """Format result dictionary into readable markdown.""" | |
| if "error" in result: | |
| return f"β {result['error']}" | |
| output = f""" | |
| # {result['prediction']} | |
| **Confidence:** {result['confidence']} | |
| **Risk Level:** {result['risk_level']} | |
| --- | |
| ### Analysis Details | |
| - **Max Anomaly Score:** {result['max_anomaly_score']} | |
| - **Average Anomaly Score:** {result['avg_anomaly_score']} | |
| - **Detection Threshold:** {result['threshold']} | |
| - **Frames Analyzed:** {result['frames_analyzed']} | |
| - **Segments Analyzed:** {result['segments_analyzed']} | |
| --- | |
| ### Interpretation | |
| {result['details']} | |
| --- | |
| **Note:** This is an AI-based analysis tool. Results should be used as a supplementary assessment and verified by trained personnel. | |
| """ | |
| return output | |
| def predict_video(video_path, progress=gr.Progress()): | |
| """Main prediction function using model.py and feature_extractor.py.""" | |
| try: | |
| progress(0, desc="Extracting frames...") | |
| frames, tmp_paths = extract_frames_optimized(video_path, max_frames=72, target_fps=4) | |
| if len(frames) < 24: | |
| return format_output({ | |
| "error": f"Video too short. Extracted only {len(frames)} frames (need at least 24)." | |
| }) | |
| progress(0.3, desc="Extracting features...") | |
| # Sliding window over frame tmp_paths | |
| window_size = 24 | |
| stride = 12 | |
| all_probs = [] | |
| num_windows = max(1, (len(tmp_paths) - window_size) // stride + 1) | |
| for i in range(0, len(tmp_paths) - window_size + 1, stride): | |
| window_paths = tmp_paths[i:i + window_size] | |
| feats = extract_features(window_paths).unsqueeze(0).to(device) | |
| with torch.no_grad(): | |
| prob = torch.sigmoid(model(feats)).item() | |
| all_probs.append(prob) | |
| progress( | |
| 0.3 + 0.6 * ((i // stride + 1) / num_windows), | |
| desc=f"Analyzing segments... ({i // stride + 1}/{num_windows})" | |
| ) | |
| progress(0.9, desc="Finalizing results...") | |
| max_prob = max(all_probs) | |
| avg_prob = float(np.mean(all_probs)) | |
| is_anomaly = max_prob > threshold | |
| result = { | |
| "prediction": "π¨ ANOMALY DETECTED" if is_anomaly else "β NORMAL ACTIVITY", | |
| "confidence": f"{max_prob * 100:.1f}%", | |
| "max_anomaly_score": f"{max_prob:.3f}", | |
| "avg_anomaly_score": f"{avg_prob:.3f}", | |
| "threshold": f"{threshold:.3f}", | |
| "frames_analyzed": len(frames), | |
| "segments_analyzed": len(all_probs), | |
| "risk_level": get_risk_level(max_prob), | |
| "details": get_interpretation(max_prob, avg_prob, threshold), | |
| } | |
| progress(1.0, desc="Complete!") | |
| return format_output(result) | |
| except Exception as e: | |
| return format_output({"error": f"Error processing video: {str(e)}"}) | |
| # Gradio Interface | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Crime Detection AI") as demo: | |
| gr.Markdown(""" | |
| # π Advanced Crime Detection System | |
| Upload a video to analyze for potential anomalous or criminal behavior. | |
| The model uses dual-backbone feature extraction with Transformer + GRU architecture. | |
| **Supported formats:** MP4, AVI, MOV, MKV | |
| **Optimized for:** Videos from 10 seconds to several minutes | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| video_input = gr.Video(label="Upload Video", height=400) | |
| analyze_btn = gr.Button("π Analyze Video", variant="primary", size="lg") | |
| gr.Markdown(""" | |
| ### Tips: | |
| - Videos are processed efficiently using adaptive frame sampling | |
| - Longer videos are analyzed in overlapping segments | |
| - Analysis typically takes 30-60 seconds | |
| """) | |
| with gr.Column(): | |
| output_text = gr.Markdown(label="Analysis Results") | |
| gr.Markdown(""" | |
| --- | |
| ### About This Model | |
| This system uses a deep learning model trained on the UCF-Crime dataset to detect anomalous activities in videos. | |
| **Architecture:** | |
| - Dual backbone feature extraction (Transformer + GRU) | |
| - Transformer encoder for long-range dependencies | |
| - Bidirectional GRU for temporal modeling | |
| - Multi-head attention mechanism | |
| **Detection Capabilities:** | |
| - Identifies unusual patterns and behaviors | |
| - Analyzes motion and spatial features | |
| - Provides confidence scores and risk levels | |
| """) | |
| analyze_btn.click( | |
| fn=predict_video, | |
| inputs=video_input, | |
| outputs=output_text | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |