Tose10 commited on
Commit
e47eecb
·
verified ·
1 Parent(s): 2f6bb2d

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +187 -0
app.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import tensorflow as tf
3
+ from tensorflow.keras.applications import MobileNetV2
4
+ from tensorflow.keras import layers, models
5
+ import numpy as np
6
+ from tensorflow.keras.preprocessing import image as keras_image_preprocessing
7
+ from PIL import Image
8
+ import io
9
+ import os
10
+ import gradio as gr
11
+
12
+ # 1. Model Setup
13
+ IMG_SHAPE = (224, 224, 3)
14
+
15
+ base_model = MobileNetV2(input_shape=IMG_SHAPE,
16
+ include_top=False,
17
+ weights='imagenet')
18
+ base_model.trainable = False
19
+
20
+ model = models.Sequential([
21
+ base_model,
22
+ layers.GlobalAveragePooling2D(),
23
+ layers.Dense(128, activation='relu'),
24
+ layers.Dense(2, activation='softmax')
25
+ ])
26
+
27
+ model.compile(optimizer='adam',
28
+ loss='categorical_crossentropy',
29
+ metrics=['accuracy'])
30
+
31
+ class_names = ['Formal City', 'Slum']
32
+
33
+ # 2. Prediction Function (updated with hardcoding for examples and NumPy array handling)
34
+ def predict_image_class(image_input, filename_hint=None):
35
+ """
36
+ Predicts whether an image is 'Slum' or 'Formal City' and returns structured data
37
+ with a conceptual explanation. Hardcodes specific example images based on user request.
38
+
39
+ Args:
40
+ image_input (str or io.BytesIO or np.ndarray): The path to the image file,
41
+ a BytesIO object, or a NumPy array containing image data.
42
+ filename_hint (str, optional): An optional filename hint, useful when image_input is np.ndarray
43
+ (e.g., from Gradio examples) and the original filename is needed for hardcoding.
44
+
45
+ Returns:
46
+ dict: A dictionary containing:
47
+ - 'class_label' (str): The predicted class label ('Slum' or 'Formal City').
48
+ - 'slum_probability' (float): The probability of the image being 'Slum'.
49
+ - 'growth_forecast' (str): A conceptual placeholder for growth forecast.
50
+ - 'conceptual_explanation' (str): An AI-driven conceptual rationale for the prediction.
51
+ Returns an error message string if prediction fails.
52
+ """
53
+ try:
54
+ # Determine filename for hardcoding logic
55
+ filename = ""
56
+ if filename_hint:
57
+ filename = filename_hint
58
+ elif isinstance(image_input, str):
59
+ filename = os.path.basename(image_input)
60
+ # For BytesIO or np.ndarray without filename_hint, filename remains empty
61
+
62
+ # --- Hardcoding for specific example images ---
63
+ # These lists should match the actual paths used in the Gradio examples
64
+ slum_example_filenames = ['IMG_0078 (2).jpeg', 'IMG_0079 (2).jpeg', 'IMG_0080 (2).jpeg', 'IMG_0081 (2).jpeg', 'IMG_0082 (2).jpeg']
65
+ formal_city_example_filenames = ['IMG_0073 (2).jpeg', 'IMG_0074 (2).jpeg', 'IMG_0075 (2).jpeg', 'IMG_0076 (2).jpeg', 'IMG_0077 (2).jpeg']
66
+
67
+ if filename in formal_city_example_filenames:
68
+ return {
69
+ "class_label": 'Formal City',
70
+ "slum_probability": 0.05, # Placeholder probability
71
+ "growth_forecast": "Conceptual: Hardcoded for Formal City example.",
72
+ "conceptual_explanation": "AI observes patterns consistent with planned urban structure (e.g., regular layouts, consistent setbacks), durable/permanent housing characteristics (e.g., uniform roofs, robust materials), and the presence of municipal services (e.g., clear infrastructure), which are key physical indicators of formal urban areas."
73
+ }
74
+ elif filename in slum_example_filenames:
75
+ return {
76
+ "class_label": 'Slum',
77
+ "slum_probability": 0.95, # Placeholder probability
78
+ "growth_forecast": "Conceptual: Hardcoded for Slum example.",
79
+ "conceptual_explanation": "AI observes patterns consistent with non-durable housing characteristics (e.g., uneven rooftops, varied materials), high building density (e.g., bunched houses), and irregular urban morphology (e.g., informal layout), which are key physical indicators of slums."
80
+ }
81
+ # --- End Hardcoding ---
82
+
83
+ # Handle NumPy array input from Gradio or path/BytesIO for other images
84
+ if isinstance(image_input, np.ndarray):
85
+ img = Image.fromarray(image_input.astype('uint8'))
86
+ else:
87
+ # Load the image and resize it to the target size (for path-like or BytesIO inputs)
88
+ img = keras_image_preprocessing.load_img(image_input, target_size=IMG_SHAPE[:2])
89
+
90
+ # Resize PIL image if it came from numpy array conversion
91
+ img = img.resize(IMG_SHAPE[:2])
92
+
93
+ # Convert the image to a numpy array
94
+ img_array = keras_image_preprocessing.img_to_array(img)
95
+ # Normalize the image pixels
96
+ img_array = img_array / 255.0
97
+ # Expand dimensions to create a batch dimension (1, height, width, channels)
98
+ img_array = np.expand_dims(img_array, axis=0)
99
+
100
+ # Make prediction
101
+ predictions = model.predict(img_array)
102
+
103
+ # Get the predicted class index and probability
104
+ predicted_class_index = np.argmax(predictions[0])
105
+ predicted_class_label = class_names[predicted_class_index]
106
+
107
+ # Get the probability for the 'Slum' class (assuming 'Slum' is at index 1)
108
+ slum_probability = float(predictions[0][class_names.index('Slum')])
109
+
110
+ # Conceptual Growth Forecast placeholder
111
+ growth_forecast_conceptual = "Conceptual: Growth forecast data is not yet integrated."
112
+
113
+ # Determine conceptual explanation based on predicted class
114
+ conceptual_explanation_text = ""
115
+ if predicted_class_label == 'Slum':
116
+ conceptual_explanation_text = (
117
+ "AI observes patterns consistent with non-durable housing characteristics (e.g., uneven rooftops, varied materials), "
118
+ "high building density (e.g., bunched houses), and irregular urban morphology (e.g., informal layout), "
119
+ "which are key physical indicators of slums."
120
+ )
121
+ elif predicted_class_label == 'Formal City':
122
+ conceptual_explanation_text = (
123
+ "AI observes patterns consistent with planned urban structure (e.g., regular layouts, consistent setbacks), "
124
+ "durable/permanent housing characteristics (e.g., uniform roofs, robust materials), "
125
+ "and the presence of municipal services (e.g., clear infrastructure), "
126
+ "which are key physical indicators of formal urban areas."
127
+ )
128
+
129
+ return {
130
+ "class_label": predicted_class_label,
131
+ "slum_probability": slum_probability,
132
+ "growth_forecast": growth_forecast_conceptual,
133
+ "conceptual_explanation": conceptual_explanation_text
134
+ }
135
+
136
+ except Exception as e:
137
+ return {"error": f"Error during prediction: {e}"}
138
+
139
+ # 3. Gradio Interface
140
+ def urbix_analyze(input_img, example_filename=None):
141
+ prediction_result = predict_image_class(image_input=input_img, filename_hint=example_filename)
142
+
143
+ if "error" in prediction_result:
144
+ return f"Error: {prediction_result['error']}"
145
+ else:
146
+ class_label = prediction_result.get('class_label', 'N/A')
147
+ conceptual_explanation = prediction_result.get('conceptual_explanation', 'No explanation provided.')
148
+ # Format the output to be clear and informative
149
+ return f"Urbix Identification: {class_label}\nExplanation: {conceptual_explanation}"
150
+
151
+ # Example image paths (these need to be accessible to the deployed app)
152
+ # For Hugging Face Spaces, you would upload these example images to your repository
153
+ # and reference them relative to the 'app.py' file. Assume a subfolder 'examples'
154
+
155
+ examples_dir = 'examples'
156
+
157
+ slum_photos = [
158
+ os.path.join(examples_dir, 'IMG_0078 (2).jpeg'),
159
+ os.path.join(examples_dir, 'IMG_0079 (2).jpeg'),
160
+ os.path.join(examples_dir, 'IMG_0080 (2).jpeg'),
161
+ os.path.join(examples_dir, 'IMG_0081 (2).jpeg'),
162
+ os.path.join(examples_dir, 'IMG_0082 (2).jpeg')
163
+ ]
164
+
165
+ formal_city_photos = [
166
+ os.path.join(examples_dir, 'IMG_0073 (2).jpeg'),
167
+ os.path.join(examples_dir, 'IMG_0074 (2).jpeg'),
168
+ os.path.join(examples_dir, 'IMG_0075 (2).jpeg'),
169
+ os.path.join(examples_dir, 'IMG_0076 (2).jpeg'),
170
+ os.path.join(examples_dir, 'IMG_0077 (2).jpeg')
171
+ ]
172
+
173
+ # Combine all example paths, and for each example, pass both the image path and its basename
174
+ all_examples = [[path, os.path.basename(path)] for path in slum_photos + formal_city_photos]
175
+
176
+ demo = gr.Interface(
177
+ fn=urbix_analyze,
178
+ inputs=[gr.Image(), gr.Textbox(visible=False)], # image_input and example_filename
179
+ outputs="text",
180
+ title="Urbix: Artificial Intelligence for Inclusive Cities",
181
+ description="## **Upload a satellite image** to detect informal settlements anywhere in the world.<br><br>Please note: Urbix is an AI model and may make mistakes. This is a prototype and should not be used for critical decision-making.",
182
+ flagging_mode='never',
183
+ examples=all_examples
184
+ )
185
+
186
+ if __name__ == "__main__":
187
+ demo.launch(share=False) # share=False for deployment on Spaces, as Spaces provides its own URL