Fix bg removal in final assets
This commit is contained in:
@@ -407,10 +407,10 @@ class VnAssetsSession:
|
||||
|
||||
The upsampler is lazy-loaded on first call and reused across
|
||||
calls. Uses ``RealESRGAN_x4plus_anime_6B`` (17 MB,
|
||||
auto-downloaded).
|
||||
auto-downloaded). Preserves alpha channel when present.
|
||||
|
||||
Args:
|
||||
input_path: Path to the input RGB image.
|
||||
input_path: Path to the input image (RGB or RGBA).
|
||||
output_path: Where to save the upscaled PNG.
|
||||
scale: Output scale factor (2, 3, or 4).
|
||||
|
||||
|
||||
@@ -72,13 +72,32 @@ def _build_upsampler(device: str = "cuda") -> RealESRGANer:
|
||||
return upsampler
|
||||
|
||||
|
||||
def _load_rgb_alpha(img: Image.Image) -> tuple[np.ndarray, np.ndarray | None]:
|
||||
"""Extract RGB array and optional alpha channel from a PIL image.
|
||||
|
||||
Returns (rgb_np, alpha_np). ``alpha_np`` is None when the image has no
|
||||
alpha channel. For paletted images, the palette is expanded first.
|
||||
"""
|
||||
if img.mode == "P":
|
||||
img = img.convert("RGBA" if "transparency" in img.info else "RGB")
|
||||
if img.mode in ("RGBA", "LA"):
|
||||
rgb = img.convert("RGB")
|
||||
alpha = img.getchannel("A")
|
||||
return np.array(rgb), np.array(alpha)
|
||||
return np.array(img.convert("RGB")), None
|
||||
|
||||
|
||||
def upscale(
|
||||
input_path: str,
|
||||
output_path: str,
|
||||
scale: int = 2,
|
||||
upsampler: RealESRGANer | None = None,
|
||||
) -> None:
|
||||
"""Upscale a single image. Output is an RGB PNG.
|
||||
"""Upscale a single image. Preserves alpha channel when present.
|
||||
|
||||
When the input is RGBA, the RGB channels are upscaled through the
|
||||
model and the alpha channel is resized with LANCZOS interpolation.
|
||||
Output format matches input: RGB for RGB inputs, RGBA for RGBA inputs.
|
||||
|
||||
Args:
|
||||
input_path: Path to the input image.
|
||||
@@ -107,17 +126,25 @@ def upscale(
|
||||
if _upsampler is None:
|
||||
_upsampler = _build_upsampler()
|
||||
|
||||
img = Image.open(input_file).convert("RGB")
|
||||
img_np = np.array(img)
|
||||
src = Image.open(input_file)
|
||||
rgb_np, alpha_np = _load_rgb_alpha(src)
|
||||
w, h = src.size
|
||||
src.close()
|
||||
|
||||
t0 = time.perf_counter()
|
||||
result, _ = _upsampler.enhance(img_np, outscale=scale)
|
||||
result, _ = _upsampler.enhance(rgb_np, outscale=scale)
|
||||
t_elapsed = round(time.perf_counter() - t0, 3)
|
||||
|
||||
result_img = Image.fromarray(result)
|
||||
|
||||
if alpha_np is not None:
|
||||
alpha_img = Image.fromarray(alpha_np)
|
||||
alpha_scaled = alpha_img.resize(result_img.size, Image.LANCZOS)
|
||||
result_img = result_img.convert("RGBA")
|
||||
result_img.putalpha(alpha_scaled)
|
||||
|
||||
result_img.save(output_file)
|
||||
|
||||
w, h = img.size
|
||||
rw, rh = result_img.size
|
||||
print(f"Saved {output_file} ({w}×{h} → {rw}×{rh}, {t_elapsed}s)")
|
||||
|
||||
@@ -158,17 +185,25 @@ def upscales(
|
||||
stem = Path(input_path).stem
|
||||
output_path = out_dir / f"{stem}_x{scale}.png"
|
||||
|
||||
img = Image.open(input_path).convert("RGB")
|
||||
img_np = np.array(img)
|
||||
src = Image.open(input_path)
|
||||
rgb_np, alpha_np = _load_rgb_alpha(src)
|
||||
w, h = src.size
|
||||
src.close()
|
||||
|
||||
t0 = time.perf_counter()
|
||||
result, _ = _upsampler.enhance(img_np, outscale=scale)
|
||||
result, _ = _upsampler.enhance(rgb_np, outscale=scale)
|
||||
t_elapsed = time.perf_counter() - t0
|
||||
total += t_elapsed
|
||||
|
||||
result_img = Image.fromarray(result)
|
||||
|
||||
if alpha_np is not None:
|
||||
alpha_img = Image.fromarray(alpha_np)
|
||||
alpha_scaled = alpha_img.resize(result_img.size, Image.LANCZOS)
|
||||
result_img = result_img.convert("RGBA")
|
||||
result_img.putalpha(alpha_scaled)
|
||||
|
||||
result_img.save(output_path)
|
||||
w, h = img.size
|
||||
rw, rh = result_img.size
|
||||
print(f"Saved {output_path} ({w}×{h} → {rw}×{rh}, {t_elapsed:.3f}s)")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user