Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| def process_rooftop_image(image, geographic_bounds): | |
| """ | |
| Process the rooftop image to detect rooftops, exclude shadows and waste areas, | |
| and calculate usable area for solar panels. | |
| Parameters: | |
| image (numpy array): Input image as a NumPy array. | |
| geographic_bounds (dict): Geographic bounds with the following keys: | |
| - lat_min, lat_max, lon_min, lon_max (floats): Latitude and longitude bounds of the image. | |
| Returns: | |
| final_image (numpy array): Image with predicted boundaries and excluded shadows. | |
| usable_area (float): Computed rooftop area usable for solar panels in square meters. | |
| """ | |
| # Convert the image to grayscale | |
| gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
| # Apply Gaussian Blur to reduce noise | |
| blurred = cv2.GaussianBlur(gray, (5, 5), 0) | |
| # Shadow detection (thresholding for dark regions) | |
| _, shadow_mask = cv2.threshold(blurred, 80, 255, cv2.THRESH_BINARY_INV) | |
| # Edge detection (Canny) | |
| edges = cv2.Canny(blurred, 50, 150) | |
| # Morphological operations to close gaps in edges | |
| kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) | |
| closed_edges = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel) | |
| # Find contours of the rooftop | |
| contours, _ = cv2.findContours(closed_edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) | |
| # Create a blank mask for the rooftop area | |
| rooftop_mask = np.zeros_like(gray) | |
| for contour in contours: | |
| # Approximate the contour and filter out unwanted small areas | |
| approx = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True) | |
| area = cv2.contourArea(approx) | |
| if area > 500: # Minimum area threshold to remove noise | |
| cv2.drawContours(rooftop_mask, [approx], -1, 255, -1) | |
| # Exclude shadows from the rooftop mask | |
| final_mask = cv2.bitwise_and(rooftop_mask, cv2.bitwise_not(shadow_mask)) | |
| # Calculate the area in pixels | |
| pixel_area = np.sum(final_mask > 0) | |
| # Convert pixels to real-world area | |
| lat_min, lat_max, lon_min, lon_max = ( | |
| geographic_bounds['lat_min'], | |
| geographic_bounds['lat_max'], | |
| geographic_bounds['lon_min'], | |
| geographic_bounds['lon_max'], | |
| ) | |
| lat_diff = abs(lat_max - lat_min) | |
| lon_diff = abs(lon_max - lon_min) | |
| # Assuming Earth radius = 6371 km | |
| earth_radius = 6371000 # in meters | |
| lat_conversion = (lat_diff * np.pi / 180) * earth_radius | |
| lon_conversion = (lon_diff * np.pi / 180) * earth_radius * np.cos(lat_min * np.pi / 180) | |
| # Conversion factor: real-world area per pixel | |
| conversion_factor = (lat_conversion * lon_conversion) / (image.shape[0] * image.shape[1]) | |
| usable_area = pixel_area * conversion_factor # in square meters | |
| # Overlay contours on the original image | |
| final_image = image.copy() | |
| cv2.drawContours(final_image, contours, -1, (0, 255, 0), 2) | |
| return final_image, usable_area | |
| # Streamlit Interface | |
| st.title("Rooftop Usable Area for Solar Panels") | |
| st.write("Upload a rooftop image to calculate the usable area for solar panels, panel count, total cost, and energy generation potential.") | |
| # File uploader for the image | |
| uploaded_file = st.file_uploader("Upload an image (PNG or JPG)", type=["png", "jpg", "jpeg"]) | |
| # Input fields for geographic bounds with default values | |
| lat_min = st.number_input("Latitude Min", value=89.67, step=0.01) | |
| lat_max = st.number_input("Latitude Max", value=89.68, step=0.01) | |
| lon_min = st.number_input("Longitude Min", value=90.78, step=0.01) | |
| lon_max = st.number_input("Longitude Max", value=90.79, step=0.01) | |
| # Input fields for irradiance, panel efficiency, and sunlight hours | |
| irradiance = st.number_input("Irradiance (W/m²)", value=200, step=1) # Default irradiance value (W/m²) | |
| panel_efficiency = st.number_input("Panel Efficiency (%)", value=18, step=1) / 100 # Default efficiency (18%) | |
| sunlight_hours = st.number_input("Sunlight Hours per Day", value=7, step=1) # Default 5 hours of sunlight | |
| # Button to process the image | |
| if st.button("Calculate Usable Area and Energy Potential"): | |
| if uploaded_file is not None: | |
| # Read the uploaded image | |
| image = np.array(Image.open(uploaded_file).convert("RGB")) # Convert PIL image to NumPy array | |
| image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # Convert RGB to BGR for OpenCV | |
| geographic_bounds = { | |
| 'lat_min': lat_min, | |
| 'lat_max': lat_max, | |
| 'lon_min': lon_min, | |
| 'lon_max': lon_max, | |
| } | |
| # Process the image | |
| final_image, usable_area = process_rooftop_image(image, geographic_bounds) | |
| # Calculate panel count, total cost, and potential energy | |
| panel_area = 5 * 5 # Each panel covers 25 square meters | |
| panel_cost = 25000 # Cost per panel in INR | |
| panel_count = usable_area // panel_area | |
| total_cost = panel_count * panel_cost | |
| # Calculate potential energy generation in kWh | |
| energy_generation_kWh = (usable_area * panel_efficiency * irradiance * sunlight_hours) / 1000 # in kWh | |
| # Display results | |
| st.image(cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB), caption="Processed Image with Boundaries") | |
| st.write(f"Usable Rooftop Area for Solar Panels (excluding shadows): **{usable_area:.2f} square meters**") | |
| st.write(f"Number of 5×5m panels that can be used: **{int(panel_count)}**") | |
| st.write(f"Total installation cost (₹25,000 per panel): **₹{int(total_cost):,}**") | |
| st.write(f"Total potential energy generation per day: **{energy_generation_kWh:.2f} kWh**") | |
| else: | |
| st.error("Please upload an image to proceed.") | |