Spaces:
Running
Running
File size: 6,549 Bytes
99cf037 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
from arch import SegFormerUNet
import torch
import torch.nn as nn
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
import cv2
import torch
from torch.utils.data import Dataset, DataLoader
import albumentations as A
from albumentations.pytorch import ToTensorV2
# Define Transformations
# transform = A.Compose([
# A.Resize(256, 256), # Resize to SegFormer input size
# A.HorizontalFlip(p=0.5),
# A.RandomBrightnessContrast(p=0.2),
# A.Normalize(mean=[0.5], std=[0.5]),
# ToTensorV2()
# ])
transform = A.Compose([
A.Resize(256, 256), # Resize to SegFormer input size
A.HorizontalFlip(p=0.5), # Randomly flip horizontally
A.VerticalFlip(p=0.2), # Randomly flip vertically
A.RandomBrightnessContrast(p=0.2), # Adjust brightness and contrast
A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.1, rotate_limit=20, p=0.5), # Small shifts, scaling, rotation
A.GaussianBlur(blur_limit=(3, 5), p=0.2), # Slight blurring for robustness
# A.GaussNoise(var_limit=(10.0, 50.0), p=0.3), # Add slight Gaussian noise
A.GridDistortion(num_steps=5, distort_limit=0.3, p=0.2), # Slight grid distortion
A.Normalize(mean=[0.5], std=[0.5]), # Normalize
ToTensorV2() # Convert to tensor
])
# Custom Dataset Class
class SolarPanelDataset(Dataset):
def __init__(self, image_dir, mask_dir, transform=None):
self.image_dir = image_dir
self.mask_dir = mask_dir
self.transform = transform
self.images = sorted(os.listdir(image_dir))
def __len__(self):
return len(self.images)
def __getitem__(self, idx):
img_path = os.path.join(self.image_dir, self.images[idx])
mask_path = os.path.join(self.mask_dir, self.images[idx].replace(".bmp", "_label.bmp"))
# Load Image & Mask
image = cv2.imread(img_path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
mask = (mask > 0).astype("uint8") # Convert to binary mask
# Apply Transformations
if self.transform:
augmented = self.transform(image=image, mask=mask)
image = augmented["image"]
mask = augmented["mask"]
return image, mask.unsqueeze(0) # Add channel dimension
# Load Dataset
val_dataset = SolarPanelDataset("dataset/val/images", "dataset/val/labels", transform=transform)
def compute_solar_area(mask, PTM=0.125, OPTA=34):
"""
Compute solar panel area from a binary segmentation mask.
"""
if isinstance(mask, torch.Tensor):
mask = mask.cpu().detach().numpy() # Convert to NumPy if Tensor
if mask.ndim == 3:
mask = mask.squeeze(0) # Remove extra channel
mask = (mask > 0.5).astype(np.float32) # Ensure binary mask
panel_pixels = mask.sum() # Count solar panel pixels
area_m2 = (panel_pixels * (PTM ** 2)) / np.cos(np.radians(OPTA)) # Convert to m²
return area_m2
def compute_accuracy_metrics(segmented_mask, actual_mask, PTM=0.125):
"""
Compute accuracy of segmented area vs. actual area using MAPE and IoU.
"""
# Compute solar panel areas
segmented_area = compute_solar_area(segmented_mask, PTM)
actual_area = compute_solar_area(actual_mask, PTM)
# Compute Mean Absolute Percentage Error (MAPE)
mape_error = np.abs((segmented_area - actual_area) / actual_area) * 100 if actual_area != 0 else 0
# Compute Intersection over Union (IoU)
intersection = ((segmented_mask > 0.5) & (actual_mask > 0.5)).sum()
union = ((segmented_mask > 0.5) | (actual_mask > 0.5)).sum()
iou_score = intersection / union if union != 0 else 0
return {
"Segmented Area (m²)": segmented_area,
"Actual Area (m²)": actual_area,
"MAPE (%)": mape_error,
"IoU Score": iou_score
}
def compute_energy_output(area_m2, efficiency=0.19, GTI=1676.2, PR=0.935):
"""
Compute estimated solar energy output.
"""
return area_m2 * efficiency * GTI * PR
def Calculate_solar_energy(val_dataset, model, idx=0):
model.eval()
# Load image and mask from validation set
image, mask = val_dataset[idx]
orig_image = np.moveaxis(image.numpy(), 0, -1) # Convert from (C, H, W) to (H, W, C)
# Move image to GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
image = image.unsqueeze(0).to(device)
with torch.no_grad():
output = model(image) # Get raw logits
pred_mask = torch.sigmoid(output).squeeze().cpu().numpy() # Convert logits to probabilities
pred_mask = (pred_mask > 0.5).astype(np.uint8) # Convert to binary mask
# Resize ground truth mask for plotting
mask = mask.squeeze().numpy()
difference = np.sum(mask != pred_mask)
print(f"Number of different pixels: {difference}")
print("-"*20)
# Compute area in m²
area_m2 = compute_solar_area(mask)
print("ORIGINAL MASK ENERGY OUTPUT")
print(f"Estimated Solar Panel Area: {area_m2:.2f} m²")
# Compute energy output in kWh
energy_kwh = compute_energy_output(area_m2)
print(f"Estimated Energy Output: {(energy_kwh/1000):.2f} MWh per year")
print("-"*20)
print("-"*20)
# Compute area in m²
area_m2 = compute_solar_area(pred_mask)
print("PREDICTED MASK ENERGY OUTPUT")
print(f"Estimated Solar Panel Area: {area_m2:.2f} m²")
# Compute energy output in kWh
energy_kwh = compute_energy_output(area_m2)
print(f"Estimated Energy Output: {(energy_kwh/1000):.2f} MWh per year")
print("-"*20)
# Plot the results
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.imshow(orig_image)
plt.title("Original Image")
plt.axis("off")
plt.subplot(1, 3, 2)
plt.imshow(mask, cmap="gray")
plt.title("Ground Truth Mask")
plt.axis("off")
plt.subplot(1, 3, 3)
plt.imshow(pred_mask, cmap="gray")
plt.title("Predicted Mask")
plt.axis("off")
plt.show()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# sample_input = torch.randn(1, 3, 512, 512).to(device)
model = SegFormerUNet().to(device)
model.eval()
checkpoint_path = "model/segformer_unet_focal_loss_97_63.pth"
checkpoint = torch.load(checkpoint_path, map_location=device)
# Load model state dict
model.load_state_dict(checkpoint)
print("Model weights loaded successfully!")
# with torch.no_grad():
# output = model(sample_input)
# Run visualization for a random validation sample
Calculate_solar_energy(val_dataset, model, idx=21) |