multimodalart HF staff commited on
Commit
3fd7963
1 Parent(s): e5a75ef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -61
app.py CHANGED
@@ -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",
@@ -47,12 +43,18 @@ pipe = StableDiffusionXLFillPipeline.from_pretrained(
47
 
48
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
49
 
 
 
 
 
 
 
 
50
 
51
  @spaces.GPU
52
- def infer(image, model_selection, width, height, overlap_width, num_inference_steps, resize_size, prompt_input=None):
53
  source = image
54
  target_size = (width, height)
55
- target_ratio = (width, height)
56
  overlap = overlap_width
57
 
58
  # New resizing logic based on resize_size
@@ -76,25 +78,63 @@ def infer(image, model_selection, width, height, overlap_width, num_inference_st
76
  new_height = int(source.height * scale_factor)
77
  source = source.resize((new_width, new_height), Image.LANCZOS)
78
 
79
- margin_x = (target_size[0] - source.width) // 2
80
- margin_y = (target_size[1] - source.height) // 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  background = Image.new('RGB', target_size, (255, 255, 255))
83
  background.paste(source, (margin_x, margin_y))
84
 
85
  mask = Image.new('L', target_size, 255)
86
  mask_draw = ImageDraw.Draw(mask)
87
- mask_draw.rectangle([
88
- (margin_x + overlap, margin_y + overlap),
89
- (margin_x + source.width - overlap, margin_y + source.height - overlap)
90
- ], fill=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  cnet_image = background.copy()
93
  cnet_image.paste(0, (0, 0), mask)
94
 
95
- final_prompt = "high quality"
96
- if prompt_input.strip() != "":
97
- final_prompt += ", " + prompt_input
98
 
99
  (
100
  prompt_embeds,
@@ -118,7 +158,12 @@ def infer(image, model_selection, width, height, overlap_width, num_inference_st
118
 
119
  yield background, cnet_image
120
 
121
- def preload_presets(target_ratio):
 
 
 
 
 
122
  if target_ratio == "9:16":
123
  changed_width = 720
124
  changed_height = 1280
@@ -128,11 +173,15 @@ def preload_presets(target_ratio):
128
  changed_height = 720
129
  return changed_width, changed_height, gr.update(open=False)
130
  elif target_ratio == "Custom":
131
- return 720, 1280, gr.update(open=True)
132
-
133
- def clear_result():
134
- return gr.update(value=None)
135
 
 
 
 
 
 
 
 
136
 
137
  css = """
138
  .gradio-container {
@@ -140,7 +189,6 @@ css = """
140
  }
141
  """
142
 
143
-
144
  title = """<h1 align="center">Diffusers Image Outpaint</h1>
145
  <div align="center">Drop an image you would like to extend, pick your expected ratio and hit Generate.</div>
146
  <div style="display: flex; justify-content: center; align-items: center; text-align: center;">
@@ -160,69 +208,69 @@ with gr.Blocks(css=css) as demo:
160
  with gr.Column():
161
  input_image = gr.Image(
162
  type="pil",
163
- label="Input Image",
164
- sources=["upload"],
165
- height = 300
166
  )
167
-
168
- prompt_input = gr.Textbox(label="Prompt (Optional)")
169
-
 
 
 
 
170
  with gr.Row():
171
  target_ratio = gr.Radio(
172
- label = "Expected Ratio",
173
- choices = ["9:16", "16:9", "Custom"],
174
- value = "9:16",
175
- scale = 2
176
  )
177
 
178
- run_button = gr.Button("Generate", scale=1)
 
 
 
 
179
 
180
  with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
181
- with gr.Column():
182
  with gr.Row():
183
  width_slider = gr.Slider(
184
  label="Width",
185
  minimum=720,
186
- maximum=1440,
187
  step=8,
188
  value=720,
189
  )
190
  height_slider = gr.Slider(
191
  label="Height",
192
  minimum=720,
193
- maximum=1440,
194
  step=8,
195
  value=1280,
196
  )
197
  with gr.Row():
198
- model_selection = gr.Dropdown(
199
- choices=list(MODELS.keys()),
200
- value="RealVisXL V5.0 Lightning",
201
- label="Model",
202
- )
203
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
204
-
205
- overlap_width = gr.Slider(
206
- label="Mask overlap width",
207
- minimum=1,
208
- maximum=50,
209
- value=42,
210
- step=1
211
- )
212
-
213
  resize_size = gr.Number(
214
  label="Resize Size (-1 for default behavior)",
215
  value=-1,
216
  precision=0
217
  )
218
-
219
  gr.Examples(
220
  examples=[
221
- ["./examples/example_1.webp", "RealVisXL V5.0 Lightning", 1280, 720],
222
- ["./examples/example_2.jpg", "RealVisXL V5.0 Lightning", 720, 1280],
223
- ["./examples/example_3.jpg", "RealVisXL V5.0 Lightning", 1024, 1024],
 
224
  ],
225
- inputs=[input_image, model_selection, width_slider, height_slider],
226
  )
227
 
228
  with gr.Column():
@@ -230,21 +278,52 @@ with gr.Blocks(css=css) as demo:
230
  interactive=False,
231
  label="Generated Image",
232
  )
 
233
 
 
 
 
 
 
 
 
 
 
 
234
  target_ratio.change(
235
- fn = preload_presets,
236
- inputs = [target_ratio],
237
- outputs = [width_slider, height_slider, settings_panel],
238
- queue = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  )
 
240
  run_button.click(
241
  fn=clear_result,
242
  inputs=None,
243
  outputs=result,
244
  ).then(
245
  fn=infer,
246
- inputs=[input_image, model_selection, width_slider, height_slider, overlap_width, num_inference_steps, resize_size, prompt_input],
 
247
  outputs=result,
 
 
 
 
248
  )
249
 
250
  prompt_input.submit(
@@ -253,8 +332,13 @@ with gr.Blocks(css=css) as demo:
253
  outputs=result,
254
  ).then(
255
  fn=infer,
256
- inputs=[input_image, model_selection, width_slider, height_slider, overlap_width, num_inference_steps, resize_size, prompt_input],
 
257
  outputs=result,
 
 
 
 
258
  )
259
 
260
- demo.queue(max_size=12).launch(share=False, show_error=True, show_api=False)
 
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",
 
43
 
44
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
45
 
46
+ def can_expand(source_width, source_height, target_width, target_height, alignment):
47
+ """Checks if the image can be expanded based on the alignment."""
48
+ if alignment in ("Left", "Right") and source_width >= target_width:
49
+ return False
50
+ if alignment in ("Top", "Bottom") and source_height >= target_height:
51
+ return False
52
+ return True
53
 
54
  @spaces.GPU
55
+ def infer(image, width, height, overlap_width, num_inference_steps, resize_size, prompt_input=None, alignment="Middle"):
56
  source = image
57
  target_size = (width, height)
 
58
  overlap = overlap_width
59
 
60
  # New resizing logic based on resize_size
 
78
  new_height = int(source.height * scale_factor)
79
  source = source.resize((new_width, new_height), Image.LANCZOS)
80
 
81
+ if not can_expand(source.width, source.height, target_size[0], target_size[1], alignment):
82
+ alignment = "Middle"
83
+
84
+ # Calculate margins based on alignment
85
+ if alignment == "Middle":
86
+ margin_x = (target_size[0] - source.width) // 2
87
+ margin_y = (target_size[1] - source.height) // 2
88
+ elif alignment == "Left":
89
+ margin_x = 0
90
+ margin_y = (target_size[1] - source.height) // 2
91
+ elif alignment == "Right":
92
+ margin_x = target_size[0] - source.width
93
+ margin_y = (target_size[1] - source.height) // 2
94
+ elif alignment == "Top":
95
+ margin_x = (target_size[0] - source.width) // 2
96
+ margin_y = 0
97
+ elif alignment == "Bottom":
98
+ margin_x = (target_size[0] - source.width) // 2
99
+ margin_y = target_size[1] - source.height
100
 
101
  background = Image.new('RGB', target_size, (255, 255, 255))
102
  background.paste(source, (margin_x, margin_y))
103
 
104
  mask = Image.new('L', target_size, 255)
105
  mask_draw = ImageDraw.Draw(mask)
106
+
107
+ # Adjust mask generation based on alignment
108
+ if alignment == "Middle":
109
+ mask_draw.rectangle([
110
+ (margin_x + overlap, margin_y + overlap),
111
+ (margin_x + source.width - overlap, margin_y + source.height - overlap)
112
+ ], fill=0)
113
+ elif alignment == "Left":
114
+ mask_draw.rectangle([
115
+ (margin_x, margin_y),
116
+ (margin_x + source.width - overlap, margin_y + source.height)
117
+ ], fill=0)
118
+ elif alignment == "Right":
119
+ mask_draw.rectangle([
120
+ (margin_x + overlap, margin_y),
121
+ (margin_x + source.width, margin_y + source.height)
122
+ ], fill=0)
123
+ elif alignment == "Top":
124
+ mask_draw.rectangle([
125
+ (margin_x, margin_y),
126
+ (margin_x + source.width, margin_y + source.height - overlap)
127
+ ], fill=0)
128
+ elif alignment == "Bottom":
129
+ mask_draw.rectangle([
130
+ (margin_x, margin_y + overlap),
131
+ (margin_x + source.width, margin_y + source.height)
132
+ ], fill=0)
133
 
134
  cnet_image = background.copy()
135
  cnet_image.paste(0, (0, 0), mask)
136
 
137
+ final_prompt = f"{prompt_input} , high quality, 4k"
 
 
138
 
139
  (
140
  prompt_embeds,
 
158
 
159
  yield background, cnet_image
160
 
161
+ def clear_result():
162
+ """Clears the result ImageSlider."""
163
+ return gr.update(value=None)
164
+
165
+ def preload_presets(target_ratio, ui_width, ui_height):
166
+ """Updates the width and height sliders based on the selected aspect ratio."""
167
  if target_ratio == "9:16":
168
  changed_width = 720
169
  changed_height = 1280
 
173
  changed_height = 720
174
  return changed_width, changed_height, gr.update(open=False)
175
  elif target_ratio == "Custom":
176
+ return ui_width, ui_height, gr.update(open=True)
 
 
 
177
 
178
+ def select_the_right_preset(user_width, user_height):
179
+ if user_width == 720 and user_height == 1280:
180
+ return "9:16"
181
+ elif user_width == 1280 and user_height == 720:
182
+ return "16:9"
183
+ else:
184
+ return "Custom"
185
 
186
  css = """
187
  .gradio-container {
 
189
  }
190
  """
191
 
 
192
  title = """<h1 align="center">Diffusers Image Outpaint</h1>
193
  <div align="center">Drop an image you would like to extend, pick your expected ratio and hit Generate.</div>
194
  <div style="display: flex; justify-content: center; align-items: center; text-align: center;">
 
208
  with gr.Column():
209
  input_image = gr.Image(
210
  type="pil",
211
+ label="Input Image"
 
 
212
  )
213
+
214
+ with gr.Row():
215
+ with gr.Column(scale=2):
216
+ prompt_input = gr.Textbox(label="Prompt (Optional)")
217
+ with gr.Column(scale=1):
218
+ run_button = gr.Button("Generate")
219
+
220
  with gr.Row():
221
  target_ratio = gr.Radio(
222
+ label="Expected Ratio",
223
+ choices=["9:16", "16:9", "Custom"],
224
+ value="9:16",
225
+ scale=2
226
  )
227
 
228
+ alignment_dropdown = gr.Dropdown(
229
+ choices=["Middle", "Left", "Right", "Top", "Bottom"],
230
+ value="Middle",
231
+ label="Alignment"
232
+ )
233
 
234
  with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
235
+ with gr.Column():
236
  with gr.Row():
237
  width_slider = gr.Slider(
238
  label="Width",
239
  minimum=720,
240
+ maximum=1536,
241
  step=8,
242
  value=720,
243
  )
244
  height_slider = gr.Slider(
245
  label="Height",
246
  minimum=720,
247
+ maximum=1536,
248
  step=8,
249
  value=1280,
250
  )
251
  with gr.Row():
 
 
 
 
 
252
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
253
+ overlap_width = gr.Slider(
254
+ label="Mask overlap width",
255
+ minimum=1,
256
+ maximum=50,
257
+ value=42,
258
+ step=1
259
+ )
 
 
260
  resize_size = gr.Number(
261
  label="Resize Size (-1 for default behavior)",
262
  value=-1,
263
  precision=0
264
  )
265
+
266
  gr.Examples(
267
  examples=[
268
+ ["./examples/example_1.webp", 1280, 720, "Middle"],
269
+ ["./examples/example_2.jpg", 1440, 810, "Left"],
270
+ ["./examples/example_3.jpg", 1024, 1024, "Top"],
271
+ ["./examples/example_3.jpg", 1024, 1024, "Bottom"],
272
  ],
273
+ inputs=[input_image, width_slider, height_slider, alignment_dropdown],
274
  )
275
 
276
  with gr.Column():
 
278
  interactive=False,
279
  label="Generated Image",
280
  )
281
+ use_as_input_button = gr.Button("Use as Input Image", visible=False)
282
 
283
+ def use_output_as_input(output_image):
284
+ """Sets the generated output as the new input image."""
285
+ return gr.update(value=output_image[1])
286
+
287
+ use_as_input_button.click(
288
+ fn=use_output_as_input,
289
+ inputs=[result],
290
+ outputs=[input_image]
291
+ )
292
+
293
  target_ratio.change(
294
+ fn=preload_presets,
295
+ inputs=[target_ratio, width_slider, height_slider],
296
+ outputs=[width_slider, height_slider, settings_panel],
297
+ queue=False
298
+ )
299
+
300
+ width_slider.change(
301
+ fn=select_the_right_preset,
302
+ inputs=[width_slider, height_slider],
303
+ outputs=[target_ratio],
304
+ queue=False
305
+ )
306
+
307
+ height_slider.change(
308
+ fn=select_the_right_preset,
309
+ inputs=[width_slider, height_slider],
310
+ outputs=[target_ratio],
311
+ queue=False
312
  )
313
+
314
  run_button.click(
315
  fn=clear_result,
316
  inputs=None,
317
  outputs=result,
318
  ).then(
319
  fn=infer,
320
+ inputs=[input_image, width_slider, height_slider, overlap_width, num_inference_steps,
321
+ resize_size, prompt_input, alignment_dropdown],
322
  outputs=result,
323
+ ).then(
324
+ fn=lambda: gr.update(visible=True),
325
+ inputs=None,
326
+ outputs=use_as_input_button,
327
  )
328
 
329
  prompt_input.submit(
 
332
  outputs=result,
333
  ).then(
334
  fn=infer,
335
+ inputs=[input_image, width_slider, height_slider, overlap_width, num_inference_steps,
336
+ resize_size, prompt_input, alignment_dropdown],
337
  outputs=result,
338
+ ).then(
339
+ fn=lambda: gr.update(visible=True),
340
+ inputs=None,
341
+ outputs=use_as_input_button,
342
  )
343
 
344
+ demo.queue(max_size=12).launch(share=False)