aneeshc commited on
Commit
1b53f8a
Β·
verified Β·
1 Parent(s): b25b778

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +238 -0
app.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import gradio as gr
3
+ import cv2
4
+ import numpy as np
5
+ from PIL import Image
6
+
7
+ from model import AdvancedCrimeDetectionModel
8
+ from feature_extractor import extract_features
9
+
10
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
11
+
12
+ # Load model
13
+ print("Loading model...")
14
+ try:
15
+ checkpoint = torch.load(
16
+ "crime_model_advanced.pth",
17
+ map_location=device,
18
+ weights_only=False
19
+ )
20
+ threshold = checkpoint.get("threshold", 0.5)
21
+ model = AdvancedCrimeDetectionModel().to(device)
22
+ model.load_state_dict(checkpoint["model_state_dict"])
23
+ model.eval()
24
+ print(f"Model loaded! Threshold: {threshold:.3f}")
25
+ except Exception as e:
26
+ print(f"Error loading model: {e}")
27
+ threshold = 0.5
28
+
29
+
30
+ def extract_frames_optimized(video_path, max_frames=72, target_fps=4):
31
+ """Efficiently extract frames from video using adaptive sampling."""
32
+ cap = cv2.VideoCapture(video_path)
33
+ if not cap.isOpened():
34
+ raise ValueError("Could not open video file")
35
+
36
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
37
+ fps = cap.get(cv2.CAP_PROP_FPS)
38
+ duration = total_frames / fps if fps > 0 else 0
39
+
40
+ print(f"Video: {total_frames} frames, {fps:.1f} FPS, {duration:.1f}s")
41
+
42
+ frame_interval = max(1, int(fps / target_fps)) if duration > 0 else 1
43
+
44
+ estimated_frames = total_frames // frame_interval
45
+ if estimated_frames > max_frames:
46
+ frame_interval = total_frames // max_frames
47
+
48
+ frames = []
49
+ tmp_paths = []
50
+ frame_count = 0
51
+
52
+ while len(frames) < max_frames:
53
+ ret, frame = cap.read()
54
+ if not ret:
55
+ break
56
+
57
+ if frame_count % frame_interval == 0:
58
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
59
+ frames.append(frame_rgb)
60
+
61
+ # Save to tmp for feature_extractor
62
+ path = f"/tmp/frame_{len(frames) - 1}.png"
63
+ cv2.imwrite(path, frame) # feature_extractor may handle BGR
64
+ tmp_paths.append(path)
65
+
66
+ frame_count += 1
67
+
68
+ cap.release()
69
+ print(f"Extracted {len(frames)} frames (every {frame_interval} frames)")
70
+ return frames, tmp_paths
71
+
72
+
73
+ def get_risk_level(prob):
74
+ """Categorize risk level based on probability."""
75
+ if prob < 0.3:
76
+ return "🟒 Low Risk"
77
+ elif prob < 0.5:
78
+ return "🟑 Medium Risk"
79
+ elif prob < 0.7:
80
+ return "🟠 Elevated Risk"
81
+ else:
82
+ return "πŸ”΄ High Risk"
83
+
84
+
85
+ def get_interpretation(max_prob, avg_prob, threshold):
86
+ """Provide interpretation of results."""
87
+ if max_prob < threshold:
88
+ return "The video appears to show normal activity. No suspicious behavior detected."
89
+ else:
90
+ severity = "significant" if max_prob > 0.7 else "potential"
91
+ consistency = "throughout the video" if avg_prob > threshold else "in specific segments"
92
+ return f"The model detected {severity} anomalous behavior {consistency}. Manual review recommended."
93
+
94
+
95
+ def format_output(result):
96
+ """Format result dictionary into readable markdown."""
97
+ if "error" in result:
98
+ return f"❌ {result['error']}"
99
+
100
+ output = f"""
101
+ # {result['prediction']}
102
+
103
+ **Confidence:** {result['confidence']}
104
+ **Risk Level:** {result['risk_level']}
105
+
106
+ ---
107
+
108
+ ### Analysis Details
109
+ - **Max Anomaly Score:** {result['max_anomaly_score']}
110
+ - **Average Anomaly Score:** {result['avg_anomaly_score']}
111
+ - **Detection Threshold:** {result['threshold']}
112
+ - **Frames Analyzed:** {result['frames_analyzed']}
113
+ - **Segments Analyzed:** {result['segments_analyzed']}
114
+
115
+ ---
116
+
117
+ ### Interpretation
118
+ {result['details']}
119
+
120
+ ---
121
+
122
+ **Note:** This is an AI-based analysis tool. Results should be used as a supplementary assessment and verified by trained personnel.
123
+ """
124
+ return output
125
+
126
+
127
+ def predict_video(video_path, progress=gr.Progress()):
128
+ """Main prediction function using model.py and feature_extractor.py."""
129
+ try:
130
+ progress(0, desc="Extracting frames...")
131
+
132
+ frames, tmp_paths = extract_frames_optimized(video_path, max_frames=72, target_fps=4)
133
+
134
+ if len(frames) < 24:
135
+ return format_output({
136
+ "error": f"Video too short. Extracted only {len(frames)} frames (need at least 24)."
137
+ })
138
+
139
+ progress(0.3, desc="Extracting features...")
140
+
141
+ # Sliding window over frame tmp_paths
142
+ window_size = 24
143
+ stride = 12
144
+ all_probs = []
145
+ num_windows = max(1, (len(tmp_paths) - window_size) // stride + 1)
146
+
147
+ for i in range(0, len(tmp_paths) - window_size + 1, stride):
148
+ window_paths = tmp_paths[i:i + window_size]
149
+ feats = extract_features(window_paths).unsqueeze(0).to(device)
150
+
151
+ with torch.no_grad():
152
+ prob = torch.sigmoid(model(feats)).item()
153
+ all_probs.append(prob)
154
+
155
+ progress(
156
+ 0.3 + 0.6 * ((i // stride + 1) / num_windows),
157
+ desc=f"Analyzing segments... ({i // stride + 1}/{num_windows})"
158
+ )
159
+
160
+ progress(0.9, desc="Finalizing results...")
161
+
162
+ max_prob = max(all_probs)
163
+ avg_prob = float(np.mean(all_probs))
164
+ is_anomaly = max_prob > threshold
165
+
166
+ result = {
167
+ "prediction": "🚨 ANOMALY DETECTED" if is_anomaly else "βœ… NORMAL ACTIVITY",
168
+ "confidence": f"{max_prob * 100:.1f}%",
169
+ "max_anomaly_score": f"{max_prob:.3f}",
170
+ "avg_anomaly_score": f"{avg_prob:.3f}",
171
+ "threshold": f"{threshold:.3f}",
172
+ "frames_analyzed": len(frames),
173
+ "segments_analyzed": len(all_probs),
174
+ "risk_level": get_risk_level(max_prob),
175
+ "details": get_interpretation(max_prob, avg_prob, threshold),
176
+ }
177
+
178
+ progress(1.0, desc="Complete!")
179
+ return format_output(result)
180
+
181
+ except Exception as e:
182
+ return format_output({"error": f"Error processing video: {str(e)}"})
183
+
184
+
185
+ # Gradio Interface
186
+ with gr.Blocks(theme=gr.themes.Soft(), title="Crime Detection AI") as demo:
187
+ gr.Markdown("""
188
+ # πŸ” Advanced Crime Detection System
189
+
190
+ Upload a video to analyze for potential anomalous or criminal behavior.
191
+ The model uses dual-backbone feature extraction with Transformer + GRU architecture.
192
+
193
+ **Supported formats:** MP4, AVI, MOV, MKV
194
+ **Optimized for:** Videos from 10 seconds to several minutes
195
+ """)
196
+
197
+ with gr.Row():
198
+ with gr.Column():
199
+ video_input = gr.Video(label="Upload Video", height=400)
200
+ analyze_btn = gr.Button("πŸ” Analyze Video", variant="primary", size="lg")
201
+
202
+ gr.Markdown("""
203
+ ### Tips:
204
+ - Videos are processed efficiently using adaptive frame sampling
205
+ - Longer videos are analyzed in overlapping segments
206
+ - Analysis typically takes 30-60 seconds
207
+ """)
208
+
209
+ with gr.Column():
210
+ output_text = gr.Markdown(label="Analysis Results")
211
+
212
+ gr.Markdown("""
213
+ ---
214
+ ### About This Model
215
+
216
+ This system uses a deep learning model trained on the UCF-Crime dataset to detect anomalous activities in videos.
217
+
218
+ **Architecture:**
219
+ - Dual backbone feature extraction (Transformer + GRU)
220
+ - Transformer encoder for long-range dependencies
221
+ - Bidirectional GRU for temporal modeling
222
+ - Multi-head attention mechanism
223
+
224
+ **Detection Capabilities:**
225
+ - Identifies unusual patterns and behaviors
226
+ - Analyzes motion and spatial features
227
+ - Provides confidence scores and risk levels
228
+
229
+ """)
230
+
231
+ analyze_btn.click(
232
+ fn=predict_video,
233
+ inputs=video_input,
234
+ outputs=output_text
235
+ )
236
+
237
+ if __name__ == "__main__":
238
+ demo.launch()