Update Salia_Croppytools.py
Browse files- Salia_Croppytools.py +45 -36
Salia_Croppytools.py
CHANGED
|
@@ -441,7 +441,7 @@ class apply_segment:
|
|
| 441 |
"required": {
|
| 442 |
"mask": ("MASK",),
|
| 443 |
"image": (choices, {}), # dropdown asset (used ONLY for loaded mask)
|
| 444 |
-
"img": ("IMAGE",), # the image to receive
|
| 445 |
"canvas": ("IMAGE",), # destination
|
| 446 |
"x": ("INT", {"default": 0, "min": -100000, "max": 100000, "step": 1}),
|
| 447 |
"y": ("INT", {"default": 0, "min": -100000, "max": 100000, "step": 1}),
|
|
@@ -458,53 +458,63 @@ class apply_segment:
|
|
| 458 |
|
| 459 |
combiner = _AILab_MaskCombiner_Exact()
|
| 460 |
|
| 461 |
-
#
|
| 462 |
-
|
|
|
|
|
|
|
|
|
|
| 463 |
|
| 464 |
-
#
|
| 465 |
-
|
| 466 |
-
final_mask, = combiner.combine_masks(inv_mask, mode="combine", mask_2=loaded_mask)
|
| 467 |
|
| 468 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
img = _as_image(img)
|
| 470 |
B, H, W, C = img.shape
|
| 471 |
|
| 472 |
-
# Resize
|
| 473 |
-
|
| 474 |
-
final_mask_resized = combiner._resize_if_needed(final_mask, (final_mask.shape[0], H, W))
|
| 475 |
|
| 476 |
-
# Batch match (
|
| 477 |
-
if
|
| 478 |
-
if
|
| 479 |
-
|
| 480 |
-
elif B == 1 and
|
| 481 |
-
img = img.expand(
|
| 482 |
B = img.shape[0]
|
| 483 |
else:
|
| 484 |
-
raise ValueError(
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
# RGB -> RGBA with alpha = final_mask
|
| 488 |
-
alpha = final_mask_resized.to(device=img.device, dtype=img.dtype)
|
| 489 |
-
final_overlay = torch.cat([img, alpha.unsqueeze(-1)], dim=-1)
|
| 490 |
-
else:
|
| 491 |
-
# RGBA: combine existing alpha with final_mask using RMBG combine (maximum)
|
| 492 |
-
rgb = img[..., :3]
|
| 493 |
-
alpha_img = img[..., 3] # [B,H,W]
|
| 494 |
|
| 495 |
-
|
| 496 |
-
a1 = alpha_img.detach().cpu()
|
| 497 |
-
a2 = final_mask_resized.detach().cpu()
|
| 498 |
-
combined_alpha, = combiner.combine_masks(a1, mode="combine", mask_2=a2)
|
| 499 |
|
| 500 |
-
|
| 501 |
-
|
| 502 |
|
| 503 |
-
#
|
|
|
|
|
|
|
| 504 |
canvas = _as_image(canvas)
|
| 505 |
-
|
| 506 |
|
| 507 |
-
out = _alpha_over_region(
|
| 508 |
return (out,)
|
| 509 |
|
| 510 |
@classmethod
|
|
@@ -525,7 +535,6 @@ class apply_segment:
|
|
| 525 |
return f"File not found in assets/images: {image}"
|
| 526 |
return True
|
| 527 |
|
| 528 |
-
|
| 529 |
# -----------------------------
|
| 530 |
# Node mappings
|
| 531 |
# -----------------------------
|
|
|
|
| 441 |
"required": {
|
| 442 |
"mask": ("MASK",),
|
| 443 |
"image": (choices, {}), # dropdown asset (used ONLY for loaded mask)
|
| 444 |
+
"img": ("IMAGE",), # the image to receive alpha_mask as alpha (overlay source)
|
| 445 |
"canvas": ("IMAGE",), # destination
|
| 446 |
"x": ("INT", {"default": 0, "min": -100000, "max": 100000, "step": 1}),
|
| 447 |
"y": ("INT", {"default": 0, "min": -100000, "max": 100000, "step": 1}),
|
|
|
|
| 458 |
|
| 459 |
combiner = _AILab_MaskCombiner_Exact()
|
| 460 |
|
| 461 |
+
# -------------------
|
| 462 |
+
# 1) invert input mask -> inverse_mask
|
| 463 |
+
# -------------------
|
| 464 |
+
inverse_mask = 1.0 - mask
|
| 465 |
+
inverse_mask = torch.clamp(inverse_mask, 0.0, 1.0)
|
| 466 |
|
| 467 |
+
# Ensure CPU so we don't ever hit CPU/GPU device mismatches with loaded masks/PIL resizing
|
| 468 |
+
inverse_mask = inverse_mask.detach().cpu()
|
|
|
|
| 469 |
|
| 470 |
+
# -------------------
|
| 471 |
+
# 2) alpha_mask = combine_masks_with_loaded(inverse_mask)
|
| 472 |
+
# i.e. max(inverse_mask, 1 - loaded_mask) using RMBG exact combiner
|
| 473 |
+
# -------------------
|
| 474 |
+
_img_asset, loaded_mask = load_image_from_assets(image)
|
| 475 |
+
loaded_mask = loaded_mask.detach().cpu()
|
| 476 |
+
|
| 477 |
+
alpha_mask, = combiner.combine_masks(
|
| 478 |
+
inverse_mask,
|
| 479 |
+
mode="combine",
|
| 480 |
+
mask_2=(1.0 - loaded_mask)
|
| 481 |
+
)
|
| 482 |
+
alpha_mask = torch.clamp(alpha_mask, 0.0, 1.0)
|
| 483 |
+
|
| 484 |
+
# -------------------
|
| 485 |
+
# 3) join image with alpha using alpha_mask -> overlay (RGBA)
|
| 486 |
+
# IMPORTANT: replace alpha, don't max() with existing alpha
|
| 487 |
+
# -------------------
|
| 488 |
img = _as_image(img)
|
| 489 |
B, H, W, C = img.shape
|
| 490 |
|
| 491 |
+
# Resize alpha_mask to match img H/W if needed (same resize logic style as RMBG)
|
| 492 |
+
alpha_mask_resized = combiner._resize_if_needed(alpha_mask, (alpha_mask.shape[0], H, W))
|
|
|
|
| 493 |
|
| 494 |
+
# Batch match (allow 1 -> N expansion)
|
| 495 |
+
if alpha_mask_resized.shape[0] != B:
|
| 496 |
+
if alpha_mask_resized.shape[0] == 1 and B > 1:
|
| 497 |
+
alpha_mask_resized = alpha_mask_resized.expand(B, H, W)
|
| 498 |
+
elif B == 1 and alpha_mask_resized.shape[0] > 1:
|
| 499 |
+
img = img.expand(alpha_mask_resized.shape[0], *img.shape[1:])
|
| 500 |
B = img.shape[0]
|
| 501 |
else:
|
| 502 |
+
raise ValueError(
|
| 503 |
+
f"Batch mismatch: img batch={B}, alpha_mask batch={alpha_mask_resized.shape[0]}"
|
| 504 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
|
| 506 |
+
alpha_mask_resized = alpha_mask_resized.to(device=img.device, dtype=img.dtype).clamp(0.0, 1.0)
|
|
|
|
|
|
|
|
|
|
| 507 |
|
| 508 |
+
rgb = img[..., :3]
|
| 509 |
+
overlay = torch.cat([rgb, alpha_mask_resized.unsqueeze(-1)], dim=-1) # RGBA
|
| 510 |
|
| 511 |
+
# -------------------
|
| 512 |
+
# 4) paste overlay onto canvas at (x,y) -> final output
|
| 513 |
+
# -------------------
|
| 514 |
canvas = _as_image(canvas)
|
| 515 |
+
overlay = overlay.to(device=canvas.device, dtype=canvas.dtype)
|
| 516 |
|
| 517 |
+
out = _alpha_over_region(overlay, canvas, x, y)
|
| 518 |
return (out,)
|
| 519 |
|
| 520 |
@classmethod
|
|
|
|
| 535 |
return f"File not found in assets/images: {image}"
|
| 536 |
return True
|
| 537 |
|
|
|
|
| 538 |
# -----------------------------
|
| 539 |
# Node mappings
|
| 540 |
# -----------------------------
|