File size: 7,945 Bytes
f8fbdd8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8c726bc
661b2f8
f8fbdd8
 
 
 
e35f3e4
f8fbdd8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
191
192
193
194
import gradio as gr
from ultralytics import YOLO
from PIL import Image
import requests
import os
import random

model = YOLO('detector.pt')


def satellite_image_params(address, api_key, zoom, size):
    """
    Generate parameters for Google Maps API request based on given address, API key, zoom level, and image size.

    Parameters:
    address (str): The address to center the map on.
    api_key (str): Google Maps API key.
    zoom (int): Zoom level for the map.
    size (str): Size of the requested map image.

    Returns:
    dict: A dictionary of parameters for the API request.
    """
    params = {
        "center": address,
        "zoom": str(zoom),
        "size": size,
        "maptype": "satellite",
        "key": api_key
    }
    return params


def fetch_satellite_image(address, api_key, zoom=18, size="640x640"):
    """
    Fetches a satellite image from Google Maps API based on the given address, api_key, zoom level, and size.

    Parameters:
    address (str): The address for the satellite image.
    api_key (str): Google Maps API key.
    zoom (int): Zoom level for the satellite image.
    size (str): Size of the satellite image.

    Returns:
    str: File name of the saved satellite image or None if the request fails.
    """
    base_url = "https://maps.googleapis.com/maps/api/staticmap?"
    params = satellite_image_params(address, api_key, zoom=zoom, size=size)
    try:
        response = requests.get(base_url, params=params)
    except requests.exceptions.RequestException as e:
        print(e)
        return None
    if response.status_code == 200:
        image_data = response.content
        img_name = f"{'_'.join(address.split()[-2:])}.jpg"
        with open(img_name, "wb") as file:
            file.write(image_data)
        print("Image was downloaded successfully")
        return img_name


def plot_results(im_array, save_image=False, img_path="results.jpg"):
    """
     Converts an image array to a PIL image and optionally saves it.

     Parameters:
     im_array (numpy.ndarray): The image array to be converted.
     save_image (bool): Whether to save the image.
     img_path (str): Path to save the image.

     Returns:
     PIL.Image: The converted PIL image.
     """
    im = Image.fromarray(im_array[..., ::-1])  # RGB PIL image
    if save_image:
        im.save(img_path)  # save image
    return im


def solar_panel_predict(image, conf=0.45):
    """
    Analyzes an image to detect solar panels and returns an annotated image along with a relevant message.

    This function uses a model to detect solar panels in the given image. If solar panels are detected with confidence
    above the specified threshold, it selects a positive sentence; otherwise, it chooses a sentence encouraging
    solar panel installation. It also annotates the image with detection results.

    Parameters:
    image: The input image for solar panel detection.
    conf: Confidence threshold for detection, default is 0.5.

    Returns:
    Tuple of (annotated image, prediction message)
    """
    negative_setences = [
        "No solar panels yet? Your roof is a blank canvas waiting for a green masterpiece! 🎨🌱",
        "It's lonely up here without solar panels. Imagine the sun-powered parties you're missing! πŸŒžπŸŽ‰",
        "Your roof could be a superhero in disguise. Just needs its solar cape! πŸ¦Έβ€β™‚οΈβ˜€οΈ",
        "Clear skies, empty roof. It's the perfect opportunity to harness the sun! πŸŒ€οΈπŸ”‹",
        "No panels detected – but don't worry, it's never too late to join the solar revolution and be a ray of hope! πŸŒπŸ’‘"]

    positive_sentences = [
        "Solar panels detected: You're not just saving money, you're also charging up Mother Earth's good vibes! πŸŒπŸ’š",
        "Roof status: Sunny side up! Your panels are turning rays into awesome days! β˜€οΈπŸ˜Ž",
        "You've got solar power! Now your roof is cooler than a polar bear in sunglasses. πŸ»β€β„οΈπŸ•ΆοΈ",
        "Green alert: Your roof is now a climate hero's cape! Solar panels are saving the day, one ray at a time. πŸ¦Έβ€β™‚οΈπŸŒž",
        "Solar panels spotted: Your roof is now officially a member of the Renewable Energy Rockstars Club! ⭐🌱"]

    results = model(image, stream=True, conf=conf)
    for result in results:
        annotated_image = result.plot()
        im = plot_results(annotated_image)

        r = result.boxes
        confi = r.conf.numpy().tolist()
        if not confi:
            prediction = random.choice(negative_setences)
        else:
            prediction = random.choice(positive_sentences)
        return im, prediction


def detector(address, api_key, zoom=18, size="640x640"):
    """
    Detects solar panels in a satellite image fetched based on the given address.

    Parameters:
    address (str): The address to fetch the satellite image of.
    api_key (str): Google Maps API key.
    zoom (int): Zoom level for the image.
    size (str): Size of the image.

    Returns:
    tuple: Prediction text and detected image.
    """
    img_name = fetch_satellite_image(address, api_key, zoom=zoom, size=size)
    im, prediction = solar_panel_predict(img_name)
    return im, prediction

custom_css = """
.feedback textarea {font-size: 20px !important;}
.centered-text {text-align: center; width: 100%;}
"""

with gr.Blocks(theme="HaleyCH/HaleyCH_Theme", title="Solar Panel Detector", css=custom_css) as app:
    # add logo
    gr.Markdown("# **Solar Panel Detector 2.0** πŸ›°οΈβ˜€οΈ", elem_classes="centered-text")
    with gr.Column(scale=1, variant="default"):
        gr.HTML(f"""
                <div style='text-align: center;'>
                    <img src='https://github.com/ArielDrabkin/Solar-Panel-Detector/blob/master/deployment/examples/DALL-E.jpeg?raw=true'
                     height='500' width='1200';'/>
                </div>
                """)
    gr.Markdown("## This app provides the ability to detect solar panels in a given address or a given image.")

    gr.Markdown("### Using by address with google maps:\n1. Enter an address or geographic coordinates.\n"
                "2. Insert your Google maps api key which you can get from - "
                "https://developers.google.com/maps/documentation/maps-static/get-api-key .\n"
                "3. Choose the zoom level (19 is the default).")
    address = gr.Textbox(label="Address")
    api_key = gr.Textbox(label="Google maps api key", type="password")
    zoom = gr.Slider(minimum=18, maximum=22, step=1, value=19, label="zoom")
    btn = gr.Button(value="Submit")
    with gr.Row():
        predicted_image_address = gr.Image(type="pil", show_label=False, scale=1)
        prediction_address = gr.Textbox(type="text", show_label=False, scale=1, elem_classes="feedback")
    btn.click(detector, inputs=[address, api_key, zoom], outputs=[predicted_image_address, prediction_address])

    gr.Markdown("### Using by a given image:\nUpload an image or use the examples below.")
    with gr.Row():
        im = gr.Image(type="pil", show_label=False, scale=1)
        predicted_image = gr.Image(type="pil", show_label=False, scale=1)

    prediction = gr.Textbox(type="text", show_label=False, elem_classes="feedback")
    btn = gr.Button(value="Submit")
    btn.click(solar_panel_predict, inputs=im, outputs=[predicted_image, prediction])

    gr.Markdown("### Image Examples")
    gr.Examples(
        examples=[os.path.join(os.path.dirname(__file__), "examples/Gottingen.jpg"),
                  os.path.join(os.path.dirname(__file__), "examples/Tubingen.jpg"),
                  os.path.join(os.path.dirname(__file__), "examples/San-Diego.jpg"),
                  os.path.join(os.path.dirname(__file__), "examples/Ceske-Budejovice.jpg")],
        inputs=im,
        outputs=[predicted_image, prediction],
        fn=solar_panel_predict,
        cache_examples=False,
    )

if __name__ == "__main__":
    app.launch()