Tanut commited on
Commit
3315876
·
1 Parent(s): 9b43269

Edit QR stylizer

Browse files
Files changed (1) hide show
  1. app.py +67 -49
app.py CHANGED
@@ -5,6 +5,7 @@ from PIL import Image
5
  import qrcode
6
  from qrcode.constants import ERROR_CORRECT_H
7
 
 
8
  # ========= device/dtype =========
9
  device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
10
  dtype = torch.float16 if device != "cpu" else torch.float32
@@ -44,58 +45,64 @@ def make_qr(url: str = "http://www.mybirdfire.com", size: int = 512, border: int
44
  return img.resize((size, size), resample=Image.NEAREST)
45
 
46
  # ========= ControlNet Stylizer (SD1.5 + sd15-canny) =========
47
- _cn = {"pipe": None}
48
- def _load_controlnet_dual():
49
- if _cn["pipe"] is None:
50
- from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
51
- from diffusers.schedulers.scheduling_euler_discrete import EulerDiscreteScheduler
52
- from controlnet_aux import CannyDetector
53
-
54
- canny = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=dtype)
55
- tile = ControlNetModel.from_pretrained("lllyasviel/control_v11f1e_sd15_tile", torch_dtype=dtype)
56
-
57
- pipe = StableDiffusionControlNetPipeline.from_pretrained(
58
- "runwayml/stable-diffusion-v1-5",
59
- controlnet=[canny, tile], # <— dual CN
60
- torch_dtype=dtype,
61
- safety_checker=None
 
62
  ).to(device)
63
-
64
  pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config)
65
- pipe.enable_attention_slicing()
66
  pipe.enable_vae_slicing()
 
 
 
67
 
68
- _cn["pipe"] = pipe
69
- _cn["cannyx"] = CannyDetector()
70
- return _cn["pipe"], _cn["cannyx"]
71
-
72
- NEG_DEFAULT = "lowres, low contrast, blurry, washed out, jpeg artifacts, worst quality"
73
-
74
 
75
- def stylize_qr(prompt: str, negative: str, steps: int, guidance: float, seed: int,
76
- canny_low: int, canny_high: int):
77
- qr_image = make_qr("http://www.mybirdfire.com", size=512, border=6)
78
- pipe, canny = _load_controlnet_dual()
 
 
 
79
 
80
- # edge map for canny CN; tile CN uses the raw QR
81
- edges = canny(qr_image, low_threshold=int(canny_low), high_threshold=int(canny_high))
82
 
83
- gen = torch.Generator(device=device).manual_seed(int(seed)) if int(seed) != 0 else None
84
-
85
- # weights per controlnet: [canny_weight, tile_weight]
86
- cn_scales = [1.20, 0.60] # stronger structure, lighter texture
87
 
88
  def run():
89
- return pipe(
90
- prompt=str(prompt),
91
- negative_prompt=negative or NEG_DEFAULT,
92
- image=[edges, qr_image],
93
- controlnet_conditioning_scale=cn_scales,
 
 
94
  num_inference_steps=int(steps),
95
  guidance_scale=float(guidance),
96
  generator=gen
97
  ).images[0]
98
 
 
 
 
 
 
99
  if device in ("cuda", "mps"):
100
  with torch.autocast(device):
101
  return run()
@@ -107,7 +114,7 @@ with gr.Blocks() as demo:
107
  gr.Markdown("## Stable Diffusion + QR Code + ControlNet")
108
 
109
  with gr.Tab("Stable Diffusion (prompt → image)"):
110
- prompt = gr.Textbox(label="Prompt", value="A fantasy castle at sunset")
111
  negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, worst quality")
112
  steps = gr.Slider(10, 50, value=30, label="Steps", step=1)
113
  cfg = gr.Slider(1, 12, value=7.0, label="Guidance Scale", step=0.1)
@@ -122,16 +129,27 @@ with gr.Blocks() as demo:
122
  out_qr = gr.Image(label="QR Code", type="pil")
123
  gr.Button("Generate QR").click(make_qr, [url, size, quiet], out_qr)
124
 
125
- with gr.Tab("QR Stylizer (ControlNet sd15-canny + Euler)"):
126
- s_prompt = gr.Textbox(label="Style Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet")
127
- s_negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)")
128
- s_steps = gr.Slider(10, 50, value=28, label="Steps", step=1)
129
- s_cfg = gr.Slider(1, 12, value=7.0, label="CFG", step=0.1)
130
- s_seed = gr.Number(value=1470713301, label="Seed", precision=0)
131
- canny_l = gr.Slider(0, 255, value=80, step=1, label="Canny low")
132
- canny_h = gr.Slider(0, 255, value=160, step=1, label="Canny high")
133
- out_styl = gr.Image(label="Stylized QR")
134
- gr.Button("Stylize").click(stylize_qr, [s_prompt, s_negative, s_steps, s_cfg, s_seed, canny_l, canny_h], out_styl)
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  if __name__ == "__main__":
137
  demo.launch()
 
5
  import qrcode
6
  from qrcode.constants import ERROR_CORRECT_H
7
 
8
+
9
  # ========= device/dtype =========
10
  device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
11
  dtype = torch.float16 if device != "cpu" else torch.float32
 
45
  return img.resize((size, size), resample=Image.NEAREST)
46
 
47
  # ========= ControlNet Stylizer (SD1.5 + sd15-canny) =========
48
+ # --- SDXL dual ControlNet stylizer (canny + tile) ---
49
+ from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel
50
+ from diffusers.schedulers.scheduling_euler_discrete import EulerDiscreteScheduler
51
+ from controlnet_aux import CannyDetector
52
+
53
+ SDXL_MODEL = "stabilityai/stable-diffusion-xl-base-1.0" # swap to your SDXL anime checkpoint if you have one
54
+ CN_CANNY = "diffusers/controlnet-canny-sdxl-1.0"
55
+ CN_TILE = "diffusers/controlnet-tile-sdxl-1.0"
56
+
57
+ _sdxl = {"pipe": None}
58
+ def _load_sdxl_dual():
59
+ if _sdxl["pipe"] is None:
60
+ cn1 = ControlNetModel.from_pretrained(CN_CANNY, torch_dtype=dtype)
61
+ cn2 = ControlNetModel.from_pretrained(CN_TILE, torch_dtype=dtype)
62
+ pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
63
+ SDXL_MODEL, controlnet=[cn1, cn2], torch_dtype=dtype, safety_checker=None
64
  ).to(device)
 
65
  pipe.scheduler = EulerDiscreteScheduler.from_config(pipe.scheduler.config)
 
66
  pipe.enable_vae_slicing()
67
+ _sdxl["pipe"] = pipe
68
+ _sdxl["canny"] = CannyDetector()
69
+ return _sdxl["pipe"], _sdxl["canny"]
70
 
71
+ NEG = "lowres, low contrast, blurry, jpeg artifacts, worst quality, extra digits, bad anatomy"
 
 
 
 
 
72
 
73
+ def stylize_qr_sdxl(prompt: str, steps: int=28, guidance: float=7.0, seed: int=1470713301,
74
+ canny_low: int=80, canny_high: int=160):
75
+ # 1) make a strong QR @1024
76
+ qr = make_qr("http://www.mybirdfire.com", size=1024, border=6)
77
+ # 2) edges for canny CN
78
+ pipe, canny = _load_sdxl_dual()
79
+ edges = canny(qr, low_threshold=int(canny_low), high_threshold=int(canny_high))
80
 
81
+ gen = torch.Generator(device=device).manual_seed(int(seed)) if int(seed)!=0 else None
 
82
 
83
+ # Control weights + schedule (canny, tile)
84
+ cn_scales = [1.1, 0.6]
85
+ cn_start = [0.25, 0.00]
86
+ cn_end = [0.95, 1.00]
87
 
88
  def run():
89
+ img = pipe(
90
+ prompt=prompt,
91
+ negative_prompt=NEG,
92
+ image=[edges, qr], # canny first, tile second
93
+ controlnet_conditioning_scale=cn_scales, # strengths
94
+ control_guidance_start=cn_start, # when they start
95
+ control_guidance_end=cn_end, # when they end
96
  num_inference_steps=int(steps),
97
  guidance_scale=float(guidance),
98
  generator=gen
99
  ).images[0]
100
 
101
+ # optional: re‑overlay razor‑sharp finder squares to boost scanning
102
+ # (uncomment if scans are borderline)
103
+ # img = overlay_finders(img, qr)
104
+ return img
105
+
106
  if device in ("cuda", "mps"):
107
  with torch.autocast(device):
108
  return run()
 
114
  gr.Markdown("## Stable Diffusion + QR Code + ControlNet")
115
 
116
  with gr.Tab("Stable Diffusion (prompt → image)"):
117
+ prompt = gr.Textbox(label="Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
118
  negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, worst quality")
119
  steps = gr.Slider(10, 50, value=30, label="Steps", step=1)
120
  cfg = gr.Slider(1, 12, value=7.0, label="Guidance Scale", step=0.1)
 
129
  out_qr = gr.Image(label="QR Code", type="pil")
130
  gr.Button("Generate QR").click(make_qr, [url, size, quiet], out_qr)
131
 
132
+ # with gr.Tab("QR Stylizer (ControlNet sd15-canny + Euler)"):
133
+ # s_prompt = gr.Textbox(label="Style Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
134
+ # s_negative = gr.Textbox(label="Negative Prompt", value="lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, worst quality, low quality, very displeasing, (bad)")
135
+ # s_steps = gr.Slider(10, 50, value=28, label="Steps", step=1)
136
+ # s_cfg = gr.Slider(1, 12, value=7.0, label="CFG", step=0.1)
137
+ # s_seed = gr.Number(value=1470713301, label="Seed", precision=0)
138
+ # canny_l = gr.Slider(0, 255, value=80, step=1, label="Canny low")
139
+ # canny_h = gr.Slider(0, 255, value=160, step=1, label="Canny high")
140
+ # out_styl = gr.Image(label="Stylized QR")
141
+ # gr.Button("Stylize").click(stylize_qr, [s_prompt, s_negative, s_steps, s_cfg, s_seed, canny_l, canny_h], out_styl)
142
+
143
+ with gr.Tab("QR Stylizer (SDXL dual ControlNet)"):
144
+ p = gr.Textbox(label="Prompt", value="Sky, Moon, Bird, Blue, In the dark, Goddess, Sweet, Beautiful, Fantasy, Art, Anime")
145
+ st = gr.Slider(20, 40, 28, step=1, label="Steps")
146
+ cfg = gr.Slider(4.5, 9.0, 7.0, step=0.1, label="CFG")
147
+ sd = gr.Number(value=1470713301, label="Seed", precision=0)
148
+ cl = gr.Slider(0, 255, 80, step=1, label="Canny low")
149
+ ch = gr.Slider(0, 255, 160, step=1, label="Canny high")
150
+ out = gr.Image(label="Stylized QR (SDXL)")
151
+ gr.Button("Stylize").click(stylize_qr_sdxl, [p, st, cfg, sd, cl, ch], out)
152
+
153
 
154
  if __name__ == "__main__":
155
  demo.launch()