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
|
The upsampler is lazy-loaded on first call and reused across
|
||||||
calls. Uses ``RealESRGAN_x4plus_anime_6B`` (17 MB,
|
calls. Uses ``RealESRGAN_x4plus_anime_6B`` (17 MB,
|
||||||
auto-downloaded).
|
auto-downloaded). Preserves alpha channel when present.
|
||||||
|
|
||||||
Args:
|
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.
|
output_path: Where to save the upscaled PNG.
|
||||||
scale: Output scale factor (2, 3, or 4).
|
scale: Output scale factor (2, 3, or 4).
|
||||||
|
|
||||||
|
|||||||
@@ -72,13 +72,32 @@ def _build_upsampler(device: str = "cuda") -> RealESRGANer:
|
|||||||
return upsampler
|
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(
|
def upscale(
|
||||||
input_path: str,
|
input_path: str,
|
||||||
output_path: str,
|
output_path: str,
|
||||||
scale: int = 2,
|
scale: int = 2,
|
||||||
upsampler: RealESRGANer | None = None,
|
upsampler: RealESRGANer | None = 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:
|
Args:
|
||||||
input_path: Path to the input image.
|
input_path: Path to the input image.
|
||||||
@@ -107,17 +126,25 @@ def upscale(
|
|||||||
if _upsampler is None:
|
if _upsampler is None:
|
||||||
_upsampler = _build_upsampler()
|
_upsampler = _build_upsampler()
|
||||||
|
|
||||||
img = Image.open(input_file).convert("RGB")
|
src = Image.open(input_file)
|
||||||
img_np = np.array(img)
|
rgb_np, alpha_np = _load_rgb_alpha(src)
|
||||||
|
w, h = src.size
|
||||||
|
src.close()
|
||||||
|
|
||||||
t0 = time.perf_counter()
|
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)
|
t_elapsed = round(time.perf_counter() - t0, 3)
|
||||||
|
|
||||||
result_img = Image.fromarray(result)
|
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)
|
result_img.save(output_file)
|
||||||
|
|
||||||
w, h = img.size
|
|
||||||
rw, rh = result_img.size
|
rw, rh = result_img.size
|
||||||
print(f"Saved {output_file} ({w}×{h} → {rw}×{rh}, {t_elapsed}s)")
|
print(f"Saved {output_file} ({w}×{h} → {rw}×{rh}, {t_elapsed}s)")
|
||||||
|
|
||||||
@@ -158,17 +185,25 @@ def upscales(
|
|||||||
stem = Path(input_path).stem
|
stem = Path(input_path).stem
|
||||||
output_path = out_dir / f"{stem}_x{scale}.png"
|
output_path = out_dir / f"{stem}_x{scale}.png"
|
||||||
|
|
||||||
img = Image.open(input_path).convert("RGB")
|
src = Image.open(input_path)
|
||||||
img_np = np.array(img)
|
rgb_np, alpha_np = _load_rgb_alpha(src)
|
||||||
|
w, h = src.size
|
||||||
|
src.close()
|
||||||
|
|
||||||
t0 = time.perf_counter()
|
t0 = time.perf_counter()
|
||||||
result, _ = _upsampler.enhance(img_np, outscale=scale)
|
result, _ = _upsampler.enhance(rgb_np, outscale=scale)
|
||||||
t_elapsed = time.perf_counter() - t0
|
t_elapsed = time.perf_counter() - t0
|
||||||
total += t_elapsed
|
total += t_elapsed
|
||||||
|
|
||||||
result_img = Image.fromarray(result)
|
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)
|
result_img.save(output_path)
|
||||||
w, h = img.size
|
|
||||||
rw, rh = result_img.size
|
rw, rh = result_img.size
|
||||||
print(f"Saved {output_path} ({w}×{h} → {rw}×{rh}, {t_elapsed:.3f}s)")
|
print(f"Saved {output_path} ({w}×{h} → {rw}×{rh}, {t_elapsed:.3f}s)")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user