Download minimal/render.py from jadgardner/reni-models: direct link, hf CLI and curl.
- Browser
- Download file 2.73 kB
-
https://huggingface.co/jadgardner/reni-models/resolve/main/minimal/render.py
- Command line
-
hf download hf://jadgardner/reni-models/minimal/render.py
-
curl -L -o render.py https://huggingface.co/jadgardner/reni-models/resolve/main/minimal/render.py
2.73 kB
| #!/usr/bin/env python3 | |
| """Render an HDR environment map with the lightweight RENI++ decoder.""" | |
| from __future__ import annotations | |
| import argparse | |
| from pathlib import Path | |
| import torch | |
| from PIL import Image | |
| from reni_decoder import ReniDecoder, equirectangular_directions | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument( | |
| "--weights", | |
| type=Path, | |
| default=Path("decoder.pt"), | |
| help="Decoder-only artifact from the RENI Models release", | |
| ) | |
| parser.add_argument("--output-dir", type=Path, default=Path("render")) | |
| parser.add_argument("--height", type=int, default=64) | |
| parser.add_argument("--seed", type=int, default=0) | |
| parser.add_argument("--exposure", type=float, default=0.0, help="Display EV") | |
| parser.add_argument("--chunk-size", type=int, default=65536) | |
| parser.add_argument( | |
| "--device", | |
| default="auto", | |
| choices=("auto", "cpu", "cuda"), | |
| ) | |
| return parser.parse_args() | |
| def linear_to_srgb(linear: torch.Tensor) -> torch.Tensor: | |
| linear = linear.clamp_min(0.0) | |
| return torch.where( | |
| linear <= 0.0031308, | |
| 12.92 * linear, | |
| 1.055 * linear.pow(1.0 / 2.4) - 0.055, | |
| ) | |
| def main() -> None: | |
| args = parse_args() | |
| device = ( | |
| "cuda" | |
| if args.device == "auto" and torch.cuda.is_available() | |
| else "cpu" | |
| if args.device == "auto" | |
| else args.device | |
| ) | |
| model = ReniDecoder.from_artifact(args.weights, device=device) | |
| generator = torch.Generator(device="cpu").manual_seed(args.seed) | |
| latent = torch.randn( | |
| model.config.latent_dim, | |
| 3, | |
| generator=generator, | |
| ).to(device) | |
| directions = equirectangular_directions( | |
| args.height, | |
| device=device, | |
| ) | |
| with torch.no_grad(): | |
| hdr = model(latent, directions, args.chunk_size).reshape( | |
| args.height, 2 * args.height, 3 | |
| ) | |
| args.output_dir.mkdir(parents=True, exist_ok=True) | |
| torch.save(hdr.cpu(), args.output_dir / "environment_linear_hdr.pt") | |
| torch.save(latent.cpu(), args.output_dir / "latent.pt") | |
| display = hdr * (2.0**args.exposure) | |
| display = display / (1.0 + display.clamp_min(0.0)) | |
| display = ( | |
| linear_to_srgb(display).clamp(0.0, 1.0).mul(255.0).byte().cpu().contiguous() | |
| ) | |
| preview = Image.frombytes( | |
| "RGB", | |
| (display.shape[1], display.shape[0]), | |
| bytes(display.flatten()), | |
| ) | |
| preview.save(args.output_dir / "environment_preview.png") | |
| print(f"Wrote {args.output_dir / 'environment_linear_hdr.pt'}") | |
| print(f"Wrote {args.output_dir / 'environment_preview.png'}") | |
| if __name__ == "__main__": | |
| main() | |