Spaces:
Running
Running
File size: 5,580 Bytes
97e4a2e 4ebd4a2 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 dba02e5 d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d758068 97e4a2e d9dd6b6 97e4a2e 1cbc755 97e4a2e dba02e5 97e4a2e 994d04f 56bfbe3 6e5059c 97e4a2e |
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 |
import timm
import transformers
from torch import nn
import numpy as np
import gradio as gr
import PIL
# Instantiate classification model
from fastai.vision.all import *
model_multi = load_learner('vit_tiny_patch16.pkl')
def binary_label(path):
return 'No-anomaly' if (parent_label(path) == 'No-Anomaly') else 'Anomaly'
model_binary = load_learner('vit_tiny_patch16_binary.pkl')
# Instantiate segmentation model
from transformers import SegformerFeatureExtractor, SegformerForSemanticSegmentation
from torchvision.transforms import Grayscale
seg_feature_extractor = SegformerFeatureExtractor.from_pretrained('zklee98/segformer-b1-solarModuleAnomaly-v0.1')
seg_model = SegformerForSemanticSegmentation.from_pretrained('zklee98/segformer-b1-solarModuleAnomaly-v0.1')
def get_seg_overlay(image, seg):
color_seg = np.zeros((seg.shape[0], seg.shape[1], 3), dtype=np.uint8) # height, width, 3
palette = np.array(sidewalk_palette())
for label, color in enumerate(palette):
color_seg[seg == label, :] = color
# Show image + mask
img = np.array(image) * 0.5 + color_seg * 0.5
img = img.astype(np.uint8)
#img = PIL.Image.open(img)
return img
#@title `def sidewalk_palette()`
def sidewalk_palette():
"""Sidewalk palette that maps each class to RGB values."""
return [
[0, 0, 0],
[216, 82, 24],
[255, 255, 0],
[125, 46, 141],
[118, 171, 47],
[161, 19, 46],
[255, 0, 0],
[0, 128, 128],
[190, 190, 0],
[0, 255, 0],
[0, 0, 255],
[170, 0, 255],
[84, 84, 0],
[84, 170, 0],
[84, 255, 0],
[170, 84, 0],
[170, 170, 0],
[170, 255, 0],
[255, 84, 0],
[255, 170, 0],
[255, 255, 0],
[33, 138, 200],
[0, 170, 127],
[0, 255, 127],
[84, 0, 127],
[84, 84, 127],
[84, 170, 127],
[84, 255, 127],
[170, 0, 127],
[170, 84, 127],
[170, 170, 127],
[170, 255, 127],
[255, 0, 127],
[255, 84, 127],
[255, 170, 127],
]
def predict(classification_mode, image):
if (classification_mode == 'Binary Classification'):
model = model_binary
else:
model = model_multi
labels = model.dls.vocab
# Classification model prediction
#image = PILImage.create(image)
pred, pred_idx, probs = model.predict(image)
seg_img = None
percentage_affected = '0%'
if (pred.upper() != 'NO-ANOMALY'):
addChannel = Grayscale(num_output_channels=3)
image = addChannel(image)
inputs = seg_feature_extractor(images=image, return_tensors="pt")
outputs = seg_model(**inputs)
logits = outputs.logits # shape (batch_size, num_labels, height/4, width/4)
# First, rescale logits to original image size
upsampled_logits = nn.functional.interpolate(
logits,
size=image.size[::-1], # (height, width)
mode='bilinear',
align_corners=False)
# Second, apply argmax on the class dimension
pred_seg = upsampled_logits.argmax(dim=1)[0]
seg_img = get_seg_overlay(image, pred_seg)
classified_pixels = np.unique(pred_seg.numpy(), return_counts=True)
pixels_count = dict({classified_pixels[0][0]: classified_pixels[1][0],
classified_pixels[0][1]: classified_pixels[1][1]})
percentage_affected = round((pixels_count[1]/960)*100, 1)
percentage_affected = str(percentage_affected) + '%'
seg_img = PIL.Image.fromarray(seg_img)
return ({labels[i]: float(probs[i]) for i in range(len(labels))}, seg_img, percentage_affected)
description = """
<center><img src="https://huggingface.co/spaces/zklee98/SolarPanelAnomaly/resolve/main/dronePV_picture.jpg" width=270px> </center><br><br><br><br>
<center>This program identifies the type of anomaly found in solar panel using an image classification model and the percentage of the affected area using an image segmentation model.</center>
<center><i>(Models are trained on <a href="https://ai4earthscience.github.io/iclr-2020-workshop/papers/ai4earth22.pdf">InfraredSolarModules</a> dataset, and hence expect infrared image as input)</center></i>
"""
gr.Interface(fn=predict,
inputs= [gr.Dropdown(choices=['Binary Classification', 'Multiclass Classification'], label='Classification Mode:',
info='Choose to classify between anomaly and no-anomaly OR between 12 different types of anomalies.'),
gr.Image(type='pil', label='Input infrared image: ')],
outputs=[gr.outputs.Label(num_top_classes=3, label='Detected:').style(container=False),
gr.Image(type='pil', label=' ').style(height=240, width=144),
gr.Textbox(label='Affected area:').style(container=False)],
title='Solar Panel Anomaly Detector',
description=description,
examples=['/images/10000.jpg', '/images/1093.jpg'],
#[PILImage.create('https://huggingface.co/spaces/zklee98/SolarPanelAnomaly/resolve/main/images/1046.jpg')]],
#['/images/1093.jpg'],
#['/images/2503.jpg'],
#['/images/4978.jpg'],
#['/images/5039.jpg'],
#['/images/7001.jpg']],
article= '<center>by <a href="https://www.linkedin.com/in/lzk/">Lee Zhe Kaai</a></center>').launch() |