sparsh007 commited on
Commit
49f651b
·
verified ·
1 Parent(s): 220997f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -60
app.py CHANGED
@@ -15,13 +15,21 @@ logger = logging.getLogger(__name__)
15
  AZURE_CONFIG = {
16
  "account_name": "assentian",
17
  "sas_token": "sv=2024-11-04&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-04-30T04:25:22Z&st=2025-04-16T20:25:22Z&spr=https&sig=HYrJBoOYc4PRe%2BoqBMl%2FmoL5Kz4ZYugbTLuEh63sbeo%3D",
18
- "container_name": "logs"
 
19
  }
20
 
21
- # YOLO Model
 
 
 
 
 
 
 
22
  try:
23
- MODEL = YOLO("./best_yolov11 (1).pt")
24
- logger.info("Model loaded successfully")
25
  except Exception as e:
26
  logger.error(f"Model loading failed: {e}")
27
  raise
@@ -44,7 +52,13 @@ def list_videos():
44
  logger.error(f"Error listing videos: {e}")
45
  return []
46
 
47
- def get_video(blob_name):
 
 
 
 
 
 
48
  try:
49
  client = get_azure_client()
50
  blob = client.get_blob_client(
@@ -52,8 +66,13 @@ def get_video(blob_name):
52
  blob=blob_name
53
  )
54
 
 
 
 
55
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as f:
56
- f.write(blob.download_blob().readall())
 
 
57
  return f.name
58
  except Exception as e:
59
  logger.error(f"Download failed: {e}")
@@ -61,101 +80,161 @@ def get_video(blob_name):
61
 
62
  def process_video(input_path, progress=gr.Progress()):
63
  try:
64
- # Validate input
65
  if not input_path or not os.path.exists(input_path):
66
- return None, "Invalid input video"
67
-
68
- # Video setup
69
  cap = cv2.VideoCapture(input_path)
 
 
 
 
70
  frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
71
  fps = cap.get(cv2.CAP_PROP_FPS)
72
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
73
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
74
-
75
  # Output setup
76
  output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
77
- writer = cv2.VideoWriter(output_file, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height))
78
-
79
- # Process frames
80
- progress(0, desc="Starting processing...")
81
- for frame_num in progress.tqdm(range(frame_count), desc="Processing"):
 
 
 
 
 
 
 
 
 
82
  ret, frame = cap.read()
83
  if not ret:
84
  break
85
-
86
- # YOLO detection
87
- results = MODEL(frame)
 
 
 
 
 
 
 
88
  for result in results:
89
  for box in result.boxes:
90
- if box.conf.item() < 0.5:
 
 
91
  continue
92
-
93
- # Draw bounding box
94
  x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
95
- cv2.rectangle(frame, (x1, y1), (x2, y2), (0,255,0), 2)
 
 
 
 
96
 
97
- # Add label
98
- label = f"{MODEL.names[int(box.cls)]} {box.conf:.2f}"
99
- cv2.putText(frame, label, (x1, y1-10),
100
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2)
101
-
 
 
 
 
102
  writer.write(frame)
103
-
 
 
 
 
 
 
 
 
 
 
 
104
  # Cleanup
105
  cap.release()
106
  writer.release()
107
  os.remove(input_path)
108
-
109
- return output_file, "Processing completed successfully"
110
-
111
  except Exception as e:
112
  logger.error(f"Processing failed: {e}")
113
  return None, f"Error: {str(e)}"
114
 
115
  # Gradio Interface
116
- with gr.Blocks(theme=gr.themes.Soft()) as app:
117
- gr.Markdown("# Video Processing Interface")
118
-
119
  with gr.Row():
120
- with gr.Column():
121
  gr.Markdown("## Video Selection")
122
  video_select = gr.Dropdown(
123
- label="Available Videos",
124
  choices=list_videos(),
125
- interactive=True,
126
- filterable=False
127
  )
128
- refresh_btn = gr.Button("🔄 Refresh List")
129
  process_btn = gr.Button("🚀 Process Selected Video", variant="primary")
130
 
131
- with gr.Column():
132
- gr.Markdown("## Output")
133
- video_output = gr.Video(label="Processed Video", format="mp4")
134
- status = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
 
 
 
135
 
136
- # Event handlers
137
- def refresh_list():
138
  return gr.Dropdown.update(choices=list_videos())
139
-
140
- def handle_process(blob_name):
141
- start_time = time.time()
142
  if not blob_name:
143
  return None, "No video selected!"
144
 
145
- local_path = get_video(blob_name)
146
- if not local_path:
147
- return None, "Download failed!"
148
-
149
- result, message = process_video(local_path)
150
- duration = time.time() - start_time
151
- return result, f"{message} | Time: {duration:.1f}s"
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- refresh_btn.click(refresh_list, outputs=video_select)
154
  process_btn.click(
155
- handle_process,
156
  inputs=video_select,
157
- outputs=[video_output, status]
 
158
  )
159
 
160
  if __name__ == "__main__":
161
- app.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
15
  AZURE_CONFIG = {
16
  "account_name": "assentian",
17
  "sas_token": "sv=2024-11-04&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-04-30T04:25:22Z&st=2025-04-16T20:25:22Z&spr=https&sig=HYrJBoOYc4PRe%2BoqBMl%2FmoL5Kz4ZYugbTLuEh63sbeo%3D",
18
+ "container_name": "logs",
19
+ "max_size_mb": 500 # 500MB file size limit
20
  }
21
 
22
+ # YOLO Model Configuration
23
+ MODEL_CONFIG = {
24
+ "model_path": "./best_yolov11 (1).pt",
25
+ "conf_threshold": 0.5,
26
+ "frame_skip": 1 # Process every frame (0 = no skipping)
27
+ }
28
+
29
+ # Initialize YOLO Model
30
  try:
31
+ MODEL = YOLO(MODEL_CONFIG["model_path"])
32
+ logger.info(f"Loaded YOLO model: {MODEL_CONFIG['model_path']}")
33
  except Exception as e:
34
  logger.error(f"Model loading failed: {e}")
35
  raise
 
52
  logger.error(f"Error listing videos: {e}")
53
  return []
54
 
55
+ def validate_video_size(blob_client):
56
+ props = blob_client.get_blob_properties()
57
+ size_mb = props.size / (1024 * 1024)
58
+ if size_mb > AZURE_CONFIG["max_size_mb"]:
59
+ raise ValueError(f"Video exceeds {AZURE_CONFIG['max_size_mb']}MB limit")
60
+
61
+ def download_video(blob_name):
62
  try:
63
  client = get_azure_client()
64
  blob = client.get_blob_client(
 
66
  blob=blob_name
67
  )
68
 
69
+ # Validate video size
70
+ validate_video_size(blob)
71
+
72
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as f:
73
+ download_stream = blob.download_blob()
74
+ for chunk in download_stream.chunks():
75
+ f.write(chunk)
76
  return f.name
77
  except Exception as e:
78
  logger.error(f"Download failed: {e}")
 
80
 
81
  def process_video(input_path, progress=gr.Progress()):
82
  try:
 
83
  if not input_path or not os.path.exists(input_path):
84
+ raise ValueError("Invalid input video path")
85
+
 
86
  cap = cv2.VideoCapture(input_path)
87
+ if not cap.isOpened():
88
+ raise RuntimeError("Failed to open video file")
89
+
90
+ # Get video properties
91
  frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
92
  fps = cap.get(cv2.CAP_PROP_FPS)
93
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
94
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
95
+
96
  # Output setup
97
  output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
98
+ writer = cv2.VideoWriter(output_file,
99
+ cv2.VideoWriter_fourcc(*'mp4v'),
100
+ fps,
101
+ (width, height))
102
+
103
+ # Processing parameters
104
+ frame_skip = MODEL_CONFIG["frame_skip"]
105
+ processed_frames = 0
106
+ total_processed = 0
107
+
108
+ progress(0, desc="Initializing video processing...")
109
+ start_time = time.time()
110
+
111
+ while cap.isOpened():
112
  ret, frame = cap.read()
113
  if not ret:
114
  break
115
+
116
+ # Frame skipping logic
117
+ if total_processed % (frame_skip + 1) != 0:
118
+ total_processed += 1
119
+ continue
120
+
121
+ # YOLO inference
122
+ results = MODEL(frame, verbose=False)
123
+ class_counts = {}
124
+
125
  for result in results:
126
  for box in result.boxes:
127
+ # Convert tensor to Python scalar
128
+ conf = box.conf.item()
129
+ if conf < MODEL_CONFIG["conf_threshold"]:
130
  continue
131
+
132
+ # Get detection coordinates
133
  x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
134
+ class_id = int(box.cls.item())
135
+ class_name = MODEL.names[class_id]
136
+
137
+ # Draw bounding box
138
+ cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
139
 
140
+ # Create label with proper float conversion
141
+ label = f"{class_name} {conf:.2f}"
142
+ cv2.putText(frame, label, (x1, y1 - 10),
143
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
144
+
145
+ # Update counts
146
+ class_counts[class_name] = class_counts.get(class_name, 0) + 1
147
+
148
+ # Write frame to output
149
  writer.write(frame)
150
+ processed_frames += 1
151
+ total_processed += 1
152
+
153
+ # Update progress
154
+ if processed_frames % 10 == 0:
155
+ progress(processed_frames / frame_count,
156
+ desc=f"Processed {processed_frames}/{frame_count} frames")
157
+
158
+ # Calculate statistics
159
+ duration = time.time() - start_time
160
+ fps = processed_frames / duration if duration > 0 else 0
161
+
162
  # Cleanup
163
  cap.release()
164
  writer.release()
165
  os.remove(input_path)
166
+
167
+ return output_file, f"Processed {processed_frames} frames in {duration:.1f}s ({fps:.1f} FPS)"
168
+
169
  except Exception as e:
170
  logger.error(f"Processing failed: {e}")
171
  return None, f"Error: {str(e)}"
172
 
173
  # Gradio Interface
174
+ with gr.Blocks(theme=gr.themes.Soft(), title="PRISM Video Analyzer") as app:
175
+ gr.Markdown("# 🏗️ PRISM Site Diary - Construction Video Analysis")
176
+
177
  with gr.Row():
178
+ with gr.Column(scale=1):
179
  gr.Markdown("## Video Selection")
180
  video_select = gr.Dropdown(
181
+ label="Available Videos from Azure",
182
  choices=list_videos(),
183
+ filterable=False,
184
+ interactive=True
185
  )
186
+ refresh_btn = gr.Button("🔄 Refresh List", variant="secondary")
187
  process_btn = gr.Button("🚀 Process Selected Video", variant="primary")
188
 
189
+ with gr.Column(scale=2):
190
+ gr.Markdown("## Analysis Results")
191
+ video_output = gr.Video(
192
+ label="Processed Video Output",
193
+ format="mp4",
194
+ interactive=False
195
+ )
196
+ status = gr.Textbox(
197
+ label="Processing Status",
198
+ interactive=False,
199
+ value="Ready to process videos"
200
+ )
201
 
202
+ def refresh_video_list():
 
203
  return gr.Dropdown.update(choices=list_videos())
204
+
205
+ def handle_video_processing(blob_name):
 
206
  if not blob_name:
207
  return None, "No video selected!"
208
 
209
+ try:
210
+ local_path = download_video(blob_name)
211
+ if not local_path:
212
+ return None, "Video download failed"
213
+
214
+ result, message = process_video(local_path)
215
+ return result, message
216
+
217
+ except Exception as e:
218
+ logger.error(f"Processing error: {e}")
219
+ return None, f"Error: {str(e)}"
220
+
221
+ # Event handlers
222
+ refresh_btn.click(
223
+ fn=refresh_video_list,
224
+ outputs=video_select,
225
+ queue=False
226
+ )
227
 
 
228
  process_btn.click(
229
+ fn=handle_video_processing,
230
  inputs=video_select,
231
+ outputs=[video_output, status],
232
+ queue=True
233
  )
234
 
235
  if __name__ == "__main__":
236
+ app.launch(
237
+ server_name="0.0.0.0",
238
+ server_port=7860,
239
+ show_error=True
240
+ )