hostel commited on
Commit
ce6e2a4
·
verified ·
1 Parent(s): cf18722

Upload 16 files

Browse files
Files changed (3) hide show
  1. app.py +37 -0
  2. app_secure.py +275 -0
  3. requirements.txt +11 -10
app.py CHANGED
@@ -7,6 +7,43 @@ from datetime import datetime
7
  import plotly.express as px
8
  import os
9
  import torch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  # Set page config
12
  st.set_page_config(
 
7
  import plotly.express as px
8
  import os
9
  import torch
10
+ import torch.nn as nn
11
+ import sys
12
+ import subprocess
13
+ from collections import OrderedDict
14
+ import yaml
15
+ from pathlib import Path
16
+
17
+ # Whitelist safe modules for unpickling
18
+ SAFE_MODULES = {
19
+ 'torch.Size',
20
+ 'torch.LongStorage',
21
+ 'torch.HalfStorage',
22
+ 'torch.FloatStorage',
23
+ 'torch.nn.modules.container.Sequential',
24
+ 'torch.nn.modules.container.ModuleList',
25
+ 'torch.nn.modules.activation.SiLU',
26
+ 'torch.nn.modules.conv.Conv2d',
27
+ 'torch.nn.modules.batchnorm.BatchNorm2d',
28
+ 'torch._utils._rebuild_tensor_v2',
29
+ 'torch._utils._rebuild_parameter',
30
+ 'collections.OrderedDict',
31
+ 'numpy.core.multiarray.scalar',
32
+ 'numpy.dtype',
33
+ 'ultralytics.nn.modules.Detect',
34
+ 'ultralytics.nn.modules.SPPF',
35
+ 'ultralytics.nn.modules.DFL',
36
+ 'ultralytics.nn.modules.Conv',
37
+ 'ultralytics.nn.modules.Bottleneck',
38
+ 'ultralytics.nn.modules.C2f',
39
+ 'ultralytics.nn.modules.Concat',
40
+ 'ultralytics.nn.tasks.DetectionModel',
41
+ 'ultralytics.yolo.utils.IterableSimpleNamespace'
42
+ }
43
+
44
+ # Security settings for Streamlit
45
+ st.set_option('server.enableXsrfProtection', False)
46
+ st.set_option('server.enableCORS', False)
47
 
48
  # Set page config
49
  st.set_page_config(
app_secure.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import cv2
4
+ import numpy as np
5
+ from ultralytics import YOLO
6
+ from datetime import datetime
7
+ import plotly.express as px
8
+ import os
9
+ import torch
10
+ import torch.nn as nn
11
+ import sys
12
+ import subprocess
13
+ from collections import OrderedDict
14
+ import yaml
15
+ from pathlib import Path
16
+ import pickle
17
+ import importlib
18
+
19
+ # Whitelist safe modules for unpickling
20
+ SAFE_MODULES = {
21
+ 'torch.Size',
22
+ 'torch.LongStorage',
23
+ 'torch.HalfStorage',
24
+ 'torch.FloatStorage',
25
+ 'torch.nn.modules.container.Sequential',
26
+ 'torch.nn.modules.container.ModuleList',
27
+ 'torch.nn.modules.activation.SiLU',
28
+ 'torch.nn.modules.conv.Conv2d',
29
+ 'torch.nn.modules.batchnorm.BatchNorm2d',
30
+ 'torch._utils._rebuild_tensor_v2',
31
+ 'torch._utils._rebuild_parameter',
32
+ 'collections.OrderedDict',
33
+ 'numpy.core.multiarray.scalar',
34
+ 'numpy.dtype',
35
+ 'ultralytics.nn.modules.Detect',
36
+ 'ultralytics.nn.modules.SPPF',
37
+ 'ultralytics.nn.modules.DFL',
38
+ 'ultralytics.nn.modules.Conv',
39
+ 'ultralytics.nn.modules.Bottleneck',
40
+ 'ultralytics.nn.modules.C2f',
41
+ 'ultralytics.nn.modules.Concat',
42
+ 'ultralytics.nn.tasks.DetectionModel',
43
+ 'ultralytics.yolo.utils.IterableSimpleNamespace'
44
+ }
45
+
46
+ # Custom safe unpickler
47
+ class SafeUnpickler(pickle.Unpickler):
48
+ def find_class(self, module, name):
49
+ # Check if the module and class combination is in our whitelist
50
+ fullname = f"{module}.{name}"
51
+ if fullname in SAFE_MODULES:
52
+ # Import the module and return the class
53
+ if module not in sys.modules:
54
+ importlib.import_module(module)
55
+ return getattr(sys.modules[module], name)
56
+ # If not in whitelist, raise an error
57
+ raise pickle.UnpicklingError(f"Attempting to unpickle unsafe module: {fullname}")
58
+
59
+ # Configure page
60
+ st.set_page_config(
61
+ page_title="License Plate Detection",
62
+ page_icon="🚗",
63
+ layout="wide"
64
+ )
65
+
66
+ # Initialize session state
67
+ if 'model' not in st.session_state:
68
+ st.session_state.model = None
69
+ if 'processed_frames' not in st.session_state:
70
+ st.session_state.processed_frames = 0
71
+ if 'detections' not in st.session_state:
72
+ st.session_state.detections = []
73
+
74
+ # Safe model loading with custom unpickler
75
+ @st.cache_resource
76
+ def load_model():
77
+ try:
78
+ # Set model directory
79
+ model_path = Path('best.pt')
80
+ if not model_path.exists():
81
+ raise FileNotFoundError("Model file not found")
82
+
83
+ # Initialize YOLO with safe loading
84
+ model = YOLO(
85
+ model_path,
86
+ task='detect',
87
+ verbose=False
88
+ )
89
+
90
+ # Force model to appropriate device
91
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
92
+ model.to(device)
93
+
94
+ # Verify model structure
95
+ if not hasattr(model, 'model') or not isinstance(model.model, nn.Module):
96
+ raise ValueError("Invalid model structure")
97
+
98
+ return model
99
+
100
+ except Exception as e:
101
+ st.error(f"Error loading model: {str(e)}")
102
+ return None
103
+
104
+ # Safe frame processing
105
+ def process_frame(frame, model):
106
+ try:
107
+ if model is None:
108
+ return []
109
+
110
+ # Ensure frame is valid
111
+ if frame is None or not isinstance(frame, np.ndarray):
112
+ return []
113
+
114
+ # Make prediction with error handling
115
+ with torch.no_grad():
116
+ results = model.predict(
117
+ source=frame,
118
+ conf=0.25,
119
+ iou=0.45,
120
+ verbose=False
121
+ )
122
+
123
+ # Safely extract results
124
+ if results and len(results) > 0:
125
+ return results[0].boxes.data.cpu().numpy()
126
+ return []
127
+
128
+ except Exception as e:
129
+ st.error(f"Error processing frame: {str(e)}")
130
+ return []
131
+
132
+ def main():
133
+ st.title("License Plate Detection System")
134
+
135
+ # Sidebar controls
136
+ with st.sidebar:
137
+ st.header("Controls")
138
+ confidence_threshold = st.slider(
139
+ "Confidence Threshold",
140
+ min_value=0.0,
141
+ max_value=1.0,
142
+ value=0.25,
143
+ step=0.05
144
+ )
145
+
146
+ # Load model
147
+ if st.session_state.model is None:
148
+ with st.spinner("Loading model..."):
149
+ st.session_state.model = load_model()
150
+
151
+ if st.session_state.model is None:
152
+ st.error("Failed to load model. Please check the model file.")
153
+ return
154
+
155
+ # File uploader
156
+ video_file = st.file_uploader(
157
+ "Upload Video",
158
+ type=['mp4', 'avi', 'mov'],
159
+ help="Upload a video file containing license plates"
160
+ )
161
+
162
+ if video_file:
163
+ try:
164
+ # Save uploaded file
165
+ temp_path = "temp_video.mp4"
166
+ with open(temp_path, "wb") as f:
167
+ f.write(video_file.read())
168
+
169
+ # Process video
170
+ cap = cv2.VideoCapture(temp_path)
171
+ if not cap.isOpened():
172
+ st.error("Error opening video file")
173
+ return
174
+
175
+ # Video info
176
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
177
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
178
+
179
+ # Display elements
180
+ progress_bar = st.progress(0)
181
+ frame_placeholder = st.empty()
182
+ stats_placeholder = st.empty()
183
+
184
+ # Process frames
185
+ frame_count = 0
186
+ while cap.isOpened():
187
+ ret, frame = cap.read()
188
+ if not ret:
189
+ break
190
+
191
+ frame_count += 1
192
+ progress = int((frame_count / total_frames) * 100)
193
+ progress_bar.progress(progress)
194
+
195
+ # Process every 3rd frame
196
+ if frame_count % 3 == 0:
197
+ detections = process_frame(frame, st.session_state.model)
198
+
199
+ for det in detections:
200
+ if det[4] >= confidence_threshold:
201
+ x1, y1, x2, y2 = map(int, det[:4])
202
+ conf = float(det[4])
203
+
204
+ # Draw detection
205
+ cv2.rectangle(
206
+ frame,
207
+ (x1, y1),
208
+ (x2, y2),
209
+ (0, 255, 0),
210
+ 2
211
+ )
212
+ cv2.putText(
213
+ frame,
214
+ f"{conf:.2f}",
215
+ (x1, y1-10),
216
+ cv2.FONT_HERSHEY_SIMPLEX,
217
+ 0.5,
218
+ (0, 255, 0),
219
+ 2
220
+ )
221
+
222
+ # Save detection
223
+ st.session_state.detections.append({
224
+ 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
225
+ 'confidence': conf
226
+ })
227
+
228
+ # Display frame
229
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
230
+ frame_placeholder.image(
231
+ frame_rgb,
232
+ channels="RGB",
233
+ use_column_width=True
234
+ )
235
+
236
+ # Update stats
237
+ with stats_placeholder:
238
+ col1, col2 = st.columns(2)
239
+ with col1:
240
+ st.metric("Processed Frames", frame_count)
241
+ with col2:
242
+ st.metric("Detections", len(st.session_state.detections))
243
+
244
+ # Clean up
245
+ cap.release()
246
+ if os.path.exists(temp_path):
247
+ os.remove(temp_path)
248
+
249
+ # Show results
250
+ if st.session_state.detections:
251
+ st.header("Detection Statistics")
252
+ df = pd.DataFrame(st.session_state.detections)
253
+
254
+ # Confidence distribution
255
+ fig = px.histogram(
256
+ df,
257
+ x='confidence',
258
+ title='Detection Confidence Distribution',
259
+ labels={'confidence': 'Confidence Score'}
260
+ )
261
+ st.plotly_chart(fig, use_container_width=True)
262
+
263
+ # Results table
264
+ st.dataframe(
265
+ df,
266
+ use_container_width=True
267
+ )
268
+
269
+ except Exception as e:
270
+ st.error(f"An error occurred: {str(e)}")
271
+ if os.path.exists(temp_path):
272
+ os.remove(temp_path)
273
+
274
+ if __name__ == "__main__":
275
+ main()
requirements.txt CHANGED
@@ -1,10 +1,11 @@
1
- streamlit
2
- pandas
3
- plotly
4
- opencv-python-headless
5
- numpy>=1.22.2
6
- ultralytics
7
- python-dateutil
8
- protobuf<=4.24.4
9
- torch>=2.0
10
- PyYAML>=5.3.1
 
 
1
+ streamlit==1.24.0
2
+ pandas==1.5.3
3
+ plotly==5.15.0
4
+ opencv-python-headless==4.7.0.72
5
+ numpy==1.24.3
6
+ ultralytics==8.0.145
7
+ python-dateutil==2.8.2
8
+ protobuf==3.20.0
9
+ torch==2.0.1
10
+ PyYAML==6.0.1
11
+ typing-extensions==4.5.0