Oysiyl commited on
Commit
6587064
·
1 Parent(s): 5b5b5fe

added a new border plus default values for freeU

Browse files
Files changed (1) hide show
  1. app.py +64 -28
app.py CHANGED
@@ -195,20 +195,26 @@ def generate_qr_code_unified(prompt: str, text_input: str, input_type: str = "UR
195
  else: # artistic
196
  yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed)
197
 
198
- def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, noise_strength: float = 0.5):
199
  """
200
- Add random dark noise ONLY to the border region of a QR code image.
 
 
201
 
202
  Args:
203
  image_tensor: ComfyUI image tensor (batch, height, width, channels) with values 0-1
204
  seed: Random seed for reproducible noise
205
  border_size: Border size in QR modules (from QR generation settings)
206
  image_size: Image size in pixels
207
- noise_strength: Strength of noise to add (0-1 range, 0.5 = medium dark noise)
208
 
209
  Returns:
210
- Modified tensor with dark noise added only to border region
211
  """
 
 
 
 
212
  # Convert to numpy for manipulation
213
  img_np = image_tensor.cpu().numpy()
214
 
@@ -219,10 +225,8 @@ def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_si
219
  img = img_np[0] # (height, width, channels)
220
  height, width, channels = img.shape
221
 
222
- # Calculate border region in pixels
223
- # Rough estimation: border_size modules out of total image
224
- # We'll use a simple approach: outer X% of the image
225
- border_thickness = max(int(height * 0.08), 20) # At least 20 pixels or 8% of image
226
 
227
  # Create border mask (1 for border region, 0 for QR code interior)
228
  border_mask = np.zeros((height, width), dtype=bool)
@@ -243,13 +247,34 @@ def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_si
243
  # Combine: only border AND white areas
244
  final_mask = border_mask & white_mask
245
 
246
- # Generate random dark noise - only grayscale (same value for all channels)
247
- noise_amount = np.random.uniform(0, noise_strength, size=(height, width))
248
-
249
- # Apply noise to all channels equally (creates grayscale noise - dark pixels)
250
- for c in range(channels):
251
- # Subtract noise to make it darker (0.5 means subtract up to 0.5 from white = dark gray to black)
252
- img[:, :, c] = np.where(final_mask, np.maximum(img[:, :, c] - noise_amount, 0), img[:, :, c])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
  # Put modified image back into batch array
255
  img_np[0] = img
@@ -440,22 +465,23 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
440
 
441
  # Only add noise if there's a border (border_size > 0)
442
  if border_size > 0:
443
- yield base_qr_pil, "Generated base QR pattern... adding border noise (step 1/5)"
444
 
445
- # Add dark noise ONLY to border region (not QR code interior)
 
446
  qr_with_border_noise = add_noise_to_border_only(
447
  get_value_at_index(comfy_qr, 0),
448
  seed=seed + 100,
449
  border_size=border_size,
450
  image_size=image_size,
451
- noise_strength=0.5 # Dark gray to black pixels
452
  )
453
 
454
- # Show the noisy QR so you can see the border noise effect
455
  noisy_qr_np = (qr_with_border_noise.cpu().numpy() * 255).astype(np.uint8)
456
  noisy_qr_np = noisy_qr_np[0]
457
  noisy_qr_pil = Image.fromarray(noisy_qr_np)
458
- yield noisy_qr_pil, "Added dark noise to border only... enhancing with AI (step 2/5)"
459
  else:
460
  # No border, skip noise
461
  qr_with_border_noise = get_value_at_index(comfy_qr, 0)
@@ -486,7 +512,7 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
486
  control_net_name="control_v11f1e_sd15_tile_fp16.safetensors"
487
  )
488
 
489
- # First ControlNet pass (using noisy QR)
490
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
491
  strength=0.45,
492
  start_percent=0,
@@ -498,14 +524,14 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
498
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
499
  )
500
 
501
- # Tile preprocessor (using noisy QR)
502
  tile_processed = tilepreprocessor.execute(
503
  pyrUp_iters=3,
504
  resolution=image_size,
505
  image=qr_with_border_noise,
506
  )
507
 
508
- # Second ControlNet pass (using tile processed from noisy QR)
509
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
510
  strength=0.45,
511
  start_percent=0,
@@ -521,14 +547,24 @@ def _pipeline_artistic(prompt: str, qr_text: str, input_type: str, image_size: i
521
  base_model = get_value_at_index(checkpointloadersimple_artistic, 0)
522
 
523
  freeu = FreeU_V2()
524
- enhanced_model = freeu.patch(
525
  model=base_model,
526
- b1=1.3, # Backbone feature enhancement - improves fine details
527
- b2=1.4, # Backbone feature enhancement (layer 2) - improves textures
528
- s1=0.9, # Skip connection dampening - reduces artifacts
529
- s2=0.2 # Skip connection dampening (layer 2) - cleaner output
530
  )[0]
531
 
 
 
 
 
 
 
 
 
 
 
532
  # First sampling pass
533
  samples = ksampler.sample(
534
  seed=seed,
 
195
  else: # artistic
196
  yield from _pipeline_artistic(prompt, qr_text, input_type, image_size, border_size, error_correction, module_size, module_drawer, actual_seed)
197
 
198
+ def add_noise_to_border_only(image_tensor, seed: int, border_size: int, image_size: int, module_size: int = 12):
199
  """
200
+ Add QR-like cubic patterns ONLY to the border region of a QR code image.
201
+ Creates black squares that resemble QR modules for a smooth transition.
202
+ The density of border cubics automatically matches the QR code interior density.
203
 
204
  Args:
205
  image_tensor: ComfyUI image tensor (batch, height, width, channels) with values 0-1
206
  seed: Random seed for reproducible noise
207
  border_size: Border size in QR modules (from QR generation settings)
208
  image_size: Image size in pixels
209
+ module_size: Size of QR modules in pixels (for cubic pattern)
210
 
211
  Returns:
212
+ Modified tensor with QR-like cubic patterns in border region
213
  """
214
+ # Early return if no border
215
+ if border_size == 0:
216
+ return image_tensor
217
+
218
  # Convert to numpy for manipulation
219
  img_np = image_tensor.cpu().numpy()
220
 
 
225
  img = img_np[0] # (height, width, channels)
226
  height, width, channels = img.shape
227
 
228
+ # Calculate border region in pixels using exact QR parameters
229
+ border_thickness = border_size * module_size # Exact border size in pixels
 
 
230
 
231
  # Create border mask (1 for border region, 0 for QR code interior)
232
  border_mask = np.zeros((height, width), dtype=bool)
 
247
  # Combine: only border AND white areas
248
  final_mask = border_mask & white_mask
249
 
250
+ # Calculate QR code interior density to determine border cubic density
251
+ interior_mask = ~border_mask # Inverse of border = QR interior
252
+ interior_pixels = img_255[interior_mask][:, 0] # Get first channel (grayscale)
253
+ black_count = (interior_pixels < 128).sum() # Count black pixels (< 128)
254
+ total_count = len(interior_pixels)
255
+ qr_density = float(black_count) / float(total_count) if total_count > 0 else 0.5
256
+
257
+ # Use QR interior density as probability for placing border cubics
258
+ # This creates a natural transition matching the QR pattern density
259
+
260
+ # Generate QR-like cubic pattern noise
261
+ # Create a grid based on module_size
262
+ for y in range(0, height, module_size):
263
+ for x in range(0, width, module_size):
264
+ # Check if this module position is mostly in the border area
265
+ y_end = min(y + module_size, height)
266
+ x_end = min(x + module_size, width)
267
+
268
+ # Count how many pixels in this module are in the final_mask
269
+ module_region = final_mask[y:y_end, x:x_end]
270
+
271
+ # If at least 50% of the module is in the border, we can place a cubic here
272
+ if module_region.sum() > (module_size * module_size * 0.5):
273
+ # Randomly decide to place a black cubic based on QR interior density
274
+ if np.random.random() < qr_density:
275
+ # Place a black square (cubic) - set all channels to 0 (black)
276
+ for c in range(channels):
277
+ img[y:y_end, x:x_end, c] = 0
278
 
279
  # Put modified image back into batch array
280
  img_np[0] = img
 
465
 
466
  # Only add noise if there's a border (border_size > 0)
467
  if border_size > 0:
468
+ yield base_qr_pil, "Generated base QR pattern... adding QR-like cubics to border (step 1/5)"
469
 
470
+ # Add QR-like cubic patterns ONLY to border region (extends QR structure into border)
471
+ # Density automatically matches QR code interior density for natural transition
472
  qr_with_border_noise = add_noise_to_border_only(
473
  get_value_at_index(comfy_qr, 0),
474
  seed=seed + 100,
475
  border_size=border_size,
476
  image_size=image_size,
477
+ module_size=module_size, # Use same module size as QR code
478
  )
479
 
480
+ # Show the noisy QR so you can see the border cubic pattern effect
481
  noisy_qr_np = (qr_with_border_noise.cpu().numpy() * 255).astype(np.uint8)
482
  noisy_qr_np = noisy_qr_np[0]
483
  noisy_qr_pil = Image.fromarray(noisy_qr_np)
484
+ yield noisy_qr_pil, "Added QR-like cubics to border... enhancing with AI (step 2/5)"
485
  else:
486
  # No border, skip noise
487
  qr_with_border_noise = get_value_at_index(comfy_qr, 0)
 
512
  control_net_name="control_v11f1e_sd15_tile_fp16.safetensors"
513
  )
514
 
515
+ # First ControlNet pass (using QR with border cubics)
516
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
517
  strength=0.45,
518
  start_percent=0,
 
524
  vae=get_value_at_index(checkpointloadersimple_artistic, 2),
525
  )
526
 
527
+ # Tile preprocessor (using QR with border cubics)
528
  tile_processed = tilepreprocessor.execute(
529
  pyrUp_iters=3,
530
  resolution=image_size,
531
  image=qr_with_border_noise,
532
  )
533
 
534
+ # Second ControlNet pass (using tile processed from QR with border cubics)
535
  controlnet_apply = controlnetapplyadvanced.apply_controlnet(
536
  strength=0.45,
537
  start_percent=0,
 
547
  base_model = get_value_at_index(checkpointloadersimple_artistic, 0)
548
 
549
  freeu = FreeU_V2()
550
+ freeu_model = freeu.patch(
551
  model=base_model,
552
+ b1=1.3, # Backbone feature enhancement - improves fine details (reduced for more blending)
553
+ b2=1.4, # Backbone feature enhancement (layer 2) - improves textures (reduced)
554
+ s1=0.9, # Skip connection dampening - reduces QR structure visibility (increased)
555
+ s2=0.2 # Skip connection dampening (layer 2) - hides more cubics (increased)
556
  )[0]
557
 
558
+ # Apply SEG (Self-Attention Guidance) for improved structural coherence
559
+ # DISABLED: SEG blurs attention maps which rounds position marker corners, affecting scannability
560
+ # smoothed_energy = NODE_CLASS_MAPPINGS["SelfAttentionGuidance"]()
561
+ # enhanced_model = smoothed_energy.patch(
562
+ # model=freeu_model,
563
+ # scale=1.5,
564
+ # blur_sigma=0.5,
565
+ # )[0]
566
+ enhanced_model = freeu_model # Use only FreeU, skip SEG
567
+
568
  # First sampling pass
569
  samples = ksampler.sample(
570
  seed=seed,