dschandra commited on
Commit
507096e
·
verified ·
1 Parent(s): f1a77d0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -176
app.py CHANGED
@@ -7,7 +7,6 @@ import tempfile
7
  import os
8
  import asyncio
9
  from concurrent.futures import ThreadPoolExecutor
10
- import time
11
 
12
  # Set page configuration
13
  st.set_page_config(page_title="Solar Panel Fault Detection", layout="wide")
@@ -19,156 +18,8 @@ st.write("Upload a thermal video (MP4) of a solar panel to detect thermal, dust,
19
  # Load model and processor
20
  @st.cache_resource
21
  def load_model():
22
- # Use a lighter model for faster inference (e.g., YOLOS-tiny or DETR)
23
  processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
24
  model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
25
- # Move model to GPU if available
26
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
27
- model.to(device)
28
- model.eval()
29
- return processor, model, device
30
-
31
- processor, model, device = load_model()
32
-
33
- # Function to process a batch of frames
34
- async def detect_faults_batch(frames, processor, model, device):
35
- # Convert frames to RGB and prepare for model
36
- inputs = processor(images=frames, return_tensors="pt").to(device)
37
-
38
- # Run inference
39
- with torch.no_grad():
40
- outputs = model(**inputs)
41
-
42
- # Post-process outputs
43
- target_sizes = torch.tensor([frame.shape[:2] for frame in frames]).to(device)
44
- results = processor.post_process_object_detection(outputs, target_sizes=target_sizes, threshold=0.9)
45
-
46
- annotated_frames = []
47
- all_faults = []
48
-
49
- for frame, result in zip(frames, results):
50
- faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False}
51
- annotated_frame = frame.copy()
52
-
53
- # Analyze frame for faults
54
- for score, label, box in zip(result["scores"], result["labels"], result["boxes"]):
55
- box = [int(i) for i in box.tolist()]
56
- roi = frame[box[1]:box[3], box[0]:box[2]]
57
- mean_intensity = np.mean(roi)
58
-
59
- # Thermal Fault: High intensity (hotspot)
60
- if mean_intensity > 200:
61
- faults["Thermal Fault"] = True
62
- cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (255, 0, 0), 2)
63
- cv2.putText(annotated_frame, "Thermal Fault", (box[0], box[1]-10),
64
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
65
-
66
- # Dust Fault: Low intensity
67
- elif mean_intensity < 100:
68
- faults["Dust Fault"] = True
69
- cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)
70
- cv2.putText(annotated_frame, "Dust Fault", (box[0], box[1]-10),
71
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
72
-
73
- # Power Generation Fault
74
- if faults["Thermal Fault"] or faults["Dust Fault"]:
75
- faults["Power Generation Fault"] = True
76
-
77
- annotated_frames.append(annotated_frame)
78
- all_faults.append(faults)
79
-
80
- return annotated_frames, all_faults
81
-
82
- # Function to process video
83
- async def process_video(video_path, frame_skip=5, batch_size=4):
84
- cap = cv2.VideoCapture(video_path)
85
- if not cap.isOpened():
86
- st.error("Error: Could not open video file.")
87
- return None, None
88
-
89
- # Get video properties
90
- frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
91
- frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
92
- fps = int(cap.get(cv2.CAP_PROP_FPS))
93
- total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
94
-
95
- # Create temporary file for output video
96
- output_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
97
- fourcc = cv2.VideoWriter_fourcc(*"mp4v")
98
- out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
99
-
100
- video_faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False}
101
- frame_count = 0
102
- frames_batch = []
103
-
104
- with st.spinner("Analyzing video..."):
105
- progress = st.progress(0)
106
- executor = ThreadPoolExecutor(max_workers=2)
107
-
108
- while cap.isOpened():
109
- ret, frame = cap.read()
110
- if not ret:
111
- break
112
-
113
- # Skip frames to reduce processing time
114
- if frame_count % frame_skip != 0:
115
- # Write original frame for skipped frames
116
- out.write(frame)
117
- frame_count += 1
118
- continue
119
-
120
- # Convert BGR to RGB
121
- frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
122
- frames_batch.append(frame_rgb)
123
-
124
- # Process batch when full
125
- if len(frames_batch) >= batch_size:
126
- annotated_frames, batch_faults = await detect_faults_batch(frames_batch, processor, model, device)
127
- for annotated_frame, faults in zip(annotated_frames, batch_faults):
128
- # Update video faults
129
- for fault in**.
130
-
131
- System: You are Grok 3 built by xAI.
132
-
133
- The code you provided seems to be cut off and contains some incomplete sections (e.g., the `process_video` function is incomplete). I'll complete and further optimize the code, incorporating the suggestions for batch processing, frame skipping, and efficient resource management. The updated code will also include proper error handling, cleanup, and a streamlined user interface for better performance and user experience.
134
-
135
- ### Key Optimizations
136
- 1. **Batch Processing**: Process frames in batches to reduce overhead and leverage GPU parallelism.
137
- 2. **Frame Skipping**: Process every nth frame to speed up analysis while maintaining accuracy.
138
- 3. **ThreadPoolExecutor**: Use threading for I/O-bound tasks like reading/writing frames.
139
- 4. **Asyncio**: Handle inference asynchronously to improve responsiveness.
140
- 5. **Lightweight Model Option**: Allow switching to a faster model like `YOLOS-tiny` (commented for flexibility).
141
- 6. **Resource Cleanup**: Ensure temporary files are properly managed.
142
- 7. **Progress Feedback**: Provide clear progress updates to the user.
143
- 8. **Error Handling**: Add robust error handling for video processing.
144
-
145
- ### Complete Updated Code
146
- ```python
147
- import streamlit as st
148
- import torch
149
- from transformers import DetrImageProcessor, DetrForObjectDetection
150
- import cv2
151
- import numpy as np
152
- import tempfile
153
- import os
154
- import asyncio
155
- from concurrent.futures import ThreadPoolExecutor
156
- import time
157
-
158
- # Set page configuration
159
- st.set_page_config(page_title="Solar Panel Fault Detection", layout="wide")
160
-
161
- # Title and description
162
- st.title("Solar Panel Fault Detection PoC")
163
- st.write("Upload a thermal video (MP4) of a solar panel to detect thermal, dust, and power generation faults.")
164
-
165
- # Load model and processor
166
- @st.cache_resource
167
- def load_model():
168
- # Use DETR-resnet-50; alternatively, use a lighter model like YOLOS-tiny for faster inference
169
- processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
170
- model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
171
- # Move model to GPU if available
172
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
173
  model.to(device)
174
  model.eval()
@@ -179,14 +30,9 @@ processor, model, device = load_model()
179
  # Function to process a batch of frames
180
  async def detect_faults_batch(frames, processor, model, device):
181
  try:
182
- # Convert frames to RGB and prepare for model
183
  inputs = processor(images=frames, return_tensors="pt").to(device)
184
-
185
- # Run inference
186
  with torch.no_grad():
187
  outputs = model(**inputs)
188
-
189
- # Post-process outputs
190
  target_sizes = torch.tensor([frame.shape[:2] for frame in frames]).to(device)
191
  results = processor.post_process_object_detection(outputs, target_sizes=target_sizes, threshold=0.9)
192
 
@@ -197,27 +43,22 @@ async def detect_faults_batch(frames, processor, model, device):
197
  faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False}
198
  annotated_frame = frame.copy()
199
 
200
- # Analyze frame for faults
201
  for score, label, box in zip(result["scores"], result["labels"], result["boxes"]):
202
  box = [int(i) for i in box.tolist()]
203
  roi = frame[box[1]:box[3], box[0]:box[2]]
204
  mean_intensity = np.mean(roi)
205
 
206
- # Thermal Fault: High intensity (hotspot)
207
  if mean_intensity > 200:
208
  faults["Thermal Fault"] = True
209
  cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (255, 0, 0), 2)
210
  cv2.putText(annotated_frame, "Thermal Fault", (box[0], box[1]-10),
211
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
212
-
213
- # Dust Fault: Low intensity
214
  elif mean_intensity < 100:
215
  faults["Dust Fault"] = True
216
  cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)
217
  cv2.putText(annotated_frame, "Dust Fault", (box[0], box[1]-10),
218
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
219
 
220
- # Power Generation Fault
221
  if faults["Thermal Fault"] or faults["Dust Fault"]:
222
  faults["Power Generation Fault"] = True
223
 
@@ -237,13 +78,11 @@ async def process_video(video_path, frame_skip=5, batch_size=4):
237
  st.error("Error: Could not open video file.")
238
  return None, None
239
 
240
- # Get video properties
241
  frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
242
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
243
  fps = int(cap.get(cv2.CAP_PROP_FPS))
244
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
245
 
246
- # Create temporary file for output video
247
  output_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
248
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
249
  out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
@@ -262,7 +101,6 @@ async def process_video(video_path, frame_skip=5, batch_size=4):
262
  if not ret:
263
  break
264
 
265
- # Skip frames to reduce processing time
266
  if frame_count % frame_skip != 0:
267
  out.write(frame)
268
  frame_count += 1
@@ -270,19 +108,14 @@ async def process_video(video_path, frame_skip=5, batch_size=4):
270
  progress.progress(min(processed_frames / total_frames, 1.0))
271
  continue
272
 
273
- # Convert BGR to RGB
274
  frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
275
  frames_batch.append(frame_rgb)
276
 
277
- 9 # Process batch when full
278
  if len(frames_batch) >= batch_size:
279
  annotated_frames, batch_faults = await detect_faults_batch(frames_batch, processor, model, device)
280
  for annotated_frame, faults in zip(annotated_frames, batch_faults):
281
- # Update video faults
282
  for fault in video_faults:
283
  video_faults[fault] |= faults[fault]
284
-
285
- # Convert back to BGR for writing
286
  annotated_frame_bgr = cv2.cvtColor(annotated_frame, cv2.COLOR_RGB2BGR)
287
  out.write(annotated_frame_bgr)
288
 
@@ -292,7 +125,6 @@ async def process_video(video_path, frame_skip=5, batch_size=4):
292
 
293
  frame_count += 1
294
 
295
- # Process remaining frames
296
  if frames_batch:
297
  annotated_frames, batch_faults = await detect_faults_batch(frames_batch, processor, model, device)
298
  for annotated_frame, faults in zip(annotated_frames, batch_faults):
@@ -322,31 +154,25 @@ uploaded_file = st.file_uploader("Upload a thermal video", type=["mp4"])
322
 
323
  if uploaded_file is not None:
324
  try:
325
- # Save uploaded video to temporary file
326
  tfile = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
327
  tfile.write(uploaded_file.read())
328
  tfile.close()
329
 
330
- # Display uploaded video
331
  st.video(tfile.name, format="video/mp4")
332
 
333
- # Process video
334
  loop = asyncio.get_event_loop()
335
  output_path, video_faults = loop.run_until_complete(process_video(tfile.name, frame_skip=5, batch_size=4))
336
 
337
  if output_path and video_faults:
338
- # Display results
339
  st.subheader("Fault Detection Results")
340
  st.video(output_path, format="video/mp4")
341
 
342
- # Show fault summary
343
  st.write("**Detected Faults in Video:**")
344
  for fault, detected in video_faults.items():
345
  status = "Detected" if detected else "Not Detected"
346
  color = "red" if detected else "green"
347
  st.markdown(f"- **{fault}**: <span style='color:{color}'>{status}</span>", unsafe_allow_html=True)
348
 
349
- # Provide recommendations
350
  if any(video_faults.values()):
351
  st.subheader("Recommendations")
352
  if video_faults["Thermal Fault"]:
@@ -358,11 +184,9 @@ if uploaded_file is not None:
358
  else:
359
  st.write("No faults detected. The solar panel appears to be functioning normally.")
360
 
361
- # Clean up output file
362
  if os.path.exists(output_path):
363
  os.unlink(output_path)
364
 
365
- # Clean up uploaded file
366
  if os.path.exists(tfile.name):
367
  os.unlink(tfile.name)
368
 
 
7
  import os
8
  import asyncio
9
  from concurrent.futures import ThreadPoolExecutor
 
10
 
11
  # Set page configuration
12
  st.set_page_config(page_title="Solar Panel Fault Detection", layout="wide")
 
18
  # Load model and processor
19
  @st.cache_resource
20
  def load_model():
 
21
  processor = DetrImageProcessor.from_pretrained("facebook/detr-resnet-50")
22
  model = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
24
  model.to(device)
25
  model.eval()
 
30
  # Function to process a batch of frames
31
  async def detect_faults_batch(frames, processor, model, device):
32
  try:
 
33
  inputs = processor(images=frames, return_tensors="pt").to(device)
 
 
34
  with torch.no_grad():
35
  outputs = model(**inputs)
 
 
36
  target_sizes = torch.tensor([frame.shape[:2] for frame in frames]).to(device)
37
  results = processor.post_process_object_detection(outputs, target_sizes=target_sizes, threshold=0.9)
38
 
 
43
  faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False}
44
  annotated_frame = frame.copy()
45
 
 
46
  for score, label, box in zip(result["scores"], result["labels"], result["boxes"]):
47
  box = [int(i) for i in box.tolist()]
48
  roi = frame[box[1]:box[3], box[0]:box[2]]
49
  mean_intensity = np.mean(roi)
50
 
 
51
  if mean_intensity > 200:
52
  faults["Thermal Fault"] = True
53
  cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (255, 0, 0), 2)
54
  cv2.putText(annotated_frame, "Thermal Fault", (box[0], box[1]-10),
55
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
 
 
56
  elif mean_intensity < 100:
57
  faults["Dust Fault"] = True
58
  cv2.rectangle(annotated_frame, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)
59
  cv2.putText(annotated_frame, "Dust Fault", (box[0], box[1]-10),
60
  cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
61
 
 
62
  if faults["Thermal Fault"] or faults["Dust Fault"]:
63
  faults["Power Generation Fault"] = True
64
 
 
78
  st.error("Error: Could not open video file.")
79
  return None, None
80
 
 
81
  frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
82
  frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
83
  fps = int(cap.get(cv2.CAP_PROP_FPS))
84
  total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
85
 
 
86
  output_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name
87
  fourcc = cv2.VideoWriter_fourcc(*"mp4v")
88
  out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
 
101
  if not ret:
102
  break
103
 
 
104
  if frame_count % frame_skip != 0:
105
  out.write(frame)
106
  frame_count += 1
 
108
  progress.progress(min(processed_frames / total_frames, 1.0))
109
  continue
110
 
 
111
  frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
112
  frames_batch.append(frame_rgb)
113
 
 
114
  if len(frames_batch) >= batch_size:
115
  annotated_frames, batch_faults = await detect_faults_batch(frames_batch, processor, model, device)
116
  for annotated_frame, faults in zip(annotated_frames, batch_faults):
 
117
  for fault in video_faults:
118
  video_faults[fault] |= faults[fault]
 
 
119
  annotated_frame_bgr = cv2.cvtColor(annotated_frame, cv2.COLOR_RGB2BGR)
120
  out.write(annotated_frame_bgr)
121
 
 
125
 
126
  frame_count += 1
127
 
 
128
  if frames_batch:
129
  annotated_frames, batch_faults = await detect_faults_batch(frames_batch, processor, model, device)
130
  for annotated_frame, faults in zip(annotated_frames, batch_faults):
 
154
 
155
  if uploaded_file is not None:
156
  try:
 
157
  tfile = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
158
  tfile.write(uploaded_file.read())
159
  tfile.close()
160
 
 
161
  st.video(tfile.name, format="video/mp4")
162
 
 
163
  loop = asyncio.get_event_loop()
164
  output_path, video_faults = loop.run_until_complete(process_video(tfile.name, frame_skip=5, batch_size=4))
165
 
166
  if output_path and video_faults:
 
167
  st.subheader("Fault Detection Results")
168
  st.video(output_path, format="video/mp4")
169
 
 
170
  st.write("**Detected Faults in Video:**")
171
  for fault, detected in video_faults.items():
172
  status = "Detected" if detected else "Not Detected"
173
  color = "red" if detected else "green"
174
  st.markdown(f"- **{fault}**: <span style='color:{color}'>{status}</span>", unsafe_allow_html=True)
175
 
 
176
  if any(video_faults.values()):
177
  st.subheader("Recommendations")
178
  if video_faults["Thermal Fault"]:
 
184
  else:
185
  st.write("No faults detected. The solar panel appears to be functioning normally.")
186
 
 
187
  if os.path.exists(output_path):
188
  os.unlink(output_path)
189
 
 
190
  if os.path.exists(tfile.name):
191
  os.unlink(tfile.name)
192