Spaces:
Running
on
Zero
Running
on
Zero
test
#37
by
akmam
- opened
- README.md +1 -1
- app.py +18 -82
- requirements.txt +3 -5
README.md
CHANGED
@@ -4,7 +4,7 @@ emoji: 🔅
|
|
4 |
colorFrom: gray
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
-
sdk_version:
|
8 |
app_file: app.py
|
9 |
pinned: true
|
10 |
license: apache-2.0
|
|
|
4 |
colorFrom: gray
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 4.42.0
|
8 |
app_file: app.py
|
9 |
pinned: true
|
10 |
license: apache-2.0
|
app.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1 |
import gradio as gr
|
2 |
import spaces
|
3 |
-
import time
|
4 |
import torch
|
5 |
from diffusers import AutoencoderKL, TCDScheduler
|
6 |
from diffusers.models.model_loading_utils import load_state_dict
|
@@ -169,57 +168,10 @@ def preview_image_and_mask(image, width, height, overlap_percentage, resize_opti
|
|
169 |
|
170 |
return preview
|
171 |
|
172 |
-
@spaces.GPU()
|
173 |
-
def infer(
|
174 |
-
image,
|
175 |
-
width,
|
176 |
-
height,
|
177 |
-
overlap_percentage,
|
178 |
-
num_inference_steps,
|
179 |
-
resize_option,
|
180 |
-
custom_resize_percentage,
|
181 |
-
prompt_input,
|
182 |
-
alignment,
|
183 |
-
overlap_left,
|
184 |
-
overlap_right,
|
185 |
-
overlap_top,
|
186 |
-
overlap_bottom
|
187 |
-
):
|
188 |
-
"""
|
189 |
-
Generate an outpainted image using Stable Diffusion XL with ControlNet guidance.
|
190 |
|
191 |
-
This function performs intelligent image outpainting by expanding the input image
|
192 |
-
according to the specified target dimensions and alignment, generating new content
|
193 |
-
guided by a textual prompt. It uses a ControlNet-enabled diffusion pipeline to ensure
|
194 |
-
coherent image extension.
|
195 |
-
|
196 |
-
Args:
|
197 |
-
image (PIL.Image): The input image to be outpainted.
|
198 |
-
width (int): The target width of the output image.
|
199 |
-
height (int): The target height of the output image.
|
200 |
-
overlap_percentage (int): Percentage of overlap between original and outpainted regions for seamless blending.
|
201 |
-
num_inference_steps (int): Number of inference steps for image generation. Higher values yield better results.
|
202 |
-
resize_option (str): Predefined or custom percentage to resize the input image ("Full", "50%", "33%", "25%", or "Custom").
|
203 |
-
custom_resize_percentage (int): Custom resize percentage if resize_option is "Custom".
|
204 |
-
prompt_input (str): A text prompt describing desired content for the generated region.
|
205 |
-
alignment (str): Alignment of the original image within the canvas ("Middle", "Left", "Right", "Top", "Bottom").
|
206 |
-
overlap_left (bool): Whether to allow blending on the left edge.
|
207 |
-
overlap_right (bool): Whether to allow blending on the right edge.
|
208 |
-
overlap_top (bool): Whether to allow blending on the top edge.
|
209 |
-
overlap_bottom (bool): Whether to allow blending on the bottom edge.
|
210 |
-
|
211 |
-
Yields:
|
212 |
-
Tuple[PIL.Image, PIL.Image]:
|
213 |
-
- The intermediate ControlNet input image (showing the masked area).
|
214 |
-
- The final generated image with the inpainted region.
|
215 |
-
"""
|
216 |
-
#gr.Info("10 seconds will be used from your daily ZeroGPU time credits.")
|
217 |
-
background, mask = prepare_image_and_mask(
|
218 |
-
image, width, height, overlap_percentage,
|
219 |
-
resize_option, custom_resize_percentage, alignment,
|
220 |
-
overlap_left, overlap_right, overlap_top, overlap_bottom
|
221 |
-
)
|
222 |
-
|
223 |
if not can_expand(background.width, background.height, width, height, alignment):
|
224 |
alignment = "Middle"
|
225 |
|
@@ -245,12 +197,10 @@ def infer(
|
|
245 |
):
|
246 |
yield cnet_image, image
|
247 |
|
248 |
-
|
249 |
-
|
250 |
-
#cnet_image.paste(image, (0, 0), mask)
|
251 |
-
|
252 |
-
#return background, cnet_image
|
253 |
|
|
|
254 |
|
255 |
def clear_result():
|
256 |
"""Clears the result ImageSlider."""
|
@@ -288,7 +238,6 @@ def toggle_custom_resize_slider(resize_option):
|
|
288 |
|
289 |
def update_history(new_image, history):
|
290 |
"""Updates the history gallery with the new image."""
|
291 |
-
time.sleep(1)
|
292 |
if history is None:
|
293 |
history = []
|
294 |
history.insert(0, new_image)
|
@@ -296,7 +245,7 @@ def update_history(new_image, history):
|
|
296 |
|
297 |
css = """
|
298 |
.gradio-container {
|
299 |
-
|
300 |
}
|
301 |
"""
|
302 |
|
@@ -425,87 +374,75 @@ with gr.Blocks(css=css) as demo:
|
|
425 |
use_as_input_button.click(
|
426 |
fn=use_output_as_input,
|
427 |
inputs=[result],
|
428 |
-
outputs=[input_image]
|
429 |
-
show_api=False
|
430 |
)
|
431 |
|
432 |
target_ratio.change(
|
433 |
fn=preload_presets,
|
434 |
inputs=[target_ratio, width_slider, height_slider],
|
435 |
outputs=[width_slider, height_slider, settings_panel],
|
436 |
-
queue=False
|
437 |
-
show_api=False
|
438 |
)
|
439 |
|
440 |
width_slider.change(
|
441 |
fn=select_the_right_preset,
|
442 |
inputs=[width_slider, height_slider],
|
443 |
outputs=[target_ratio],
|
444 |
-
queue=False
|
445 |
-
show_api=False
|
446 |
)
|
447 |
|
448 |
height_slider.change(
|
449 |
fn=select_the_right_preset,
|
450 |
inputs=[width_slider, height_slider],
|
451 |
outputs=[target_ratio],
|
452 |
-
queue=False
|
453 |
-
show_api=False
|
454 |
)
|
455 |
|
456 |
resize_option.change(
|
457 |
fn=toggle_custom_resize_slider,
|
458 |
inputs=[resize_option],
|
459 |
outputs=[custom_resize_percentage],
|
460 |
-
queue=False
|
461 |
-
show_api=False
|
462 |
)
|
463 |
|
464 |
run_button.click( # Clear the result
|
465 |
fn=clear_result,
|
466 |
inputs=None,
|
467 |
outputs=result,
|
468 |
-
show_api=False
|
469 |
).then( # Generate the new image
|
470 |
fn=infer,
|
471 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
|
472 |
resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
|
473 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
474 |
outputs=result,
|
475 |
-
).then( # Show the "Use as Input Image" button
|
476 |
-
fn=lambda: gr.update(visible=True),
|
477 |
-
inputs=None,
|
478 |
-
outputs=use_as_input_button,
|
479 |
-
show_api=False
|
480 |
).then( # Update the history gallery
|
481 |
fn=lambda x, history: update_history(x[1], history),
|
482 |
inputs=[result, history_gallery],
|
483 |
outputs=history_gallery,
|
484 |
-
|
|
|
|
|
|
|
485 |
)
|
486 |
|
487 |
prompt_input.submit( # Clear the result
|
488 |
fn=clear_result,
|
489 |
inputs=None,
|
490 |
outputs=result,
|
491 |
-
show_api=False
|
492 |
).then( # Generate the new image
|
493 |
fn=infer,
|
494 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
|
495 |
resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
|
496 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
497 |
outputs=result,
|
498 |
-
show_api=False
|
499 |
).then( # Update the history gallery
|
500 |
fn=lambda x, history: update_history(x[1], history),
|
501 |
inputs=[result, history_gallery],
|
502 |
outputs=history_gallery,
|
503 |
-
show_api=False
|
504 |
).then( # Show the "Use as Input Image" button
|
505 |
fn=lambda: gr.update(visible=True),
|
506 |
inputs=None,
|
507 |
outputs=use_as_input_button,
|
508 |
-
show_api=False
|
509 |
)
|
510 |
|
511 |
preview_button.click(
|
@@ -513,8 +450,7 @@ with gr.Blocks(css=css) as demo:
|
|
513 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
|
514 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
515 |
outputs=preview_image,
|
516 |
-
queue=False
|
517 |
-
show_api=False
|
518 |
)
|
519 |
|
520 |
-
demo.queue(max_size=12).launch(share=False, show_error=True
|
|
|
1 |
import gradio as gr
|
2 |
import spaces
|
|
|
3 |
import torch
|
4 |
from diffusers import AutoencoderKL, TCDScheduler
|
5 |
from diffusers.models.model_loading_utils import load_state_dict
|
|
|
168 |
|
169 |
return preview
|
170 |
|
171 |
+
@spaces.GPU(duration=24)
|
172 |
+
def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
|
173 |
+
background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
if not can_expand(background.width, background.height, width, height, alignment):
|
176 |
alignment = "Middle"
|
177 |
|
|
|
197 |
):
|
198 |
yield cnet_image, image
|
199 |
|
200 |
+
image = image.convert("RGBA")
|
201 |
+
cnet_image.paste(image, (0, 0), mask)
|
|
|
|
|
|
|
202 |
|
203 |
+
yield background, cnet_image
|
204 |
|
205 |
def clear_result():
|
206 |
"""Clears the result ImageSlider."""
|
|
|
238 |
|
239 |
def update_history(new_image, history):
|
240 |
"""Updates the history gallery with the new image."""
|
|
|
241 |
if history is None:
|
242 |
history = []
|
243 |
history.insert(0, new_image)
|
|
|
245 |
|
246 |
css = """
|
247 |
.gradio-container {
|
248 |
+
width: 1200px !important;
|
249 |
}
|
250 |
"""
|
251 |
|
|
|
374 |
use_as_input_button.click(
|
375 |
fn=use_output_as_input,
|
376 |
inputs=[result],
|
377 |
+
outputs=[input_image]
|
|
|
378 |
)
|
379 |
|
380 |
target_ratio.change(
|
381 |
fn=preload_presets,
|
382 |
inputs=[target_ratio, width_slider, height_slider],
|
383 |
outputs=[width_slider, height_slider, settings_panel],
|
384 |
+
queue=False
|
|
|
385 |
)
|
386 |
|
387 |
width_slider.change(
|
388 |
fn=select_the_right_preset,
|
389 |
inputs=[width_slider, height_slider],
|
390 |
outputs=[target_ratio],
|
391 |
+
queue=False
|
|
|
392 |
)
|
393 |
|
394 |
height_slider.change(
|
395 |
fn=select_the_right_preset,
|
396 |
inputs=[width_slider, height_slider],
|
397 |
outputs=[target_ratio],
|
398 |
+
queue=False
|
|
|
399 |
)
|
400 |
|
401 |
resize_option.change(
|
402 |
fn=toggle_custom_resize_slider,
|
403 |
inputs=[resize_option],
|
404 |
outputs=[custom_resize_percentage],
|
405 |
+
queue=False
|
|
|
406 |
)
|
407 |
|
408 |
run_button.click( # Clear the result
|
409 |
fn=clear_result,
|
410 |
inputs=None,
|
411 |
outputs=result,
|
|
|
412 |
).then( # Generate the new image
|
413 |
fn=infer,
|
414 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
|
415 |
resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
|
416 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
417 |
outputs=result,
|
|
|
|
|
|
|
|
|
|
|
418 |
).then( # Update the history gallery
|
419 |
fn=lambda x, history: update_history(x[1], history),
|
420 |
inputs=[result, history_gallery],
|
421 |
outputs=history_gallery,
|
422 |
+
).then( # Show the "Use as Input Image" button
|
423 |
+
fn=lambda: gr.update(visible=True),
|
424 |
+
inputs=None,
|
425 |
+
outputs=use_as_input_button,
|
426 |
)
|
427 |
|
428 |
prompt_input.submit( # Clear the result
|
429 |
fn=clear_result,
|
430 |
inputs=None,
|
431 |
outputs=result,
|
|
|
432 |
).then( # Generate the new image
|
433 |
fn=infer,
|
434 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
|
435 |
resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
|
436 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
437 |
outputs=result,
|
|
|
438 |
).then( # Update the history gallery
|
439 |
fn=lambda x, history: update_history(x[1], history),
|
440 |
inputs=[result, history_gallery],
|
441 |
outputs=history_gallery,
|
|
|
442 |
).then( # Show the "Use as Input Image" button
|
443 |
fn=lambda: gr.update(visible=True),
|
444 |
inputs=None,
|
445 |
outputs=use_as_input_button,
|
|
|
446 |
)
|
447 |
|
448 |
preview_button.click(
|
|
|
450 |
inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
|
451 |
overlap_left, overlap_right, overlap_top, overlap_bottom],
|
452 |
outputs=preview_image,
|
453 |
+
queue=False
|
|
|
454 |
)
|
455 |
|
456 |
+
demo.queue(max_size=12).launch(share=False, show_error=True)
|
requirements.txt
CHANGED
@@ -1,12 +1,10 @@
|
|
1 |
torch==2.5.1
|
2 |
-
spaces==0.
|
3 |
-
gradio
|
4 |
gradio-imageslider
|
5 |
numpy==1.26.4
|
6 |
transformers==4.45.0
|
7 |
accelerate==0.33.0
|
8 |
-
|
9 |
-
diffusers==0.32.2
|
10 |
-
huggingface-hub
|
11 |
fastapi<0.113.0
|
12 |
opencv-python
|
|
|
1 |
torch==2.5.1
|
2 |
+
spaces==0.30.4
|
3 |
+
gradio==4.42.0
|
4 |
gradio-imageslider
|
5 |
numpy==1.26.4
|
6 |
transformers==4.45.0
|
7 |
accelerate==0.33.0
|
8 |
+
diffusers==0.30.3
|
|
|
|
|
9 |
fastapi<0.113.0
|
10 |
opencv-python
|