import streamlit as st import cv2 import numpy as np import tempfile import os import torch from ultralytics import YOLO # Set page config st.set_page_config(page_title="Solar Panel Fault Detection", layout="wide") st.title("Solar Panel Fault Detection (Optimized)") st.write("Upload a thermal video (MP4) to detect thermal, dust, and power generation faults.") # Load YOLO model @st.cache_resource def load_model(): model = YOLO("yolov5s.pt") # Replace with your custom-trained model if available return model model = load_model() # Fault detection with frame & location tracking def detect_faults(frame, results, frame_number): faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False} fault_locations = [] annotated_frame = frame.copy() for result in results: boxes = result.boxes for box in boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) conf = float(box.conf[0]) cls = int(box.cls[0]) roi = frame[y1:y2, x1:x2] if roi.size == 0: continue mean_intensity = np.mean(roi) if mean_intensity > 200: faults["Thermal Fault"] = True color = (255, 0, 0) label = "Thermal Fault" elif mean_intensity < 100: faults["Dust Fault"] = True color = (0, 255, 0) label = "Dust Fault" else: continue # Track location fault_locations.append({ "frame": frame_number, "label": label, "confidence": round(conf, 2), "intensity": round(mean_intensity, 2), "box": (x1, y1, x2, y2) }) # Annotate overlay = annotated_frame.copy() alpha = 0.3 cv2.rectangle(overlay, (x1, y1), (x2, y2), color, -1) cv2.addWeighted(overlay, alpha, annotated_frame, 1 - alpha, 0, annotated_frame) cv2.rectangle(annotated_frame, (x1, y1), (x2, y2), color, 2) cv2.putText(annotated_frame, f"{label} ({mean_intensity:.1f})", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) if faults["Thermal Fault"] or faults["Dust Fault"]: faults["Power Generation Fault"] = True return annotated_frame, faults, fault_locations # Video processing def process_video(video_path): cap = cv2.VideoCapture(video_path) if not cap.isOpened(): st.error("Failed to open video.") return None, None, None fps = int(cap.get(cv2.CAP_PROP_FPS)) total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) output_path = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False).name out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height)) frame_count = 0 video_faults = {"Thermal Fault": False, "Dust Fault": False, "Power Generation Fault": False} all_fault_locations = [] process_every_n_frames = fps # 1 frame per second with st.spinner("Processing video..."): progress = st.progress(0) while cap.isOpened(): ret, frame = cap.read() if not ret: break if frame_count % process_every_n_frames == 0: resized = cv2.resize(frame, (640, 480)) frame_rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB) results = model(frame_rgb, verbose=False) annotated_frame, faults, locations = detect_faults(frame, results, frame_count) all_fault_locations.extend(locations) for fault in video_faults: video_faults[fault] |= faults[fault] else: annotated_frame = frame out.write(annotated_frame) frame_count += 1 progress.progress(min(frame_count / total_frames, 1.0)) cap.release() out.release() return output_path, video_faults, all_fault_locations # File uploader uploaded_file = st.file_uploader("Upload a thermal video", type=["mp4"]) if uploaded_file: temp_input_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name with open(temp_input_path, "wb") as f: f.write(uploaded_file.read()) st.video(temp_input_path) output_path, video_faults, fault_locations = process_video(temp_input_path) if output_path: st.subheader("Detection Results") st.video(output_path) st.write("### Detected Faults:") for fault, detected in video_faults.items(): color = "red" if detected else "green" st.markdown(f"- **{fault}**: {'Detected' if detected else 'Not Detected'}", unsafe_allow_html=True) if any(video_faults.values()): st.subheader("Recommendations") if video_faults["Thermal Fault"]: st.write("- Check for overheating components.") if video_faults["Dust Fault"]: st.write("- Clean dust from solar panel surface.") if video_faults["Power Generation Fault"]: st.write("- Investigate potential efficiency issues.") else: st.success("No faults detected. The system seems to be functioning properly.") # Display fault locations if fault_locations: st.subheader("📍 Fault Locations in Video") st.dataframe([ { "Frame": loc["frame"], "Fault Type": loc["label"], "Confidence": loc["confidence"], "Intensity": loc["intensity"], "Box": f"{loc['box']}" } for loc in fault_locations ]) os.unlink(output_path) os.unlink(temp_input_path) st.markdown("---") st.caption("Built with Streamlit + YOLOv5 (Ultralytics) for fast fault detection.")