Spaces:
Running
on
Zero
Added Option to select where to align the base image.
Browse filesIt gives option to user to select in which direction. Image expands.


You can try this from here.
https://kingnish-diffusers-image-outpaint.hf.space/?__theme=light&__sign=eyJhbGciOiJFZERTQSJ9.eyJyZWFkIjp0cnVlLCJwZXJtaXNzaW9ucyI6eyJyZXBvLmNvbnRlbnQucmVhZCI6dHJ1ZX0sIm9uQmVoYWxmT2YiOnsia2luZCI6InVzZXIiLCJfaWQiOiI2NjEyYWVkZjA5ZjE2ZTczNDdkZmE3ZTEiLCJ1c2VyIjoiS2luZ05pc2gifSwiaWF0IjoxNzI2OTQ2NDU5LCJzdWIiOiIvc3BhY2VzL0tpbmdOaXNoL2RpZmZ1c2Vycy1pbWFnZS1vdXRwYWludCIsImV4cCI6MTcyNzAzMjg1OSwiaXNzIjoiaHR0cHM6Ly9odWdnaW5nZmFjZS5jbyJ9.myCJz6Exn4S5wrRIrFXELMSIx9HLhAr-o9gJkJ3v13gCbD0eERoJYWQ-OxQ1GI4unzqQSKGzDyGNREXMw1eBCg
@@ -12,10 +12,6 @@ from pipeline_fill_sd_xl import StableDiffusionXLFillPipeline
|
|
12 |
from PIL import Image, ImageDraw
|
13 |
import numpy as np
|
14 |
|
15 |
-
MODELS = {
|
16 |
-
"RealVisXL V5.0 Lightning": "SG161222/RealVisXL_V5.0_Lightning",
|
17 |
-
}
|
18 |
-
|
19 |
config_file = hf_hub_download(
|
20 |
"xinsir/controlnet-union-sdxl-1.0",
|
21 |
filename="config_promax.json",
|
@@ -48,11 +44,20 @@ pipe = StableDiffusionXLFillPipeline.from_pretrained(
|
|
48 |
pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
|
49 |
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
@spaces.GPU
|
52 |
-
def infer(image,
|
|
|
53 |
source = image
|
54 |
target_size = (width, height)
|
55 |
-
target_ratio = (width, height) # Calculate aspect ratio from width and height
|
56 |
overlap = overlap_width
|
57 |
|
58 |
# Upscale if source is smaller than target in both dimensions
|
@@ -68,25 +73,63 @@ def infer(image, model_selection, width, height, overlap_width, num_inference_st
|
|
68 |
new_height = int(source.height * scale_factor)
|
69 |
source = source.resize((new_width, new_height), Image.LANCZOS)
|
70 |
|
71 |
-
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
background = Image.new('RGB', target_size, (255, 255, 255))
|
75 |
background.paste(source, (margin_x, margin_y))
|
76 |
|
77 |
mask = Image.new('L', target_size, 255)
|
78 |
mask_draw = ImageDraw.Draw(mask)
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
84 |
cnet_image = background.copy()
|
85 |
cnet_image.paste(0, (0, 0), mask)
|
86 |
|
87 |
-
final_prompt = "high quality"
|
88 |
-
if prompt_input.strip() != "":
|
89 |
-
final_prompt += ", " + prompt_input
|
90 |
|
91 |
(
|
92 |
prompt_embeds,
|
@@ -110,7 +153,14 @@ def infer(image, model_selection, width, height, overlap_width, num_inference_st
|
|
110 |
|
111 |
yield background, cnet_image
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
def preload_presets(target_ratio):
|
|
|
114 |
if target_ratio == "9:16":
|
115 |
changed_width = 720
|
116 |
changed_height = 1280
|
@@ -122,9 +172,6 @@ def preload_presets(target_ratio):
|
|
122 |
elif target_ratio == "Custom":
|
123 |
return 720, 1280, gr.update(open=True)
|
124 |
|
125 |
-
def clear_result():
|
126 |
-
return gr.update(value=None)
|
127 |
-
|
128 |
|
129 |
css = """
|
130 |
.gradio-container {
|
@@ -145,63 +192,64 @@ with gr.Blocks(css=css) as demo:
|
|
145 |
with gr.Column():
|
146 |
input_image = gr.Image(
|
147 |
type="pil",
|
148 |
-
label="Input Image"
|
149 |
-
sources=["upload"],
|
150 |
-
height = 300
|
151 |
)
|
152 |
-
|
153 |
-
|
154 |
-
|
|
|
|
|
|
|
|
|
155 |
with gr.Row():
|
156 |
target_ratio = gr.Radio(
|
157 |
-
label
|
158 |
-
choices
|
159 |
-
value
|
160 |
-
scale
|
161 |
)
|
162 |
|
163 |
-
|
|
|
|
|
|
|
|
|
164 |
|
165 |
with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
|
166 |
-
with gr.Column():
|
167 |
with gr.Row():
|
168 |
width_slider = gr.Slider(
|
169 |
label="Width",
|
170 |
minimum=720,
|
171 |
-
maximum=
|
172 |
step=8,
|
173 |
value=720, # Set a default value
|
174 |
)
|
175 |
height_slider = gr.Slider(
|
176 |
label="Height",
|
177 |
minimum=720,
|
178 |
-
maximum=
|
179 |
step=8,
|
180 |
value=1280, # Set a default value
|
181 |
)
|
182 |
with gr.Row():
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
|
|
|
|
|
|
187 |
)
|
188 |
-
|
189 |
-
|
190 |
-
overlap_width = gr.Slider(
|
191 |
-
label="Mask overlap width",
|
192 |
-
minimum=1,
|
193 |
-
maximum=50,
|
194 |
-
value=42,
|
195 |
-
step=1
|
196 |
-
)
|
197 |
-
|
198 |
gr.Examples(
|
199 |
examples=[
|
200 |
-
["./examples/example_1.webp",
|
201 |
-
["./examples/example_2.jpg",
|
202 |
-
["./examples/example_3.jpg",
|
|
|
203 |
],
|
204 |
-
inputs=[input_image,
|
205 |
)
|
206 |
|
207 |
with gr.Column():
|
@@ -209,21 +257,38 @@ with gr.Blocks(css=css) as demo:
|
|
209 |
interactive=False,
|
210 |
label="Generated Image",
|
211 |
)
|
|
|
|
|
|
|
|
|
|
|
212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
target_ratio.change(
|
214 |
-
fn
|
215 |
-
inputs
|
216 |
-
outputs
|
217 |
-
queue
|
218 |
)
|
|
|
219 |
run_button.click(
|
220 |
fn=clear_result,
|
221 |
inputs=None,
|
222 |
outputs=result,
|
223 |
).then(
|
224 |
fn=infer,
|
225 |
-
inputs=[input_image,
|
|
|
226 |
outputs=result,
|
|
|
|
|
|
|
|
|
227 |
)
|
228 |
|
229 |
prompt_input.submit(
|
@@ -232,8 +297,14 @@ with gr.Blocks(css=css) as demo:
|
|
232 |
outputs=result,
|
233 |
).then(
|
234 |
fn=infer,
|
235 |
-
inputs=[input_image,
|
|
|
236 |
outputs=result,
|
|
|
|
|
|
|
|
|
237 |
)
|
238 |
|
239 |
-
|
|
|
|
12 |
from PIL import Image, ImageDraw
|
13 |
import numpy as np
|
14 |
|
|
|
|
|
|
|
|
|
15 |
config_file = hf_hub_download(
|
16 |
"xinsir/controlnet-union-sdxl-1.0",
|
17 |
filename="config_promax.json",
|
|
|
44 |
pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
|
45 |
|
46 |
|
47 |
+
def can_expand(source_width, source_height, target_width, target_height, alignment):
|
48 |
+
"""Checks if the image can be expanded based on the alignment."""
|
49 |
+
if alignment in ("Left", "Right") and source_width >= target_width:
|
50 |
+
return False
|
51 |
+
if alignment in ("Top", "Bottom") and source_height >= target_height:
|
52 |
+
return False
|
53 |
+
return True
|
54 |
+
|
55 |
+
|
56 |
@spaces.GPU
|
57 |
+
def infer(image, width, height, overlap_width, num_inference_steps, prompt_input=None, alignment="Middle"):
|
58 |
+
|
59 |
source = image
|
60 |
target_size = (width, height)
|
|
|
61 |
overlap = overlap_width
|
62 |
|
63 |
# Upscale if source is smaller than target in both dimensions
|
|
|
73 |
new_height = int(source.height * scale_factor)
|
74 |
source = source.resize((new_width, new_height), Image.LANCZOS)
|
75 |
|
76 |
+
if not can_expand(source.width, source.height, target_size[0], target_size[1], alignment):
|
77 |
+
alignment = "Middle"
|
78 |
+
|
79 |
+
# Calculate margins based on alignment
|
80 |
+
if alignment == "Middle":
|
81 |
+
margin_x = (target_size[0] - source.width) // 2
|
82 |
+
margin_y = (target_size[1] - source.height) // 2
|
83 |
+
elif alignment == "Left":
|
84 |
+
margin_x = 0
|
85 |
+
margin_y = (target_size[1] - source.height) // 2
|
86 |
+
elif alignment == "Right":
|
87 |
+
margin_x = target_size[0] - source.width
|
88 |
+
margin_y = (target_size[1] - source.height) // 2
|
89 |
+
elif alignment == "Top":
|
90 |
+
margin_x = (target_size[0] - source.width) // 2
|
91 |
+
margin_y = 0
|
92 |
+
elif alignment == "Bottom":
|
93 |
+
margin_x = (target_size[0] - source.width) // 2
|
94 |
+
margin_y = target_size[1] - source.height
|
95 |
|
96 |
background = Image.new('RGB', target_size, (255, 255, 255))
|
97 |
background.paste(source, (margin_x, margin_y))
|
98 |
|
99 |
mask = Image.new('L', target_size, 255)
|
100 |
mask_draw = ImageDraw.Draw(mask)
|
101 |
+
|
102 |
+
# Adjust mask generation based on alignment
|
103 |
+
if alignment == "Middle":
|
104 |
+
mask_draw.rectangle([
|
105 |
+
(margin_x + overlap, margin_y + overlap),
|
106 |
+
(margin_x + source.width - overlap, margin_y + source.height - overlap)
|
107 |
+
], fill=0)
|
108 |
+
elif alignment == "Left":
|
109 |
+
mask_draw.rectangle([
|
110 |
+
(margin_x, margin_y),
|
111 |
+
(margin_x + source.width - overlap, margin_y + source.height)
|
112 |
+
], fill=0)
|
113 |
+
elif alignment == "Right":
|
114 |
+
mask_draw.rectangle([
|
115 |
+
(margin_x + overlap, margin_y),
|
116 |
+
(margin_x + source.width, margin_y + source.height)
|
117 |
+
], fill=0)
|
118 |
+
elif alignment == "Top":
|
119 |
+
mask_draw.rectangle([
|
120 |
+
(margin_x, margin_y),
|
121 |
+
(margin_x + source.width, margin_y + source.height - overlap)
|
122 |
+
], fill=0)
|
123 |
+
elif alignment == "Bottom":
|
124 |
+
mask_draw.rectangle([
|
125 |
+
(margin_x, margin_y + overlap),
|
126 |
+
(margin_x + source.width, margin_y + source.height)
|
127 |
+
], fill=0)
|
128 |
|
129 |
cnet_image = background.copy()
|
130 |
cnet_image.paste(0, (0, 0), mask)
|
131 |
|
132 |
+
final_prompt = f"{prompt_input} , high quality, 4k"
|
|
|
|
|
133 |
|
134 |
(
|
135 |
prompt_embeds,
|
|
|
153 |
|
154 |
yield background, cnet_image
|
155 |
|
156 |
+
|
157 |
+
def clear_result():
|
158 |
+
"""Clears the result ImageSlider."""
|
159 |
+
return gr.update(value=None)
|
160 |
+
|
161 |
+
|
162 |
def preload_presets(target_ratio):
|
163 |
+
"""Updates the width and height sliders based on the selected aspect ratio."""
|
164 |
if target_ratio == "9:16":
|
165 |
changed_width = 720
|
166 |
changed_height = 1280
|
|
|
172 |
elif target_ratio == "Custom":
|
173 |
return 720, 1280, gr.update(open=True)
|
174 |
|
|
|
|
|
|
|
175 |
|
176 |
css = """
|
177 |
.gradio-container {
|
|
|
192 |
with gr.Column():
|
193 |
input_image = gr.Image(
|
194 |
type="pil",
|
195 |
+
label="Input Image"
|
|
|
|
|
196 |
)
|
197 |
+
|
198 |
+
with gr.Row():
|
199 |
+
with gr.Column(scale=2):
|
200 |
+
prompt_input = gr.Textbox(label="Prompt (Optional)")
|
201 |
+
with gr.Column(scale=1):
|
202 |
+
run_button = gr.Button("Generate")
|
203 |
+
|
204 |
with gr.Row():
|
205 |
target_ratio = gr.Radio(
|
206 |
+
label="Expected Ratio",
|
207 |
+
choices=["9:16", "16:9", "Custom"],
|
208 |
+
value="9:16",
|
209 |
+
scale=2
|
210 |
)
|
211 |
|
212 |
+
alignment_dropdown = gr.Dropdown(
|
213 |
+
choices=["Middle", "Left", "Right", "Top", "Bottom"],
|
214 |
+
value="Middle",
|
215 |
+
label="Alignment"
|
216 |
+
)
|
217 |
|
218 |
with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
|
219 |
+
with gr.Column():
|
220 |
with gr.Row():
|
221 |
width_slider = gr.Slider(
|
222 |
label="Width",
|
223 |
minimum=720,
|
224 |
+
maximum=1536,
|
225 |
step=8,
|
226 |
value=720, # Set a default value
|
227 |
)
|
228 |
height_slider = gr.Slider(
|
229 |
label="Height",
|
230 |
minimum=720,
|
231 |
+
maximum=1536,
|
232 |
step=8,
|
233 |
value=1280, # Set a default value
|
234 |
)
|
235 |
with gr.Row():
|
236 |
+
num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
|
237 |
+
overlap_width = gr.Slider(
|
238 |
+
label="Mask overlap width",
|
239 |
+
minimum=1,
|
240 |
+
maximum=50,
|
241 |
+
value=42,
|
242 |
+
step=1
|
243 |
)
|
244 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
gr.Examples(
|
246 |
examples=[
|
247 |
+
["./examples/example_1.webp", 1280, 720, "Middle"],
|
248 |
+
["./examples/example_2.jpg", 1440, 810, "Left"],
|
249 |
+
["./examples/example_3.jpg", 1024, 1024, "Top"],
|
250 |
+
["./examples/example_3.jpg", 1024, 1024, "Bottom"],
|
251 |
],
|
252 |
+
inputs=[input_image, width_slider, height_slider, alignment_dropdown],
|
253 |
)
|
254 |
|
255 |
with gr.Column():
|
|
|
257 |
interactive=False,
|
258 |
label="Generated Image",
|
259 |
)
|
260 |
+
use_as_input_button = gr.Button("Use as Input Image", visible=False)
|
261 |
+
|
262 |
+
def use_output_as_input(output_image):
|
263 |
+
"""Sets the generated output as the new input image."""
|
264 |
+
return gr.update(value=output_image[1])
|
265 |
|
266 |
+
use_as_input_button.click(
|
267 |
+
fn=use_output_as_input,
|
268 |
+
inputs=[result],
|
269 |
+
outputs=[input_image]
|
270 |
+
)
|
271 |
+
|
272 |
target_ratio.change(
|
273 |
+
fn=preload_presets,
|
274 |
+
inputs=[target_ratio],
|
275 |
+
outputs=[width_slider, height_slider, settings_panel],
|
276 |
+
queue=False
|
277 |
)
|
278 |
+
|
279 |
run_button.click(
|
280 |
fn=clear_result,
|
281 |
inputs=None,
|
282 |
outputs=result,
|
283 |
).then(
|
284 |
fn=infer,
|
285 |
+
inputs=[input_image, width_slider, height_slider, overlap_width, num_inference_steps,
|
286 |
+
prompt_input, alignment_dropdown],
|
287 |
outputs=result,
|
288 |
+
).then(
|
289 |
+
fn=lambda: gr.update(visible=True),
|
290 |
+
inputs=None,
|
291 |
+
outputs=use_as_input_button,
|
292 |
)
|
293 |
|
294 |
prompt_input.submit(
|
|
|
297 |
outputs=result,
|
298 |
).then(
|
299 |
fn=infer,
|
300 |
+
inputs=[input_image, width_slider, height_slider, overlap_width, num_inference_steps,
|
301 |
+
prompt_input, alignment_dropdown],
|
302 |
outputs=result,
|
303 |
+
).then(
|
304 |
+
fn=lambda: gr.update(visible=True),
|
305 |
+
inputs=None,
|
306 |
+
outputs=use_as_input_button,
|
307 |
)
|
308 |
|
309 |
+
|
310 |
+
demo.queue(max_size=12).launch(share=False)
|