Spaces:
Running on Zero
Running on Zero
Download fdanyone/foreground.py from rerun/4danyone-rerun: direct link, hf CLI and curl.
- Browser
- Download file 2.32 kB
-
https://huggingface.co/spaces/rerun/4danyone-rerun/resolve/1b2e96f9bdb4bdc32148870859e16da0ad533680/fdanyone/foreground.py
- Command line
-
hf download hf://spaces/rerun/4danyone-rerun@1b2e96f9bdb4bdc32148870859e16da0ad533680/fdanyone/foreground.py
-
curl -L -o foreground.py https://huggingface.co/spaces/rerun/4danyone-rerun/resolve/1b2e96f9bdb4bdc32148870859e16da0ad533680/fdanyone/foreground.py
2.32 kB
| """Pinned BiRefNet inference over the canonical source clip.""" | |
| from __future__ import annotations | |
| import gc | |
| from pathlib import Path | |
| import numpy as np | |
| from PIL import Image | |
| from fdanyone.config import FOREGROUND | |
| def predict_foreground_masks( | |
| frames: tuple[np.ndarray, ...], | |
| model_path: str | Path, | |
| device: str, | |
| *, | |
| batch_size: int = FOREGROUND.batch_size, | |
| ) -> np.ndarray: | |
| """Return full-raster 8-bit foreground masks for the canonical clip.""" | |
| import torch | |
| from torchvision import transforms | |
| from torchvision.transforms.functional import to_pil_image | |
| from transformers import AutoModelForImageSegmentation | |
| if not frames: | |
| raise ValueError("Foreground inference requires at least one frame.") | |
| if batch_size <= 0: | |
| raise ValueError("batch_size must be positive.") | |
| shape = frames[0].shape | |
| if any(frame.dtype != np.uint8 or frame.shape != shape for frame in frames): | |
| raise ValueError("Foreground frames must share one RGB uint8 raster.") | |
| model = AutoModelForImageSegmentation.from_pretrained( | |
| str(Path(model_path).expanduser().resolve()), | |
| local_files_only=True, | |
| trust_remote_code=True, | |
| ) | |
| model = model.eval().half().to(device) | |
| transform = transforms.Compose( | |
| [ | |
| transforms.Resize(FOREGROUND.image_size), | |
| transforms.ToTensor(), | |
| transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), | |
| ] | |
| ) | |
| output: list[np.ndarray] = [] | |
| try: | |
| for start in range(0, len(frames), batch_size): | |
| images = [Image.fromarray(frame, mode="RGB") for frame in frames[start : start + batch_size]] | |
| inputs = torch.stack([transform(image) for image in images]).to(device=device, dtype=torch.float16) | |
| with torch.inference_mode(): | |
| predictions = model(inputs)[-1].sigmoid().cpu() | |
| for image, prediction in zip(images, predictions, strict=True): | |
| mask = to_pil_image(prediction).resize(image.size).convert("L") | |
| output.append(np.asarray(mask, dtype=np.uint8).copy()) | |
| del inputs, predictions | |
| finally: | |
| del model | |
| gc.collect() | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| return np.stack(output) | |