achiru commited on
Commit
ddce00f
·
1 Parent(s): 3960c16
Files changed (3) hide show
  1. app.py +261 -0
  2. generate_code.py +103 -0
  3. requirements.txt +9 -0
app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import gradio as gr
3
+ from multiprocessing import cpu_count
4
+ import os
5
+ from generate_code import create_code, backgrounds, correction_map
6
+
7
+ from diffusers import (
8
+ StableDiffusionControlNetPipeline,
9
+ ControlNetModel,
10
+ EulerAncestralDiscreteScheduler,
11
+ )
12
+
13
+ main_generator = torch.Generator()
14
+
15
+ # MONSTER_V2 = "/home/ubuntu/training/diffusers/examples/controlnet/out_model_2023-06-18_17-27-06"
16
+ # LANDMARKS = "/home/ubuntu/training/diffusers/examples/controlnet/out_model_2023-06-19_23-43-50/"
17
+ MONSTER_V2 = "monster-labs/V2"
18
+ LANDMARKS = "monster-labs/V2"
19
+
20
+ controlnet = [
21
+ ControlNetModel.from_pretrained(MONSTER_V2, torch_dtype=torch.float16, subfolder="step1"),
22
+ ControlNetModel.from_pretrained(LANDMARKS, torch_dtype=torch.float16, subfolder="step2"),
23
+ ]
24
+
25
+ pipe = StableDiffusionControlNetPipeline.from_pretrained(
26
+ "runwayml/stable-diffusion-v1-5",
27
+ controlnet=controlnet,
28
+ safety_checker=None,
29
+ torch_dtype=torch.float16,
30
+ ).to("cuda")
31
+ pipe.enable_xformers_memory_efficient_attention()
32
+ pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
33
+
34
+ def inference_map(
35
+ qr_code_content: str,
36
+ prompt: str,
37
+ negative_prompt: str,
38
+ guidance_scale: float,
39
+ controlnet_conditioning_scale_0: float,
40
+ seed: int,
41
+ controlnet_start_0: float,
42
+ controlnet_start_1: float,
43
+ controlnet_end_0: float,
44
+ controlnet_end_1: float,
45
+ background: str,
46
+ error_correction: str,
47
+ margin: int,
48
+ module_size: int,
49
+ width: int,
50
+ height: int,
51
+ ):
52
+ return inference(
53
+ qr_code_content,
54
+ prompt,
55
+ negative_prompt,
56
+ guidance_scale,
57
+ (controlnet_conditioning_scale_0, 1),
58
+ seed,
59
+ (controlnet_start_0, controlnet_start_1),
60
+ (controlnet_end_0, controlnet_end_1),
61
+ background,
62
+ error_correction,
63
+ margin,
64
+ module_size,
65
+ width,
66
+ height,
67
+ )
68
+
69
+ def inference(
70
+ qr_code_content: str,
71
+ prompt: str,
72
+ negative_prompt: str,
73
+ guidance_scale: float = 10.0,
74
+ controlnet_conditioning_scale: tuple[float, float] = (1.0, 1.0),
75
+ seed: int = -1,
76
+ controlnet_start: tuple[float, float] = (0.2, 0.0),
77
+ controlnet_end: tuple[float, float] = (0.95, 1.0),
78
+ background: str = "gray",
79
+ error_correction: str = "H",
80
+ margin: int = 1,
81
+ module_size: int = 16,
82
+ width: int = None,
83
+ height: int = None,
84
+ ):
85
+ if prompt is None or prompt == "":
86
+ raise gr.Error("Prompt is required")
87
+
88
+ if qr_code_content is None or qr_code_content == "":
89
+ raise gr.Error("QR Code Content is required")
90
+
91
+ if background not in backgrounds:
92
+ raise gr.Error("Invalid background")
93
+
94
+ if error_correction not in correction_map:
95
+ raise gr.Error("Invalid error correction")
96
+
97
+
98
+ generator = torch.manual_seed(seed) if seed != -1 else main_generator
99
+
100
+ # print("Generating QR Code from content")
101
+ qrcode_images = create_code(qr_code_content, module_size, margin, background, error_correction, False, 1, True)
102
+
103
+ out = pipe(
104
+ prompt=prompt,
105
+ negative_prompt=negative_prompt,
106
+ image=list(qrcode_images),
107
+ width=qrcode_images[0].width,
108
+ height=qrcode_images[0].height,
109
+ guidance_scale=float(guidance_scale),
110
+ controlnet_conditioning_scale=controlnet_conditioning_scale,
111
+ # controlnet_start=controlnet_start,
112
+ # controlnet_end=controlnet_end,
113
+ controlnet_guidance=[(controlnet_start[0], controlnet_end[0]), (controlnet_start[1], controlnet_end[1])],
114
+ generator=generator,
115
+ num_inference_steps=40,
116
+ )
117
+ return out.images[0]
118
+
119
+ with gr.Blocks() as blocks:
120
+ with gr.Row():
121
+ with gr.Column():
122
+ qr_code_content = gr.Textbox(
123
+ label="QR Code Content",
124
+ info="QR Code Content or URL",
125
+ value="",
126
+ )
127
+
128
+ prompt = gr.Textbox(
129
+ label="Prompt",
130
+ info="Prompt that guides the generation towards",
131
+ )
132
+ negative_prompt = gr.Textbox(
133
+ label="Negative Prompt",
134
+ value="ugly, disfigured, low quality, blurry, nsfw",
135
+ )
136
+
137
+ with gr.Accordion(
138
+ label="Params: The generated QR Code functionality is largely influenced by the parameters detailed below",
139
+ open=True,
140
+ ):
141
+ controlnet_conditioning_scale = gr.Slider(
142
+ minimum=0.5,
143
+ maximum=2.5,
144
+ step=0.01,
145
+ value=1.5,
146
+ label="Controlnet Conditioning Scale",
147
+ )
148
+ guidance_scale = gr.Slider(
149
+ minimum=0.0,
150
+ maximum=25.0,
151
+ step=0.25,
152
+ value=7,
153
+ label="Guidance Scale",
154
+ )
155
+ seed = gr.Number(
156
+ minimum=-1,
157
+ maximum=9999999999,
158
+ step=1,
159
+ value=2313123,
160
+ label="Seed",
161
+ randomize=True,
162
+ )
163
+ controlnet_start_0 = gr.Slider(
164
+ minimum=0.0,
165
+ maximum=1.0,
166
+ step=0.01,
167
+ value=0.2,
168
+ label="Controlnet Start 0",
169
+ )
170
+ controlnet_start_1 = gr.Slider(
171
+ minimum=0.0,
172
+ maximum=1.0,
173
+ step=0.01,
174
+ value=0.0,
175
+ label="Controlnet Start 1",
176
+ )
177
+ controlnet_end_0 = gr.Slider(
178
+ minimum=0.0,
179
+ maximum=1.0,
180
+ step=0.01,
181
+ value=0.95,
182
+ label="Controlnet End 0",
183
+ )
184
+ controlnet_end_1 = gr.Slider(
185
+ minimum=0.0,
186
+ maximum=1.0,
187
+ step=0.01,
188
+ value=1.0,
189
+ label="Controlnet End 1",
190
+ )
191
+ background = gr.Dropdown(
192
+ label="Background",
193
+ choices=backgrounds,
194
+ value="gray",
195
+ )
196
+ error_correction = gr.Dropdown(
197
+ label="Error Correction",
198
+ choices=correction_map.keys(),
199
+ value="H",
200
+ )
201
+ margin = gr.Slider(
202
+ minimum=0,
203
+ maximum=10,
204
+ step=1,
205
+ value=1,
206
+ label="Margin",
207
+ )
208
+ module_size = gr.Slider(
209
+ minimum=1,
210
+ maximum=100,
211
+ step=1,
212
+ value=16,
213
+ label="Module Size",
214
+ )
215
+ width = gr.Slider(
216
+ minimum=512,
217
+ maximum=1024,
218
+ step=256,
219
+ value=512,
220
+ label="Width",
221
+ )
222
+ height = gr.Slider(
223
+ minimum=512,
224
+ maximum=1024,
225
+ step=256,
226
+ value=512,
227
+ label="Height",
228
+ )
229
+ with gr.Row():
230
+ run_btn = gr.Button("Run")
231
+ with gr.Column():
232
+ result_image = gr.Image(label="Result Image", elem_id="result_image")
233
+ run_btn.click(
234
+ inference_map,
235
+ inputs=[
236
+ qr_code_content,
237
+ prompt,
238
+ negative_prompt,
239
+ guidance_scale,
240
+ controlnet_conditioning_scale,
241
+ seed,
242
+ controlnet_start_0,
243
+ controlnet_start_1,
244
+ controlnet_end_0,
245
+ controlnet_end_1,
246
+ background,
247
+ error_correction,
248
+ margin,
249
+ module_size,
250
+ width,
251
+ height,
252
+ ],
253
+ outputs=[result_image],
254
+ )
255
+
256
+ # login = os.environ.get("LOGIN", "admin")
257
+ # password = os.environ.get("PASSWORD", "1234")
258
+
259
+ blocks.queue(concurrency_count=1, max_size=40)
260
+ blocks.launch(share=False)
261
+ # blocks.launch(share=False, auth=(login, password))
generate_code.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import qrcode
2
+ import numpy as np
3
+ from PIL import Image
4
+ import base64
5
+
6
+ correction_map = {
7
+ 'L': qrcode.constants.ERROR_CORRECT_L,
8
+ 'M': qrcode.constants.ERROR_CORRECT_M,
9
+ 'Q': qrcode.constants.ERROR_CORRECT_Q,
10
+ 'H': qrcode.constants.ERROR_CORRECT_H,
11
+ }
12
+
13
+ backgrounds = ['white', 'black', 'gray', 'noise']
14
+
15
+ bg_map = {
16
+ 'white': 255,
17
+ 'black': 0,
18
+ 'gray': 128,
19
+ }
20
+
21
+ def create_code(text, module_size, margin, background, error_correction, centered, submodule_prop, split=False):
22
+ qr = qrcode.QRCode(
23
+ version=1,
24
+ error_correction=correction_map[error_correction],
25
+ box_size=module_size,
26
+ border=margin if margin > 0 else 1,
27
+ )
28
+ qr.add_data(text)
29
+ qr.make(fit=True)
30
+
31
+ img = qr.make_image(fill_color="black", back_color="white")
32
+
33
+ # find smallest image size multiple of 256 that can fit qr
34
+ offset_min = 8 * module_size
35
+ w, h = img.size
36
+
37
+ mask = None
38
+
39
+ if margin == 0:
40
+ corner_size = 9 * module_size
41
+ # make a mask that hides the margin when not in the corners
42
+ mask = np.ones((h, w)).astype(bool)
43
+ mask[corner_size:-corner_size, :] = False
44
+ mask[:, corner_size:-corner_size] = False
45
+ mask[-corner_size:, -corner_size:] = False
46
+ mask[module_size:-module_size, module_size:-module_size] = True
47
+
48
+ if submodule_prop != 1:
49
+ submodule_size = round(module_size * submodule_prop)
50
+ k = (module_size - submodule_size) // 2
51
+ # qr_array = np.array(img).reshape((h // module_size, w // module_size, module_size, module_size))
52
+ new_mask = np.zeros((h // module_size, module_size, w // module_size, module_size)).astype(bool)
53
+ new_mask[:, k:k+submodule_size, :, k:k+submodule_size] = True
54
+ mask = np.logical_and(mask, new_mask.reshape((h, w)))
55
+
56
+ w = (w + 255 + offset_min) // 256 * 256
57
+ h = (h + 255 + offset_min) // 256 * 256
58
+
59
+ # create new image with background chosen by user
60
+ if background == 'noise':
61
+ # noise = np.random.randint(0, 256, (h // module_size, w // module_size), dtype=np.uint8)
62
+ noise = np.random.normal(128, 64, (h // module_size, w // module_size)).astype(np.uint8)
63
+ # noise = (noise // 128) * 255
64
+ noise = np.round(noise / 128) * 128
65
+ # clamp values
66
+ noise = np.clip(noise, 0, 255)
67
+
68
+ bg = Image.fromarray(noise.astype(np.uint8)).resize((w, h), Image.NEAREST)
69
+ else:
70
+ bg = Image.new('L', (w, h), bg_map[background])
71
+
72
+ # paste qr code in the center of the image
73
+ if centered:
74
+ coords = ((w - img.size[0]) // 2, (h - img.size[1]) // 2)
75
+ else:
76
+ # paste it aligned on module size, closest to center
77
+ coords = ((w - img.size[0]) // 2 // module_size * module_size, (h - img.size[1]) // 2 // module_size * module_size)
78
+
79
+ if mask is not None:
80
+ new_img = Image.new('L', img.size, bg_map['gray'] if background == 'noise' else bg_map[background])
81
+ new_img.paste(img, mask=Image.fromarray(mask))
82
+ bg.paste(new_img, coords)
83
+ else:
84
+ bg.paste(img, coords)
85
+
86
+ if split:
87
+ # isolate the 3 qr markers, paste them onto a new gray image
88
+ m_size = module_size * 9
89
+
90
+ new_bg = Image.new('L', (w, h), bg_map['gray'])
91
+
92
+ # create mask for the 3 markers from a numpy array
93
+ mask = np.zeros((h, w), dtype=bool)
94
+ mask[coords[1]:coords[1] + m_size, coords[0]:coords[0] + m_size] = True
95
+ mask[coords[1]:coords[1] + m_size, coords[0] + img.size[0] - m_size:coords[0] + img.size[0]] = True
96
+ mask[coords[1] + img.size[1] - m_size:coords[1] + img.size[1], coords[0]:coords[0] + m_size] = True
97
+
98
+ # paste the 3 markers on the new image
99
+ new_bg.paste(bg, mask=Image.fromarray(mask))
100
+
101
+ return bg, new_bg
102
+ else:
103
+ return bg,
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ diffusers
2
+ transformers
3
+ accelerate
4
+ torch
5
+ xformers
6
+ gradio
7
+ Pillow
8
+ qrcode
9
+ numpy