KingNish commited on
Commit
07baece
1 Parent(s): ad4dbe6

Added Option to select where to align the base image.

Browse files

It gives option to user to select in which direction. Image expands.

![image.png](https://cdn-uploads.huggingface.co/production/uploads/6612aedf09f16e7347dfa7e1/2tSuPsxDWyGjWZlHZPZFs.png)

![image.png](https://cdn-uploads.huggingface.co/production/uploads/6612aedf09f16e7347dfa7e1/16V4zj4cDiFWhkzHjuiND.png)

You can try this from here.

https://kingnish-diffusers-image-outpaint.hf.space/?__theme=light&__sign=eyJhbGciOiJFZERTQSJ9.eyJyZWFkIjp0cnVlLCJwZXJtaXNzaW9ucyI6eyJyZXBvLmNvbnRlbnQucmVhZCI6dHJ1ZX0sIm9uQmVoYWxmT2YiOnsia2luZCI6InVzZXIiLCJfaWQiOiI2NjEyYWVkZjA5ZjE2ZTczNDdkZmE3ZTEiLCJ1c2VyIjoiS2luZ05pc2gifSwiaWF0IjoxNzI2OTQ2NDU5LCJzdWIiOiIvc3BhY2VzL0tpbmdOaXNoL2RpZmZ1c2Vycy1pbWFnZS1vdXRwYWludCIsImV4cCI6MTcyNzAzMjg1OSwiaXNzIjoiaHR0cHM6Ly9odWdnaW5nZmFjZS5jbyJ9.myCJz6Exn4S5wrRIrFXELMSIx9HLhAr-o9gJkJ3v13gCbD0eERoJYWQ-OxQ1GI4unzqQSKGzDyGNREXMw1eBCg

Files changed (1) hide show
  1. app.py +128 -57
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",
@@ -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, model_selection, width, height, overlap_width, num_inference_steps, prompt_input=None):
 
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
- margin_x = (target_size[0] - source.width) // 2
72
- margin_y = (target_size[1] - source.height) // 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- mask_draw.rectangle([
80
- (margin_x + overlap, margin_y + overlap),
81
- (margin_x + source.width - overlap, margin_y + source.height - overlap)
82
- ], fill=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- prompt_input = gr.Textbox(label="Prompt (Optional)")
154
-
 
 
 
 
155
  with gr.Row():
156
  target_ratio = gr.Radio(
157
- label = "Expected Ratio",
158
- choices = ["9:16", "16:9", "Custom"],
159
- value = "9:16",
160
- scale = 2
161
  )
162
 
163
- run_button = gr.Button("Generate", scale=1)
 
 
 
 
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=1440,
172
  step=8,
173
  value=720, # Set a default value
174
  )
175
  height_slider = gr.Slider(
176
  label="Height",
177
  minimum=720,
178
- maximum=1440,
179
  step=8,
180
  value=1280, # Set a default value
181
  )
182
  with gr.Row():
183
- model_selection = gr.Dropdown(
184
- choices=list(MODELS.keys()),
185
- value="RealVisXL V5.0 Lightning",
186
- label="Model",
 
 
 
187
  )
188
- num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8 )
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", "RealVisXL V5.0 Lightning", 1280, 720],
201
- ["./examples/example_2.jpg", "RealVisXL V5.0 Lightning", 720, 1280],
202
- ["./examples/example_3.jpg", "RealVisXL V5.0 Lightning", 1024, 1024],
 
203
  ],
204
- inputs=[input_image, model_selection, width_slider, height_slider],
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 = preload_presets,
215
- inputs = [target_ratio],
216
- outputs = [width_slider, height_slider, settings_panel],
217
- queue = False
218
  )
 
219
  run_button.click(
220
  fn=clear_result,
221
  inputs=None,
222
  outputs=result,
223
  ).then(
224
  fn=infer,
225
- inputs=[input_image, model_selection, width_slider, height_slider, overlap_width, num_inference_steps, prompt_input],
 
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, model_selection, width_slider, height_slider, overlap_width, num_inference_steps, prompt_input],
 
236
  outputs=result,
 
 
 
 
237
  )
238
 
239
- 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",
 
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)