sprite / sprite_extractor.py
Cnass's picture
Upload 11 files
2414b69 verified
Raw History Blame Contribute Delete
2.69 kB
"""
sprite_extractor.py
--------------------
Turns segmentation results (bounding boxes) into actual exported sprite
images. This is where "extract each sprite at the smallest possible
bounding box, no resize, optional NEAREST padding" is implemented.
"""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from background import BackgroundInfo, apply_transparency
from image_utils import BBox, crop_exact, pad_nearest, to_pil
from segmentation import DetectedSprite
@dataclass
class ExtractedSprite:
sprite_index: int
bbox: BBox
rgba: np.ndarray # exact pixels, background untouched
rgba_transparent_bg: np.ndarray # same pixels, background made transparent
confidence: float
confidence_reasons: list[str]
component_count: int
source_file: str
source: str = "gap" # which segmentation path produced it
def extract_sprite(
sheet_rgba: np.ndarray,
bg_info: BackgroundInfo,
detected: DetectedSprite,
source_file: str,
padding: int = 0,
) -> ExtractedSprite:
"""
Crop exactly `detected.bbox` out of the sheet (no resampling). Produces
two variants: background kept as-is, and background made transparent
(only the border-connected background pixels, per background.py).
"""
b = detected.bbox
kept = crop_exact(sheet_rgba, b.x, b.y, b.width, b.height)
# Build the transparent-background version by cropping from a
# full-sheet transparent copy, so the exact same border-connected mask
# logic applies consistently regardless of crop boundaries.
full_transparent = apply_transparency(sheet_rgba, bg_info)
transparent = crop_exact(full_transparent, b.x, b.y, b.width, b.height)
if padding > 0:
kept = pad_nearest(kept, padding)
transparent = pad_nearest(transparent, padding)
return ExtractedSprite(
sprite_index=detected.sprite_index,
bbox=b,
rgba=kept,
rgba_transparent_bg=transparent,
confidence=detected.confidence,
confidence_reasons=detected.confidence_reasons,
component_count=detected.component_count,
source_file=source_file,
source=detected.source,
)
def extract_all(
sheet_rgba: np.ndarray,
bg_info: BackgroundInfo,
detections: list[DetectedSprite],
source_file: str,
padding: int = 0,
) -> list[ExtractedSprite]:
return [
extract_sprite(sheet_rgba, bg_info, d, source_file, padding=padding)
for d in detections
]
def sprite_to_pil(sprite: ExtractedSprite, keep_background: bool):
arr = sprite.rgba if keep_background else sprite.rgba_transparent_bg
return to_pil(arr)