Allow uploading a background image
Browse files
app.py
CHANGED
|
@@ -43,38 +43,38 @@ pipe.enable_xformers_memory_efficient_attention()
|
|
| 43 |
# pipe.unet = torch.nn.DataParallel(pipe.unet)
|
| 44 |
|
| 45 |
|
| 46 |
-
def resize_for_condition_image(input_image: Image.Image, resolution: int, canvas_width: int = None, canvas_height: int = None):
|
| 47 |
input_image = input_image.convert("RGBA")
|
| 48 |
W, H = input_image.size
|
| 49 |
|
| 50 |
-
#
|
| 51 |
-
if
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
canvas = Image.new("RGBA", (canvas_width, canvas_height), (255, 255, 255, 0))
|
| 57 |
|
| 58 |
# Determine the relative size of the QR code based on the canvas dimensions
|
| 59 |
qr_scale_ratio = 768 / min(1024, 768) # Base ratio (relative to 1024x768)
|
| 60 |
-
qr_target_size = int(min(
|
| 61 |
|
| 62 |
# Resize the QR code to maintain its relative size
|
| 63 |
input_image = input_image.resize((qr_target_size, qr_target_size), resample=Image.LANCZOS)
|
| 64 |
W, H = input_image.size
|
| 65 |
|
| 66 |
-
# Paste the resized QR code
|
| 67 |
-
qr_x = int(
|
| 68 |
-
qr_y = (
|
| 69 |
|
| 70 |
# Use the alpha channel of the input_image as the mask
|
| 71 |
-
canvas.paste(input_image, (qr_x, qr_y), mask=input_image.split()[3])
|
| 72 |
|
| 73 |
return canvas
|
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
|
|
|
|
| 78 |
SAMPLER_MAP = {
|
| 79 |
"DPM++ Karras SDE": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True, algorithm_type="sde-dpmsolver++"),
|
| 80 |
"DPM++ Karras": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True),
|
|
@@ -95,6 +95,7 @@ def inference(
|
|
| 95 |
seed: int = -1,
|
| 96 |
init_image: Image.Image | None = None,
|
| 97 |
qrcode_image: Image.Image | None = None,
|
|
|
|
| 98 |
use_qr_code_as_init_image=True,
|
| 99 |
sampler="DPM++ Karras SDE",
|
| 100 |
width: int = 768,
|
|
@@ -126,15 +127,15 @@ def inference(
|
|
| 126 |
# Add 50% transparency to the white background
|
| 127 |
data = qrcode_image.getdata()
|
| 128 |
new_data = [
|
| 129 |
-
(item[0], item[1], item[2],
|
| 130 |
for item in data
|
| 131 |
]
|
| 132 |
qrcode_image.putdata(new_data)
|
| 133 |
|
| 134 |
-
qrcode_image = resize_for_condition_image(qrcode_image, 768, width, height)
|
| 135 |
else:
|
| 136 |
print("Using QR Code Image")
|
| 137 |
-
qrcode_image = resize_for_condition_image(qrcode_image, 768, width, height)
|
| 138 |
|
| 139 |
# hack due to gradio examples
|
| 140 |
init_image = qrcode_image
|
|
@@ -155,6 +156,7 @@ def inference(
|
|
| 155 |
return out.images[0] # type: ignore
|
| 156 |
|
| 157 |
|
|
|
|
| 158 |
with gr.Blocks() as blocks:
|
| 159 |
gr.Markdown(
|
| 160 |
"""
|
|
@@ -204,6 +206,12 @@ model: https://huggingface.co/DionTimmer/controlnet_qrcode-control_v1p_sd15
|
|
| 204 |
init_image = gr.Image(label="Init Image (Optional). Leave blank to generate image with SD 2.1", type="pil")
|
| 205 |
|
| 206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
with gr.Accordion(
|
| 208 |
label="Params: The generated QR Code functionality is largely influenced by the parameters detailed below",
|
| 209 |
open=True,
|
|
@@ -253,26 +261,26 @@ model: https://huggingface.co/DionTimmer/controlnet_qrcode-control_v1p_sd15
|
|
| 253 |
run_btn = gr.Button("Run")
|
| 254 |
with gr.Column():
|
| 255 |
result_image = gr.Image(label="Result Image")
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
|
| 277 |
gr.Examples(
|
| 278 |
examples=[
|
|
|
|
| 43 |
# pipe.unet = torch.nn.DataParallel(pipe.unet)
|
| 44 |
|
| 45 |
|
| 46 |
+
def resize_for_condition_image(input_image: Image.Image, resolution: int, background_image: Image.Image = None, canvas_width: int = None, canvas_height: int = None):
|
| 47 |
input_image = input_image.convert("RGBA")
|
| 48 |
W, H = input_image.size
|
| 49 |
|
| 50 |
+
# Use the uploaded background image or create a blank canvas
|
| 51 |
+
if background_image:
|
| 52 |
+
background_image = background_image.convert("RGBA")
|
| 53 |
+
canvas = background_image.resize((canvas_width or W, canvas_height or H), Image.LANCZOS)
|
| 54 |
+
else:
|
| 55 |
+
canvas = Image.new("RGBA", (canvas_width or W, canvas_height or H), (255, 255, 255, 0))
|
|
|
|
| 56 |
|
| 57 |
# Determine the relative size of the QR code based on the canvas dimensions
|
| 58 |
qr_scale_ratio = 768 / min(1024, 768) # Base ratio (relative to 1024x768)
|
| 59 |
+
qr_target_size = int(min(canvas.size) * qr_scale_ratio)
|
| 60 |
|
| 61 |
# Resize the QR code to maintain its relative size
|
| 62 |
input_image = input_image.resize((qr_target_size, qr_target_size), resample=Image.LANCZOS)
|
| 63 |
W, H = input_image.size
|
| 64 |
|
| 65 |
+
# Paste the resized QR code onto the background
|
| 66 |
+
qr_x = int(canvas.size[0] * (2 / 3)) - (W // 2) # Adjust x-coordinate to 2/3 of the canvas
|
| 67 |
+
qr_y = (canvas.size[1] - H) // 2 # Center the QR code vertically
|
| 68 |
|
| 69 |
# Use the alpha channel of the input_image as the mask
|
| 70 |
+
canvas.paste(input_image, (qr_x, qr_y), mask=input_image.split()[3])
|
| 71 |
|
| 72 |
return canvas
|
| 73 |
|
| 74 |
|
| 75 |
|
| 76 |
|
| 77 |
+
|
| 78 |
SAMPLER_MAP = {
|
| 79 |
"DPM++ Karras SDE": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True, algorithm_type="sde-dpmsolver++"),
|
| 80 |
"DPM++ Karras": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True),
|
|
|
|
| 95 |
seed: int = -1,
|
| 96 |
init_image: Image.Image | None = None,
|
| 97 |
qrcode_image: Image.Image | None = None,
|
| 98 |
+
background_image: Image.Image | None = None, # New input
|
| 99 |
use_qr_code_as_init_image=True,
|
| 100 |
sampler="DPM++ Karras SDE",
|
| 101 |
width: int = 768,
|
|
|
|
| 127 |
# Add 50% transparency to the white background
|
| 128 |
data = qrcode_image.getdata()
|
| 129 |
new_data = [
|
| 130 |
+
(item[0], item[1], item[2], 128) if item[:3] == (255, 255, 255) else item
|
| 131 |
for item in data
|
| 132 |
]
|
| 133 |
qrcode_image.putdata(new_data)
|
| 134 |
|
| 135 |
+
qrcode_image = resize_for_condition_image(qrcode_image, 768, background_image, width, height)
|
| 136 |
else:
|
| 137 |
print("Using QR Code Image")
|
| 138 |
+
qrcode_image = resize_for_condition_image(qrcode_image, 768, background_image, width, height)
|
| 139 |
|
| 140 |
# hack due to gradio examples
|
| 141 |
init_image = qrcode_image
|
|
|
|
| 156 |
return out.images[0] # type: ignore
|
| 157 |
|
| 158 |
|
| 159 |
+
|
| 160 |
with gr.Blocks() as blocks:
|
| 161 |
gr.Markdown(
|
| 162 |
"""
|
|
|
|
| 206 |
init_image = gr.Image(label="Init Image (Optional). Leave blank to generate image with SD 2.1", type="pil")
|
| 207 |
|
| 208 |
|
| 209 |
+
with gr.Accordion(label="Background Image (Optional)", open=False):
|
| 210 |
+
background_image = gr.Image(
|
| 211 |
+
label="Background Image (Optional). Leave blank for default background",
|
| 212 |
+
type="pil",
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
with gr.Accordion(
|
| 216 |
label="Params: The generated QR Code functionality is largely influenced by the parameters detailed below",
|
| 217 |
open=True,
|
|
|
|
| 261 |
run_btn = gr.Button("Run")
|
| 262 |
with gr.Column():
|
| 263 |
result_image = gr.Image(label="Result Image")
|
| 264 |
+
run_btn.click(
|
| 265 |
+
inference,
|
| 266 |
+
inputs=[
|
| 267 |
+
qr_code_content,
|
| 268 |
+
prompt,
|
| 269 |
+
negative_prompt,
|
| 270 |
+
guidance_scale,
|
| 271 |
+
controlnet_conditioning_scale,
|
| 272 |
+
strength,
|
| 273 |
+
seed,
|
| 274 |
+
init_image,
|
| 275 |
+
qr_code_image,
|
| 276 |
+
use_qr_code_as_init_image,
|
| 277 |
+
sampler,
|
| 278 |
+
width, # add width input
|
| 279 |
+
height, # add height input
|
| 280 |
+
],
|
| 281 |
+
outputs=[result_image],
|
| 282 |
+
concurrency_limit=1
|
| 283 |
+
)
|
| 284 |
|
| 285 |
gr.Examples(
|
| 286 |
examples=[
|