--- license: cc-by-nc-4.0 pipeline_tag: depth-estimation tags: - surface-normals - normal-estimation - panoramic-images - equirectangular - high-resolution - computer-vision - in-the-wild - zero-shot ---

📟 PaGeR-Normals Model Card

Github Website arXiv HF Collection License

`PaGeR-Normals` is the **normals-only** variant of PaGeR released with the paper: - **Paper:** [Unified Panoramic Geometry Estimation via Multi-View Foundation Models](https://huggingface.co/papers/2605.26368) — [arXiv:2605.26368](https://arxiv.org/abs/2605.26368) From a single equirectangular (ERP) panorama, it produces a **dense surface-normal map** (unit vectors in the panorama's world frame) in a single forward pass. If you want depth, metric scale, and sky masking from the same model, use the unified [`prs-eth/PaGeR`](https://huggingface.co/prs-eth/PaGeR) checkpoint instead. You can also browse the rest of our [PaGeR HF collection](https://huggingface.co/collections/prs-eth/pager-697241d06b3733a6f18e4d39) or try the [interactive demo](https://huggingface.co/spaces/prs-eth/PaGeR). ## Model Details - **Developed by:** [Vukasin Bozic](https://vulus98.github.io/), [Isidora Slavkovic](https://linkedin.com/in/isidora-slavkovic), [Dominik Narnhofer](https://scholar.google.com/citations?user=tFx8AhkAAAAJ&hl=en), [Nando Metzger](https://nandometzger.github.io/), [Denis Rozumny](https://rozumden.github.io/), [Konrad Schindler](https://scholar.google.com/citations?user=FZuNgqIAAAAJ), [Nikolai Kalischek](https://scholar.google.com/citations?user=XwzlnZoAAAAJ&hl=de). - **Model type:** Feed-forward, multi-view foundation-model adaptation for single-image panoramic surface-normal estimation. - **Backbone:** [Depth Anything 3](https://github.com/ByteDance-Seed/Depth-Anything-3) (`da3-giant`, ViT-Giant), repurposed for cubemap-based multi-view processing of the panorama. - **Inputs:** A single ERP panorama, internally projected onto a 6-face cubemap at 504 px per face. - **Output:** Dense surface-normal map at panoramic resolution, returned as unit vectors in the panorama's world frame. - **Resolution:** Designed for high-resolution ERP inputs, up to 3K. - **License:** [CC BY-NC 4.0](LICENSE) — academic / non-commercial use only. The released weights are derivative works of the [Depth Anything 3](https://github.com/ByteDance-Seed/Depth-Anything-3) `da3-giant` backbone, released by ByteDance under CC BY-NC 4.0, and inherit that restriction. Commercial use is not permitted. - **Resources for more information:** [Project Website](https://pager360.github.io/), [Paper](https://arxiv.org/abs/2605.26368), [Code](https://github.com/prs-eth/PaGeR). ### Other released checkpoints | Checkpoint | Hugging Face id | Depth | Normals | Sky | |---|---|---|---|---| | PaGeR *(unified, recommended)* | [`prs-eth/PaGeR`](https://huggingface.co/prs-eth/PaGeR) | ✅ | ✅ | ✅ | | PaGeR-Metric-Depth | [`prs-eth/PaGeR-metric-depth`](https://huggingface.co/prs-eth/PaGeR-metric-depth) | ✅ (metric) | | | | **PaGeR-Normals** *(this card)* | [`prs-eth/PaGeR-normals`](https://huggingface.co/prs-eth/PaGeR-normals) | | ✅ | | ## Usage A minimal Python snippet that runs the normals-only model on a single panorama and produces a dense surface-normal map in one forward pass. The snippet assumes you have [cloned the repository](https://github.com/prs-eth/PaGeR) and `pip install -e .` ed it, so that `src.pager` is importable; checkpoint weights and config are streamed from the Hub on first use. ```python import numpy as np import torch from huggingface_hub import hf_hub_download from omegaconf import OmegaConf from PIL import Image from src.pager import Pager from src.utils.geometry_utils import erp_to_cubemap from src.utils.utils import prepare_normals_for_logging checkpoint = "prs-eth/PaGeR-normals" device = torch.device("cuda") # 1. Load the model config from the Hub and instantiate Pager. config_path = hf_hub_download(repo_id=checkpoint, filename="config.yaml") cfg = OmegaConf.load(config_path) pager = Pager(checkpoint, cfg=cfg, device=device) pager.get_intrinsics_extrinsics(image_size=cfg.face_size, fov=getattr(cfg, "cube_fov", 90.0)) pager.model.to(device).eval() # 2. Load a panorama and project it to the 6-face cubemap PaGeR consumes. panorama = np.array(Image.open("assets/examples/apartment_synth.jpg").convert("RGB")) / 255.0 panorama = torch.from_numpy(panorama).permute(2, 0, 1).float() * 2 - 1 rgb_cubemap = erp_to_cubemap(panorama, face_w=cfg.face_size, fov=getattr(cfg, "cube_fov", 90.0)).unsqueeze(0).to(device) # 3. Run one forward pass. The normals head is the only head in this # checkpoint — no depth, sky, or scale outputs. with torch.inference_mode(): pred = pager(rgb_cubemap, dtype=torch.float16) # 4. Convert the raw normals output into an ERP-resolution unit-normal map. # ``sky_mask=None`` because this checkpoint has no sky head, so unbounded # regions are left as predicted instead of being masked out. H, W = panorama.shape[-2:] normals, normals_viz = prepare_normals_for_logging( pager, pred["normals"][0], None, (H, W), ) ``` `normals` is a `(3, H, W)` float32 unit-normal field in the panorama's world frame at the input panorama resolution; `normals_viz` is the uint8 RGB preview (per-sample rescaled). If you also need sky filling, depth, or metric scale from the same model, use the unified [`prs-eth/PaGeR`](https://huggingface.co/prs-eth/PaGeR) checkpoint instead. See the [GitHub repository](https://github.com/prs-eth/PaGeR) for the full CLI (`inference.py`), evaluation scripts, the Gradio demo (`app.py`), and the point-cloud exporter. ## Citation If you use this checkpoint in your work, please cite: ```bibtex @article{bozic2026pager, title = {Unified Panoramic Geometry Estimation via Multi-View Foundation Models}, author = {Bozic, Vukasin and Slavkovic, Isidora and Narnhofer, Dominik and Metzger, Nando and Rozumny, Denis and Schindler, Konrad and Kalischek, Nikolai}, journal = {arXiv preprint arXiv:2605.26368}, year = {2026} } ```