Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -12,9 +12,6 @@ import spaces
|
|
12 |
import numpy as np
|
13 |
import cv2
|
14 |
from pyzxing import BarCodeReader
|
15 |
-
import tempfile
|
16 |
-
from io import BytesIO
|
17 |
-
import base64
|
18 |
|
19 |
from diffusers import (
|
20 |
StableDiffusionPipeline,
|
@@ -36,8 +33,8 @@ qrcode_generator = qrcode.QRCode(
|
|
36 |
)
|
37 |
|
38 |
controlnet = ControlNetModel.from_pretrained(
|
39 |
-
|
40 |
-
"DionTimmer/controlnet_qrcode-control_v1p_sd15",
|
41 |
torch_dtype=torch.float16
|
42 |
).to("cuda")
|
43 |
|
@@ -72,7 +69,7 @@ SAMPLER_MAP = {
|
|
72 |
"DEIS": lambda config: DEISMultistepScheduler.from_config(config),
|
73 |
}
|
74 |
|
75 |
-
def scan_qr_code(image
|
76 |
# Convert gradio image to PIL Image if necessary
|
77 |
if isinstance(image, np.ndarray):
|
78 |
image = Image.fromarray(image)
|
@@ -83,85 +80,34 @@ def scan_qr_code(image, sensitivity=0.5):
|
|
83 |
# Convert to numpy array
|
84 |
np_image = np.array(gray_image)
|
85 |
|
86 |
-
# Preprocess the image
|
87 |
-
_, binary_image = cv2.threshold(np_image, int(255 * sensitivity), 255, cv2.THRESH_BINARY)
|
88 |
-
|
89 |
-
# List to store successful scans
|
90 |
-
successful_scans = []
|
91 |
-
|
92 |
# Method 1: Using qrcode library
|
93 |
try:
|
94 |
qr = qrcode.QRCode()
|
95 |
qr.add_data('')
|
96 |
qr.decode(gray_image)
|
97 |
-
|
98 |
-
except Exception
|
99 |
-
|
100 |
|
101 |
# Method 2: Using OpenCV
|
102 |
try:
|
103 |
qr_detector = cv2.QRCodeDetector()
|
104 |
retval, decoded_info, points, straight_qrcode = qr_detector.detectAndDecodeMulti(np_image)
|
105 |
if retval:
|
106 |
-
|
107 |
-
except Exception
|
108 |
-
|
109 |
|
110 |
-
# Method 3:
|
111 |
try:
|
112 |
reader = BarCodeReader()
|
113 |
results = reader.decode(np_image)
|
114 |
if results:
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
if not results:
|
119 |
-
results = reader.decode(binary_image)
|
120 |
-
if results:
|
121 |
-
successful_scans.extend([("zxing-cpp (binary)", result.parsed) for result in results])
|
122 |
-
except Exception as e:
|
123 |
-
print(f"zxing-cpp failed: {str(e)}")
|
124 |
|
125 |
-
|
126 |
-
if not successful_scans:
|
127 |
-
try:
|
128 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
|
129 |
-
image.save(temp_file.name)
|
130 |
-
reader = BarCodeReader()
|
131 |
-
results = reader.decode(temp_file.name)
|
132 |
-
if results:
|
133 |
-
successful_scans.extend([("zxing-cpp (file)", result.parsed) for result in results])
|
134 |
-
os.unlink(temp_file.name)
|
135 |
-
except Exception as e:
|
136 |
-
print(f"Temporary file scanning failed: {str(e)}")
|
137 |
-
|
138 |
-
return successful_scans
|
139 |
-
|
140 |
-
def generate_qr_code(
|
141 |
-
data,
|
142 |
-
version=None,
|
143 |
-
error_correction=qrcode.constants.ERROR_CORRECT_H,
|
144 |
-
box_size=10,
|
145 |
-
border=4,
|
146 |
-
fill_color="black",
|
147 |
-
back_color="white"
|
148 |
-
):
|
149 |
-
qr = qrcode.QRCode(
|
150 |
-
version=version,
|
151 |
-
error_correction=error_correction,
|
152 |
-
box_size=box_size,
|
153 |
-
border=border,
|
154 |
-
)
|
155 |
-
qr.add_data(data)
|
156 |
-
qr.make(fit=True)
|
157 |
-
|
158 |
-
img = qr.make_image(fill_color=fill_color, back_color=back_color)
|
159 |
-
return img
|
160 |
-
|
161 |
-
def image_to_base64(img):
|
162 |
-
buffered = BytesIO()
|
163 |
-
img.save(buffered, format="PNG")
|
164 |
-
return base64.b64encode(buffered.getvalue()).decode()
|
165 |
|
166 |
@spaces.GPU()
|
167 |
def inference(
|
@@ -176,13 +122,6 @@ def inference(
|
|
176 |
qrcode_image: Image.Image | None = None,
|
177 |
use_qr_code_as_init_image = True,
|
178 |
sampler = "DPM++ Karras SDE",
|
179 |
-
verify_sensitivity: float = 0.5,
|
180 |
-
qr_version: int = 1,
|
181 |
-
qr_error_correction: str = "H",
|
182 |
-
qr_box_size: int = 10,
|
183 |
-
qr_border: int = 4,
|
184 |
-
qr_fill_color: str = "black",
|
185 |
-
qr_back_color: str = "white",
|
186 |
):
|
187 |
try:
|
188 |
if prompt is None or prompt == "":
|
@@ -197,29 +136,21 @@ def inference(
|
|
197 |
|
198 |
if qr_code_content != "" or qrcode_image.size == (1, 1):
|
199 |
print("Generating QR Code from content")
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
}
|
206 |
-
qrcode_image = generate_qr_code(
|
207 |
-
qr_code_content,
|
208 |
-
version=qr_version,
|
209 |
-
error_correction=error_correction_map[qr_error_correction],
|
210 |
-
box_size=qr_box_size,
|
211 |
-
border=qr_border,
|
212 |
-
fill_color=qr_fill_color,
|
213 |
-
back_color=qr_back_color,
|
214 |
)
|
|
|
|
|
|
|
|
|
215 |
qrcode_image = resize_for_condition_image(qrcode_image, 768)
|
216 |
else:
|
217 |
print("Using QR Code Image")
|
218 |
qrcode_image = resize_for_condition_image(qrcode_image, 768)
|
219 |
|
220 |
-
# Generate base64 string of the initial QR code
|
221 |
-
initial_qr_base64 = image_to_base64(qrcode_image)
|
222 |
-
|
223 |
# hack due to gradio examples
|
224 |
init_image = qrcode_image
|
225 |
|
@@ -236,19 +167,15 @@ def inference(
|
|
236 |
strength=float(strength),
|
237 |
num_inference_steps=50,
|
238 |
)
|
239 |
-
|
240 |
-
# Verify the generated QR code
|
241 |
-
verify_result = scan_qr_code(out.images[0], sensitivity=verify_sensitivity)
|
242 |
-
|
243 |
-
return out.images[0], verify_result, initial_qr_base64
|
244 |
except Exception as e:
|
245 |
print(f"Error in inference: {str(e)}")
|
246 |
# Return a blank image in case of an error
|
247 |
-
return Image.new('RGB', (768, 768), color='white')
|
248 |
|
249 |
|
250 |
|
251 |
-
with gr.Blocks(theme=
|
252 |
gr.Markdown(
|
253 |
"""
|
254 |

|
@@ -302,7 +229,7 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
302 |
use_qr_code_as_init_image = gr.Checkbox(
|
303 |
label="Use QR code as init image",
|
304 |
value=True,
|
305 |
-
interactive=
|
306 |
info="Whether init image should be QR code. Unclick to pass init image or generate init image with Stable Diffusion 2.1"
|
307 |
)
|
308 |
with gr.Accordion(label="Init Images (Optional)", open=False, visible=True) as init_image_acc:
|
@@ -315,7 +242,7 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
315 |
minimum=0.0,
|
316 |
maximum=5.0,
|
317 |
step=0.01,
|
318 |
-
value=1.
|
319 |
label="QR Code Visibility",
|
320 |
)
|
321 |
gr.Markdown(
|
@@ -324,9 +251,9 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
324 |
|
325 |
- **Low settings (0.0-0.5)**: If you choose a lower value, the QR code will blend more into the art, and it might be hard to scan with a phone. This setting is great if you want the image to look amazing, but you might lose some of the scannability. Try this if you care more about art and less about the QR code being easily recognized.
|
326 |
|
327 |
-
- **Medium settings (0.6-
|
328 |
|
329 |
-
- **High settings (
|
330 |
|
331 |
Start with **1.3** if you're unsure, and adjust up or down depending on whether you want the QR code to be more artistic or more functional.
|
332 |
"""
|
@@ -355,7 +282,7 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
355 |
minimum=0.0,
|
356 |
maximum=50.0,
|
357 |
step=0.25,
|
358 |
-
value=
|
359 |
label="Follow the Prompt",
|
360 |
)
|
361 |
gr.Markdown(
|
@@ -410,28 +337,11 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
410 |
Try **-1** if you want to explore and generate different designs. If you find something you really love, write down the seed number and use it again to recreate the same design.
|
411 |
"""
|
412 |
)
|
413 |
-
|
414 |
-
verify_sensitivity = gr.Slider(
|
415 |
-
minimum=0.1,
|
416 |
-
maximum=1.0,
|
417 |
-
step=0.05,
|
418 |
-
value=0.5,
|
419 |
-
label="Verify Sensitivity",
|
420 |
-
)
|
421 |
-
gr.Markdown(
|
422 |
-
"""
|
423 |
-
**Verify Sensitivity** controls how sensitive the QR code scanner is when verifying the generated image.
|
424 |
-
A lower value (closer to 0.1) makes the scanner more sensitive and able to detect less clear QR codes,
|
425 |
-
while a higher value (closer to 1.0) requires clearer, more distinct QR codes to be detected.
|
426 |
-
"""
|
427 |
-
)
|
428 |
with gr.Row():
|
429 |
run_btn = gr.Button("🎨 Create Your QR Art", variant="primary")
|
430 |
|
431 |
with gr.Column():
|
432 |
result_image = gr.Image(label="Your Artistic QR Code")
|
433 |
-
initial_qr_image = gr.Image(label="Initial QR Code", visible=False)
|
434 |
-
download_initial_qr = gr.Button("Download Initial QR Code")
|
435 |
scan_button = gr.Button("Scan QR Code")
|
436 |
scan_result = gr.Textbox(label="Scan Result", interactive=False)
|
437 |
|
@@ -452,14 +362,11 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
452 |
if image is None:
|
453 |
return "No image to scan"
|
454 |
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
return "Failed to scan QR code. The image might be too artistic or the QR code might not be clear enough. Try adjusting the 'QR Code Visibility' setting for better results."
|
461 |
-
except Exception as e:
|
462 |
-
return f"An error occurred while scanning: {str(e)}"
|
463 |
|
464 |
scan_button.click(
|
465 |
scan_and_display,
|
@@ -467,9 +374,7 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
467 |
outputs=[scan_result]
|
468 |
)
|
469 |
|
470 |
-
|
471 |
-
return gr.Image.update(value=base64_string, visible=True)
|
472 |
-
|
473 |
run_btn.click(
|
474 |
inference,
|
475 |
inputs=[
|
@@ -484,13 +389,10 @@ with gr.Blocks(theme=gr.themes.Monochrome()) as blocks:
|
|
484 |
qr_code_image,
|
485 |
use_qr_code_as_init_image,
|
486 |
sampler,
|
487 |
-
verify_sensitivity,
|
488 |
],
|
489 |
-
outputs=[result_image
|
490 |
concurrency_limit=20
|
491 |
)
|
492 |
|
493 |
-
download_initial_qr.click(lambda x: x, inputs=[initial_qr_image], outputs=[initial_qr_image])
|
494 |
-
|
495 |
blocks.queue(max_size=20,api_open=False)
|
496 |
blocks.launch(share=bool(os.environ.get("SHARE", False)), show_api=True)
|
|
|
12 |
import numpy as np
|
13 |
import cv2
|
14 |
from pyzxing import BarCodeReader
|
|
|
|
|
|
|
15 |
|
16 |
from diffusers import (
|
17 |
StableDiffusionPipeline,
|
|
|
33 |
)
|
34 |
|
35 |
controlnet = ControlNetModel.from_pretrained(
|
36 |
+
"monster-labs/control_v1p_sd15_qrcode_monster",
|
37 |
+
#"DionTimmer/controlnet_qrcode-control_v1p_sd15",
|
38 |
torch_dtype=torch.float16
|
39 |
).to("cuda")
|
40 |
|
|
|
69 |
"DEIS": lambda config: DEISMultistepScheduler.from_config(config),
|
70 |
}
|
71 |
|
72 |
+
def scan_qr_code(image):
|
73 |
# Convert gradio image to PIL Image if necessary
|
74 |
if isinstance(image, np.ndarray):
|
75 |
image = Image.fromarray(image)
|
|
|
80 |
# Convert to numpy array
|
81 |
np_image = np.array(gray_image)
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
# Method 1: Using qrcode library
|
84 |
try:
|
85 |
qr = qrcode.QRCode()
|
86 |
qr.add_data('')
|
87 |
qr.decode(gray_image)
|
88 |
+
return qr.data.decode('utf-8')
|
89 |
+
except Exception:
|
90 |
+
pass
|
91 |
|
92 |
# Method 2: Using OpenCV
|
93 |
try:
|
94 |
qr_detector = cv2.QRCodeDetector()
|
95 |
retval, decoded_info, points, straight_qrcode = qr_detector.detectAndDecodeMulti(np_image)
|
96 |
if retval:
|
97 |
+
return decoded_info[0]
|
98 |
+
except Exception:
|
99 |
+
pass
|
100 |
|
101 |
+
# Method 3: Fallback to zxing-cpp
|
102 |
try:
|
103 |
reader = BarCodeReader()
|
104 |
results = reader.decode(np_image)
|
105 |
if results:
|
106 |
+
return results[0].parsed
|
107 |
+
except Exception:
|
108 |
+
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
|
110 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
|
112 |
@spaces.GPU()
|
113 |
def inference(
|
|
|
122 |
qrcode_image: Image.Image | None = None,
|
123 |
use_qr_code_as_init_image = True,
|
124 |
sampler = "DPM++ Karras SDE",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
):
|
126 |
try:
|
127 |
if prompt is None or prompt == "":
|
|
|
136 |
|
137 |
if qr_code_content != "" or qrcode_image.size == (1, 1):
|
138 |
print("Generating QR Code from content")
|
139 |
+
qr = qrcode.QRCode(
|
140 |
+
version=1,
|
141 |
+
error_correction=qrcode.constants.ERROR_CORRECT_H,
|
142 |
+
box_size=10,
|
143 |
+
border=4,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
)
|
145 |
+
qr.add_data(qr_code_content)
|
146 |
+
qr.make(fit=True)
|
147 |
+
|
148 |
+
qrcode_image = qr.make_image(fill_color="black", back_color="white")
|
149 |
qrcode_image = resize_for_condition_image(qrcode_image, 768)
|
150 |
else:
|
151 |
print("Using QR Code Image")
|
152 |
qrcode_image = resize_for_condition_image(qrcode_image, 768)
|
153 |
|
|
|
|
|
|
|
154 |
# hack due to gradio examples
|
155 |
init_image = qrcode_image
|
156 |
|
|
|
167 |
strength=float(strength),
|
168 |
num_inference_steps=50,
|
169 |
)
|
170 |
+
return out.images[0] # type: ignore
|
|
|
|
|
|
|
|
|
171 |
except Exception as e:
|
172 |
print(f"Error in inference: {str(e)}")
|
173 |
# Return a blank image in case of an error
|
174 |
+
return Image.new('RGB', (768, 768), color='white')
|
175 |
|
176 |
|
177 |
|
178 |
+
with gr.Blocks(theme='Hev832/Applio') as blocks:
|
179 |
gr.Markdown(
|
180 |
"""
|
181 |

|
|
|
229 |
use_qr_code_as_init_image = gr.Checkbox(
|
230 |
label="Use QR code as init image",
|
231 |
value=True,
|
232 |
+
interactive=False,
|
233 |
info="Whether init image should be QR code. Unclick to pass init image or generate init image with Stable Diffusion 2.1"
|
234 |
)
|
235 |
with gr.Accordion(label="Init Images (Optional)", open=False, visible=True) as init_image_acc:
|
|
|
242 |
minimum=0.0,
|
243 |
maximum=5.0,
|
244 |
step=0.01,
|
245 |
+
value=1.3,
|
246 |
label="QR Code Visibility",
|
247 |
)
|
248 |
gr.Markdown(
|
|
|
251 |
|
252 |
- **Low settings (0.0-0.5)**: If you choose a lower value, the QR code will blend more into the art, and it might be hard to scan with a phone. This setting is great if you want the image to look amazing, but you might lose some of the scannability. Try this if you care more about art and less about the QR code being easily recognized.
|
253 |
|
254 |
+
- **Medium settings (0.6-1.5)**: This is the sweet spot where the QR code remains clearly visible while still blending in with the art. You can still scan it easily with a phone, but it looks more creative. For most users, setting it around **1.1** is a great start to balance both art and function.
|
255 |
|
256 |
+
- **High settings (1.6-5.0)**: If you need to make sure that the QR code is super easy to scan, even if it means the image looks less like art and more like a regular QR code, then choose a higher value. This is ideal when functionality is the main goal, and the artistic side can take a backseat.
|
257 |
|
258 |
Start with **1.3** if you're unsure, and adjust up or down depending on whether you want the QR code to be more artistic or more functional.
|
259 |
"""
|
|
|
282 |
minimum=0.0,
|
283 |
maximum=50.0,
|
284 |
step=0.25,
|
285 |
+
value=7.5,
|
286 |
label="Follow the Prompt",
|
287 |
)
|
288 |
gr.Markdown(
|
|
|
337 |
Try **-1** if you want to explore and generate different designs. If you find something you really love, write down the seed number and use it again to recreate the same design.
|
338 |
"""
|
339 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
with gr.Row():
|
341 |
run_btn = gr.Button("🎨 Create Your QR Art", variant="primary")
|
342 |
|
343 |
with gr.Column():
|
344 |
result_image = gr.Image(label="Your Artistic QR Code")
|
|
|
|
|
345 |
scan_button = gr.Button("Scan QR Code")
|
346 |
scan_result = gr.Textbox(label="Scan Result", interactive=False)
|
347 |
|
|
|
362 |
if image is None:
|
363 |
return "No image to scan"
|
364 |
|
365 |
+
scanned_text = scan_qr_code(image)
|
366 |
+
if scanned_text:
|
367 |
+
return f"Scanned successfully: {scanned_text}"
|
368 |
+
else:
|
369 |
+
return "Failed to scan QR code. Try adjusting the settings for better visibility."
|
|
|
|
|
|
|
370 |
|
371 |
scan_button.click(
|
372 |
scan_and_display,
|
|
|
374 |
outputs=[scan_result]
|
375 |
)
|
376 |
|
377 |
+
|
|
|
|
|
378 |
run_btn.click(
|
379 |
inference,
|
380 |
inputs=[
|
|
|
389 |
qr_code_image,
|
390 |
use_qr_code_as_init_image,
|
391 |
sampler,
|
|
|
392 |
],
|
393 |
+
outputs=[result_image],
|
394 |
concurrency_limit=20
|
395 |
)
|
396 |
|
|
|
|
|
397 |
blocks.queue(max_size=20,api_open=False)
|
398 |
blocks.launch(share=bool(os.environ.get("SHARE", False)), show_api=True)
|