Spaces:
Build error
Build error
File size: 16,796 Bytes
3513e58 fd15add 3513e58 0e3758e 3513e58 951b02e 3513e58 2d7c291 5c40000 720af5c 3513e58 5c40000 4580601 5c40000 2d7c291 3513e58 f6f32f9 3513e58 2d7c291 3513e58 951b02e 3513e58 951b02e 3513e58 0e3758e 3513e58 c3c7569 3513e58 5c40000 3513e58 951b02e 3513e58 5c40000 3513e58 5c40000 951b02e 5c40000 3513e58 5c40000 3513e58 5c40000 3513e58 c3c7569 5c40000 fbef195 3513e58 fbef195 abc9e54 c3c7569 3513e58 fd15add 3513e58 951b02e 3513e58 fbef195 fd15add fbef195 3513e58 fbef195 3513e58 5c40000 3513e58 fbef195 3513e58 fbef195 3513e58 fbef195 3513e58 fbef195 3513e58 951b02e fbef195 5c40000 fbef195 5c40000 fbef195 3513e58 fbef195 3513e58 c3c7569 3513e58 fbef195 3513e58 fbef195 c3c7569 3513e58 b8751a0 5e56207 3513e58 c3c7569 3513e58 fbef195 3513e58 fbef195 c3c7569 fbef195 c3c7569 5c40000 3513e58 5c40000 3513e58 5c40000 | 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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | import gradio as gr
import numpy as np
import argparse
import os
import random
import torch as th
th.set_float32_matmul_precision('high')
import torchvision as tv
from guided_diffusion import logger
from guided_diffusion.script_util import (
model_and_diffusion_defaults,
create_model_and_diffusion,
recreate_diffusion_with_steps,
add_dict_to_argparser,
args_to_dict,
)
import argparse
import warnings
from torchvision import transforms
import torch.nn.functional as F
import huggingface_hub
import functools
# import spaces
# Check if running in Hugging Face Spaces
is_spaces = os.environ.get("SPACE_ID") is not None
spaces_decorator = lambda f: f # Default no-op decorator
if is_spaces:
try:
import spaces
print("Running in Hugging Face Spaces environment")
# Create a decorator based on FREE_GPU environment variable
free_gpu = os.environ.get("FREE_GPU", "false").lower() == "true"
spaces_decorator = functools.partial(spaces.GPU, duration=480, free_gpu=free_gpu)
except ImportError:
print("spaces module not found, continuing without it")
is_spaces = False
model_path = huggingface_hub.hf_hub_download("Kutluhan/SemanticInpaint", "model008000.pt")
def create_argparser():
defaults = dict(
data_dir="",
dataset_mode="",
clip_denoised=True,
num_samples=10000,
batch_size=1,
use_ddim=False,
model_path=model_path,
results_path="",
is_train=False,
s=1.5,
inpainting=True
)
defaults.update(model_and_diffusion_defaults())
parser = argparse.ArgumentParser()
add_dict_to_argparser(parser, defaults)
return parser
args = create_argparser().parse_args()
print(args)
def load_model():
print(args)
args.num_classes = args.num_classes + 3 if args.inpainting else args.num_classes
logger.configure()
logger.log("creating model and diffusion...")
model, diffusion = create_model_and_diffusion(
**args_to_dict(args, model_and_diffusion_defaults().keys())
)
model.load_state_dict(
th.load(args.model_path, map_location="cpu")
)
model.to("cuda")
return model, diffusion
model, diffusion = load_model()
model.convert_to_fp16()
model.eval()
# Check if torch compile should be enabled via environment variable
use_torch_compile = os.environ.get("USE_TORCH_COMPILE", "0").lower() == "1"
if use_torch_compile:
try:
print("Enabling PyTorch compilation mode to improve performance")
model = th.compile(model, mode="reduce-overhead", fullgraph=True)
except Exception as e:
print(f"Failed to enable PyTorch compilation mode: {e}")
print("Continuing without compilation")
# Label to color mapping
label_color_mapping = {
0: (0, 0, 0), # No information
1: (128, 64, 128), # Urban fabric
2: (244, 35, 232), # Industrial / commercial
3: (70, 70, 70), # Mine / dump / construction
4: (102, 102, 156), # Artificial non-agricultural
5: (190, 153, 153), # Arable land
6: (153, 153, 153), # Permanent crops
7: (250, 170, 30), # Pastures
8: (220, 220, 0), # Complex & mixed cultivation
9: (107, 142, 35), # Orchards
10: (152, 251, 152), # Forests
11: (70, 130, 180), # Herbaceous vegetation
12: (220, 20, 60), # Open spaces
13: (255, 0, 0), # Wetlands
14: (0, 0, 142), # Water
15: (220, 220, 220), # Clouds & shadows
}
label_to_name = {
0: "No information",
1: "Urban fabric",
2: "Industrial / commercial",
3: "Mine / dump / construction",
4: "Artificial non-agricultural",
5: "Arable land",
6: "Permanent crops",
7: "Pastures",
8: "Complex & mixed cultivation",
9: "Orchards",
10: "Forests",
11: "Herbaceous vegetation",
12: "Open spaces",
13: "Wetlands",
14: "Water",
15: "Clouds & shadows"
}
name_to_label = {v: k for k, v in label_to_name.items()}
label_color_mapping_ts = th.tensor(list(label_color_mapping.values()))
def create_drawing_canvas():
"""Create a blank white canvas."""
canvas = np.ones((256, 256, 3), dtype=np.uint8) * 0
return canvas
def update_drawing_color(label):
"""
Update the ImageEditor's brush color based on the
chosen label in the dropdown and show helpful hints.
"""
# Extract label index from dropdown (e.g. "Water [USE ALONE]: (0, 0, 142)" -> 14)
# Handle labels with tags by splitting on ":" and then extracting the base name
label_part = label.split(":")[0].strip()
# Extract the base label name without tags
if "[USE ALONE]" in label_part:
base_label = label_part.replace("[USE ALONE]", "").strip()
elif "[DONT USE]" in label_part:
base_label = label_part.replace("[DONT USE]", "").strip()
else:
base_label = label_part
# Get the label index
label_idx = name_to_label.get(base_label, 0)
# Get RGB color from dictionary, then convert to hex (#RRGGBB)
color = label_color_mapping[label_idx]
hex_color = "#{:02x}{:02x}{:02x}".format(*color)
# Define message types and hints for each label
label_hints = {
# Multi-Label Combinations That Work Well (info)
1: ("info", "Urban Fabric: Tends to generate city-like structures and dense urban layouts. Works well with Industrial/Commercial."),
2: ("info", "Industrial/Commercial: Often produces road networks and industrial complexes. Draw thin lines to simulate roads when using this label."),
6: ("info", "Permanent Crops: Generates brown or green agricultural fields."),
10: ("info", "Forests: Creates dense forested regions."),
14: ("info", "Water: Primarily generates lakes (greenish color) and occasionally seas (bluish color). Combines well with Wetlands."),
4: ("info", "Artificial Non-Agricultural Vegetated Areas: Complements urban layouts."),
# Labels That Work Well Alone (info)
7: ("info", "Pastures: Best used independently."),
5: ("info", "Arable Land: Works well individually."),
11: ("info", "Herbaceous Vegetation: Sometimes generates white snowy textures. Best used alone."),
# Labels That Do Not Perform Well (warning)
3: ("warning", "Mine/Dump/Construction: Limited generation quality due to insufficient data."),
8: ("warning", "Complex & Mixed Cultivation Patterns: Inconsistent results."),
9: ("warning", "Orchards: Often unreliable."),
12: ("warning", "Open Spaces with Little or No Vegetation: Sparse or incoherent generation."),
15: ("warning", "Clouds & Shadows: Limited performance due to insufficient data."),
# Recommended Combinations (info)
13: ("info", "Wetlands: Works best when combined with Water to generate more realistic transitions."),
# Empty for other labels
0: ("", ""),
}
# Get hint for current label
hint_type, hint_text = label_hints.get(label_idx, ("", ""))
# Return an update for the existing ImageEditor component and the hint
return gr.ImageEditor(
label="Semantic Drawing",
container=True,
brush=gr.Brush(
colors=[f'#{c[0]:02x}{c[1]:02x}{c[2]:02x}' for c in label_color_mapping.values()],
default_color=hex_color,
color_mode='fixed',
default_size=20
),
interactive=True
), hex_color, hint_type, hint_text
tfs_label = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((256, 256), interpolation=transforms.InterpolationMode.NEAREST),
transforms.ToTensor(),
# transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
def copy_output_to_input(output_image):
return output_image
# Define the generate_image function with conditional decorator
@spaces_decorator
def generate_image(input_image, semantic_drawing, num_imgs):
"""
Generate image using the model with adjustable prob_mask parameter.
"""
print("num_imgs", num_imgs)
tfs = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((256, 256)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
diffusion_steps = 1000
print(diffusion_steps)
img = tfs(input_image).unsqueeze(0)
# Convert semantic_drawing to numpy array if it's not already
# 256x256x3
raw_label = semantic_drawing["composite"][:,:,:3].copy()
# Convert RGB colors to semantic indexes
semantic_label = np.zeros((raw_label.shape[0], raw_label.shape[1]), dtype=np.uint8)
for label_idx, color in label_color_mapping.items():
# Find pixels that match this color exactly
mask = np.all(raw_label == color, axis=2)
semantic_label[mask] = label_idx
# Check if any pixels couldn't be mapped to a label
unmapped = np.all(np.logical_not(np.any(
[np.all(raw_label == color, axis=2) for color in label_color_mapping.values()],
axis=0
)), axis=0)
if np.any(unmapped):
raise ValueError(f"Found colors in the semantic drawing that don't match any label color")
semantic_label= semantic_label.reshape(1, 1, 256, 256)
input_label = th.FloatTensor(1, 19, 256, 256).zero_()
input_image = th.tensor(np.where(semantic_label == 0, img, 0))
input_label[0, -3:, :, :] = input_image
input_semantics = input_label.scatter_(1, th.tensor(semantic_label).long(), 1.0)
model_kwargs = {'y': input_semantics.tile(num_imgs, 1, 1, 1),}
model_kwargs['s'] = args.s
print(args.s)
sample_fn = (
diffusion.p_sample_loop if not args.use_ddim else diffusion.ddim_sample_loop
)
output_imgs = []
sample = sample_fn(
model,
(num_imgs, 3, 256, 256),
clip_denoised=args.clip_denoised,
model_kwargs=model_kwargs,
progress=True,
)
sample = (sample + 1) / 2.0
sample = sample.cpu().permute(0, 2, 3, 1)
for num in range(num_imgs):
output_img = sample.cpu().numpy()[num]
output_imgs.append(output_img)
return output_imgs # return twice: for output and new input
def put_clicked_into_input(evt: gr.SelectData):
"""
evt.value -> value associated with the clicked item
(a NumPy array *or* a list, gradio versions differ)
evt.index -> zero-based index of the thumbnail that was clicked
"""
clicked = evt.value
image = clicked['image']['path']
if isinstance(clicked, list): # safety for older gradio versions
clicked = clicked[evt.index]
return image # single image (NumPy array)
def put_selected_into_input(chosen_img):
print('chosen_img', chosen_img)
if chosen_img is None:
raise gr.Error("Please click an image in the gallery first.")
return chosen_img
with gr.Blocks() as demo:
gr.Markdown("# Satellite Image Semantic Inpainting with DDPM")
# Add recommendations and best practices
with gr.Accordion("Usage Guidelines & Best Practices", open=True):
gr.Markdown("""
### General Recommendations
- **Generate Multiple Samples**: Generate 2-4 samples to explore different variations. Not all outputs are visually satisfying, so multiple samples increase your chance of getting high-quality results.
### Best Practices
- **Use Few Classes at a Time**: Start with 1-2 semantic classes, draw them on the mask, and generate images.
- **Iterative Editing**: Select the best image from the generated samples as your new base, then add 1-2 more semantic classes and repeat.
- **Preserve Context**: Using only 1-2 new mask types at a time helps maintain better visual and semantic context.
- **Avoid Large Masks**: Drawing very large masks disrupts spatial coherence. Prefer smaller, targeted edits for better realism.
### Label Indications
- Labels marked with **[USE ALONE]** work best independently.
- Labels marked with **[DONT USE]** generally produce poor results.
- Unmarked labels can be combined for interesting effects.
""")
# Create modified label names with tags
modified_label_names = {}
for k, v in label_to_name.items():
if k in [7, 5, 11]: # Labels that work well alone
modified_label_names[k] = f"{v} [USE ALONE]"
elif k in [3, 8, 9, 12, 15]: # Labels that don't perform well
modified_label_names[k] = f"{v} [DONT USE]"
else:
modified_label_names[k] = v
with gr.Row():
with gr.Column(scale=1):
input_image = gr.Image(
label="Input Image",
type="numpy",
container=True,
height=350
)
with gr.Column(scale=1):
semantic_drawing = gr.ImageEditor(
label="Semantic Drawing",
container=True,
brush=gr.Brush(
colors=[f'#{c[0]:02x}{c[1]:02x}{c[2]:02x}' for c in label_color_mapping.values()],
default_color='#000000',
color_mode='fixed',
default_size=20
),
interactive=True,
height=350
)
with gr.Row(equal_height=True):
with gr.Column(scale=1):
label_dropdown = gr.Dropdown(
choices=[f"{modified_label_names[k]}: {label_color_mapping[k]}" for k in label_color_mapping],
label="Select Label",
value=f"{modified_label_names[0]}: {label_color_mapping[0]}",
)
with gr.Column(scale=1):
color_display = gr.ColorPicker(
label="Selected Color",
value="#000000",
interactive=False,
container=True
)
with gr.Row():
num_imgs_slider = gr.Slider(
minimum=1, maximum=4, value=1, step=1,
label="Images to generate"
)
with gr.Row():
generate_btn = gr.Button("Generate Image", size="large")
with gr.Row():
output_image = gr.Gallery(
label="Generated images",
height="auto", columns=[4], # 4 columns looks nice up to 8 images
preview=False,
)
selected_img = gr.State(value=None)
with gr.Row():
use_as_input_btn = gr.Button("Use Output as New Input")
# Example images
gr.Examples(
examples=[
["examples/example1.png", create_drawing_canvas()],
["examples/example2.png", create_drawing_canvas()],
["examples/example3.png", create_drawing_canvas()],
["examples/example4.png", "./examples/example4_mask.png"],
["examples/example5.png", "./examples/example5_mask.png"],
["examples/example6.png", "./examples/example6_mask.png"],
["examples/example7.png", "./examples/example7_mask.png"],
["examples/example8.png", "./examples/example8_mask.png"],
],
inputs=[input_image, semantic_drawing]
)
# Connect the generate button
generate_btn.click(
fn=generate_image,
inputs=[input_image, semantic_drawing, num_imgs_slider],
outputs=output_image
)
output_image.select(
fn=put_clicked_into_input,
inputs=None, # the gallery value is the *selected image*, not the list
outputs=selected_img # gr.Image expects a single ndarray → OK
)
use_as_input_btn.click(
fn=put_selected_into_input,
inputs=selected_img, # comes from our hidden State
outputs=input_image
)
# Add hint components (hidden from UI but used for handling hints)
hint_type = gr.Textbox(visible=False)
hint_text = gr.Textbox(visible=False)
# Function to display appropriate notification based on hint type and text
def show_notification(hint_type, hint_text):
if hint_type == "warning":
return gr.Warning(hint_text)
elif hint_type == "info":
return gr.Info(hint_text)
return None
# Connect the dropdown to update functions
label_dropdown.change(
fn=update_drawing_color,
inputs=label_dropdown,
outputs=[semantic_drawing, color_display, hint_type, hint_text]
).then(
fn=show_notification,
inputs=[hint_type, hint_text],
outputs=None
)
if __name__ == "__main__":
demo.launch()
|