Update app.py
Browse files
app.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""gQIR Gradio demo
|
| 3 |
-
|
| 4 |
Single-frame mode follows infer_sd2GAN_stage2.py (color path only).
|
| 5 |
Burst mode follows infer_burst_realistic.py for 77->11 aggregation and reconstruction.
|
| 6 |
-
|
| 7 |
Local run cmd:
|
| 8 |
python gradio_app.py
|
| 9 |
--single-config configs/inference/eval_sd2GAN.yaml \
|
|
@@ -49,7 +47,13 @@ try:
|
|
| 49 |
except Exception:
|
| 50 |
h5py = None
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
|
|
|
| 53 |
DEFAULT_SINGLE_CONFIG_COLOR = "configs/inference/eval_3bit_color.yaml"
|
| 54 |
DEFAULT_SINGLE_CONFIG_MONO = "configs/inference/eval_3bit_mono.yaml"
|
| 55 |
DEFAULT_BURST_CONFIG_COLOR = "configs/inference/eval_burst_mosaic.yaml"
|
|
@@ -60,6 +64,23 @@ BURST_WINDOW = 77
|
|
| 60 |
PIPELINE_COLOR = "Color"
|
| 61 |
PIPELINE_MONO = "Monochrome"
|
| 62 |
PIPELINE_OPTIONS = [PIPELINE_COLOR, PIPELINE_MONO]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
SINGLE_MODE_GT = "GT image (simulate 3-bit SPAD)"
|
| 65 |
SINGLE_MODE_REAL = "Real SPAD frame"
|
|
@@ -77,6 +98,9 @@ RUNTIME_SINGLE_CONFIGS: dict[str, Path] = {}
|
|
| 77 |
RUNTIME_BURST_CONFIGS: dict[str, Path] = {}
|
| 78 |
RUNTIME_DEVICE: str = "cuda"
|
| 79 |
RUNTIME_BURST_OUT_SIZES: dict[str, int] = {}
|
|
|
|
|
|
|
|
|
|
| 80 |
_TEMP_VIDEO_DIRS: list[str] = []
|
| 81 |
|
| 82 |
|
|
@@ -129,12 +153,114 @@ def parse_args() -> argparse.Namespace:
|
|
| 129 |
default="cuda" if torch.cuda.is_available() else "cpu",
|
| 130 |
help="Inference device, e.g. cuda, cuda:0, cpu",
|
| 131 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
parser.add_argument("--port", type=int, default=7860)
|
| 133 |
parser.add_argument("--local", action="store_true", help="Bind to 127.0.0.1 instead of 0.0.0.0")
|
| 134 |
parser.add_argument("--share", action="store_true")
|
| 135 |
return parser.parse_args()
|
| 136 |
|
| 137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
def _ensure_rgb_image(arr: np.ndarray) -> np.ndarray:
|
| 139 |
arr = np.asarray(arr)
|
| 140 |
if arr.ndim == 2:
|
|
@@ -378,9 +504,10 @@ def differentiable_warp(x: torch.Tensor, flow: torch.Tensor) -> torch.Tensor:
|
|
| 378 |
|
| 379 |
|
| 380 |
class SingleColorPipeline:
|
| 381 |
-
def __init__(self, config_path: Path, device: str):
|
| 382 |
self.config_path = config_path
|
| 383 |
self.device = device
|
|
|
|
| 384 |
self.max_size = DEFAULT_MAX_SIZE
|
| 385 |
self.model: Optional[SD2Enhancer] = None
|
| 386 |
|
|
@@ -388,6 +515,7 @@ class SingleColorPipeline:
|
|
| 388 |
if self.model is not None:
|
| 389 |
return
|
| 390 |
cfg = OmegaConf.load(str(self.config_path))
|
|
|
|
| 391 |
if cfg.base_model_type != "sd2":
|
| 392 |
raise ValueError(f"Unsupported base_model_type for single pipeline: {cfg.base_model_type}")
|
| 393 |
self.model = SD2Enhancer(
|
|
@@ -462,9 +590,10 @@ class SingleColorPipeline:
|
|
| 462 |
|
| 463 |
|
| 464 |
class BurstColorPipeline:
|
| 465 |
-
def __init__(self, config_path: Path, device: str):
|
| 466 |
self.config_path = config_path
|
| 467 |
self.device = device
|
|
|
|
| 468 |
self.cfg = None
|
| 469 |
self.out_size = 512
|
| 470 |
self.weight_dtype = torch.bfloat16 if str(device).startswith("cuda") else torch.float32
|
|
@@ -482,6 +611,7 @@ class BurstColorPipeline:
|
|
| 482 |
return
|
| 483 |
|
| 484 |
cfg = OmegaConf.load(str(self.config_path))
|
|
|
|
| 485 |
self.cfg = cfg
|
| 486 |
self.out_size = int(cfg.dataset.val.params.out_size)
|
| 487 |
|
|
@@ -504,7 +634,7 @@ class BurstColorPipeline:
|
|
| 504 |
dropout = False
|
| 505 |
|
| 506 |
raft_model = RAFT(RAFTArgs())
|
| 507 |
-
raft_path =
|
| 508 |
raft_dict = torch.load(str(raft_path), map_location="cpu")
|
| 509 |
corrected = {}
|
| 510 |
for k, v in raft_dict.items():
|
|
@@ -687,6 +817,7 @@ def _get_single_pipeline(pipeline_type: str) -> SingleColorPipeline:
|
|
| 687 |
_SINGLE_PIPELINES[pipeline_type] = SingleColorPipeline(
|
| 688 |
RUNTIME_SINGLE_CONFIGS[pipeline_type],
|
| 689 |
RUNTIME_DEVICE,
|
|
|
|
| 690 |
)
|
| 691 |
_SINGLE_PIPELINES[pipeline_type].load()
|
| 692 |
return _SINGLE_PIPELINES[pipeline_type]
|
|
@@ -702,6 +833,7 @@ def _get_burst_pipeline(pipeline_type: str) -> BurstColorPipeline:
|
|
| 702 |
_BURST_PIPELINES[pipeline_type] = BurstColorPipeline(
|
| 703 |
RUNTIME_BURST_CONFIGS[pipeline_type],
|
| 704 |
RUNTIME_DEVICE,
|
|
|
|
| 705 |
)
|
| 706 |
_BURST_PIPELINES[pipeline_type].load()
|
| 707 |
return _BURST_PIPELINES[pipeline_type]
|
|
@@ -1201,18 +1333,15 @@ def build_demo() -> gr.Blocks:
|
|
| 1201 |
<a href="https://arxiv.org/abs/2602.20417">ArXiv</a> |
|
| 1202 |
<a href="https://github.com/Aryan-Garg/gQIR">GitHub</a>
|
| 1203 |
</p>
|
| 1204 |
-
|
| 1205 |
### What You Can Run
|
| 1206 |
- **Single Frame (Stage-2):** Reconstruct one frame from either a clean GT image (internally simulated to SPAD) or a real SPAD frame.
|
| 1207 |
- **Burst (Stage-3):** Reconstruct from a fixed **77-frame** window using either GT videos/cubes or real photon cubes.
|
| 1208 |
- **Pipelines:** Toggle between **Color** and **Monochrome** reconstruction in both tabs.
|
| 1209 |
-
|
| 1210 |
### Supported Inputs
|
| 1211 |
- **Single GT:** Standard image uploads.
|
| 1212 |
- **Single Real:** Real SPAD frame image uploads.
|
| 1213 |
- **Burst GT:** Public-friendly videos (`.mp4`, `.mov`, `.wmv`, `.avi`, `.mkv`, `.webm`) plus research cube formats (`.npy`, `.npz`, `.pt`, `.h5`) or image folders.
|
| 1214 |
- **Burst Real:** Photon cubes (`.npy`, `.npz`, `.pt`, `.h5`) or image folders.
|
| 1215 |
-
|
| 1216 |
### Quick Usage
|
| 1217 |
1. Pick pipeline and input mode.
|
| 1218 |
2. Load input and select burst start index (for Stage-3).
|
|
@@ -1341,12 +1470,16 @@ def build_demo() -> gr.Blocks:
|
|
| 1341 |
|
| 1342 |
def main() -> None:
|
| 1343 |
global RUNTIME_SINGLE_CONFIGS, RUNTIME_BURST_CONFIGS, RUNTIME_DEVICE, RUNTIME_BURST_OUT_SIZES
|
|
|
|
| 1344 |
|
| 1345 |
args = parse_args()
|
| 1346 |
single_color_cfg = Path(args.single_config if args.single_config else args.single_config_color).resolve()
|
| 1347 |
burst_color_cfg = Path(args.burst_config if args.burst_config else args.burst_config_color).resolve()
|
| 1348 |
single_mono_cfg = Path(args.single_config_mono).resolve()
|
| 1349 |
burst_mono_cfg = Path(args.burst_config_mono).resolve()
|
|
|
|
|
|
|
|
|
|
| 1350 |
|
| 1351 |
RUNTIME_SINGLE_CONFIGS = {
|
| 1352 |
PIPELINE_COLOR: single_color_cfg,
|
|
@@ -1356,6 +1489,10 @@ def main() -> None:
|
|
| 1356 |
PIPELINE_COLOR: burst_color_cfg,
|
| 1357 |
PIPELINE_MONO: burst_mono_cfg,
|
| 1358 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1359 |
RUNTIME_BURST_OUT_SIZES = {}
|
| 1360 |
for key, cfg_path in RUNTIME_BURST_CONFIGS.items():
|
| 1361 |
burst_cfg = OmegaConf.load(str(cfg_path))
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""gQIR Gradio demo
|
|
|
|
| 3 |
Single-frame mode follows infer_sd2GAN_stage2.py (color path only).
|
| 4 |
Burst mode follows infer_burst_realistic.py for 77->11 aggregation and reconstruction.
|
|
|
|
| 5 |
Local run cmd:
|
| 6 |
python gradio_app.py
|
| 7 |
--single-config configs/inference/eval_sd2GAN.yaml \
|
|
|
|
| 47 |
except Exception:
|
| 48 |
h5py = None
|
| 49 |
|
| 50 |
+
try:
|
| 51 |
+
from huggingface_hub import hf_hub_download
|
| 52 |
+
except Exception:
|
| 53 |
+
hf_hub_download = None
|
| 54 |
+
|
| 55 |
|
| 56 |
+
APP_ROOT = Path(__file__).resolve().parent
|
| 57 |
DEFAULT_SINGLE_CONFIG_COLOR = "configs/inference/eval_3bit_color.yaml"
|
| 58 |
DEFAULT_SINGLE_CONFIG_MONO = "configs/inference/eval_3bit_mono.yaml"
|
| 59 |
DEFAULT_BURST_CONFIG_COLOR = "configs/inference/eval_burst_mosaic.yaml"
|
|
|
|
| 64 |
PIPELINE_COLOR = "Color"
|
| 65 |
PIPELINE_MONO = "Monochrome"
|
| 66 |
PIPELINE_OPTIONS = [PIPELINE_COLOR, PIPELINE_MONO]
|
| 67 |
+
HF_DEFAULT_REPO_ID = "aRy4n/gQIR"
|
| 68 |
+
HF_MODEL_FILES = {
|
| 69 |
+
PIPELINE_COLOR: {
|
| 70 |
+
"single_qvae": "0105000.pt",
|
| 71 |
+
"single_lora": "state_dict.pth",
|
| 72 |
+
"burst_qvae": "0105000.pt",
|
| 73 |
+
"burst_lora": "state_dict.pth",
|
| 74 |
+
"burst_fusion": "fusion_vit_0050000.pt",
|
| 75 |
+
},
|
| 76 |
+
PIPELINE_MONO: {
|
| 77 |
+
"single_qvae": "mono/0150000.pt",
|
| 78 |
+
"single_lora": "mono/state_dict.pth",
|
| 79 |
+
"burst_qvae": "mono/0150000.pt",
|
| 80 |
+
"burst_lora": "mono/state_dict.pth",
|
| 81 |
+
"burst_fusion": "mono/fusion_vit_0020000.pt",
|
| 82 |
+
},
|
| 83 |
+
}
|
| 84 |
|
| 85 |
SINGLE_MODE_GT = "GT image (simulate 3-bit SPAD)"
|
| 86 |
SINGLE_MODE_REAL = "Real SPAD frame"
|
|
|
|
| 98 |
RUNTIME_BURST_CONFIGS: dict[str, Path] = {}
|
| 99 |
RUNTIME_DEVICE: str = "cuda"
|
| 100 |
RUNTIME_BURST_OUT_SIZES: dict[str, int] = {}
|
| 101 |
+
RUNTIME_HF_REPO_ID: str = HF_DEFAULT_REPO_ID
|
| 102 |
+
RUNTIME_HF_CACHE_DIR: Optional[str] = None
|
| 103 |
+
RUNTIME_HF_TOKEN: Optional[str] = None
|
| 104 |
_TEMP_VIDEO_DIRS: list[str] = []
|
| 105 |
|
| 106 |
|
|
|
|
| 153 |
default="cuda" if torch.cuda.is_available() else "cpu",
|
| 154 |
help="Inference device, e.g. cuda, cuda:0, cpu",
|
| 155 |
)
|
| 156 |
+
parser.add_argument(
|
| 157 |
+
"--hf-repo-id",
|
| 158 |
+
type=str,
|
| 159 |
+
default=HF_DEFAULT_REPO_ID,
|
| 160 |
+
help="Hugging Face repo containing gQIR checkpoints used when config paths are not local files.",
|
| 161 |
+
)
|
| 162 |
+
parser.add_argument(
|
| 163 |
+
"--hf-cache-dir",
|
| 164 |
+
type=str,
|
| 165 |
+
default=None,
|
| 166 |
+
help="Optional Hugging Face cache directory for checkpoint downloads.",
|
| 167 |
+
)
|
| 168 |
+
parser.add_argument(
|
| 169 |
+
"--hf-token",
|
| 170 |
+
type=str,
|
| 171 |
+
default=None,
|
| 172 |
+
help="Optional HF token. If omitted, app reads HF_TOKEN or HUGGINGFACE_HUB_TOKEN env vars.",
|
| 173 |
+
)
|
| 174 |
parser.add_argument("--port", type=int, default=7860)
|
| 175 |
parser.add_argument("--local", action="store_true", help="Bind to 127.0.0.1 instead of 0.0.0.0")
|
| 176 |
parser.add_argument("--share", action="store_true")
|
| 177 |
return parser.parse_args()
|
| 178 |
|
| 179 |
|
| 180 |
+
def _resolve_existing_file(path_value: Optional[str]) -> Optional[str]:
|
| 181 |
+
if not path_value:
|
| 182 |
+
return None
|
| 183 |
+
raw = Path(str(path_value)).expanduser()
|
| 184 |
+
candidates = [raw]
|
| 185 |
+
if not raw.is_absolute():
|
| 186 |
+
candidates.append(APP_ROOT / raw)
|
| 187 |
+
for p in candidates:
|
| 188 |
+
if p.is_file():
|
| 189 |
+
return str(p.resolve())
|
| 190 |
+
return None
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def _download_hf_checkpoint(filename: str) -> str:
|
| 194 |
+
if hf_hub_download is None:
|
| 195 |
+
raise RuntimeError(
|
| 196 |
+
"huggingface_hub is required to download checkpoints. Install it or provide local model paths."
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
kwargs: dict[str, Any] = {
|
| 200 |
+
"repo_id": RUNTIME_HF_REPO_ID,
|
| 201 |
+
"filename": filename,
|
| 202 |
+
}
|
| 203 |
+
if RUNTIME_HF_CACHE_DIR:
|
| 204 |
+
kwargs["cache_dir"] = RUNTIME_HF_CACHE_DIR
|
| 205 |
+
if RUNTIME_HF_TOKEN:
|
| 206 |
+
kwargs["token"] = RUNTIME_HF_TOKEN
|
| 207 |
+
|
| 208 |
+
try:
|
| 209 |
+
downloaded = hf_hub_download(**kwargs)
|
| 210 |
+
except Exception as exc:
|
| 211 |
+
raise RuntimeError(
|
| 212 |
+
f"Failed to download '{filename}' from '{RUNTIME_HF_REPO_ID}'. "
|
| 213 |
+
"Check repo, token permissions, and network availability."
|
| 214 |
+
) from exc
|
| 215 |
+
return str(Path(downloaded).resolve())
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def _resolve_checkpoint_path(config_value: Optional[str], pipeline_type: str, file_key: str) -> str:
|
| 219 |
+
if pipeline_type not in HF_MODEL_FILES:
|
| 220 |
+
raise ValueError(f"Unknown pipeline type for checkpoint resolution: {pipeline_type}")
|
| 221 |
+
if file_key not in HF_MODEL_FILES[pipeline_type]:
|
| 222 |
+
raise ValueError(f"Unknown checkpoint key '{file_key}' for pipeline type '{pipeline_type}'")
|
| 223 |
+
|
| 224 |
+
existing = _resolve_existing_file(config_value)
|
| 225 |
+
if existing is not None:
|
| 226 |
+
return existing
|
| 227 |
+
|
| 228 |
+
hf_file = HF_MODEL_FILES[pipeline_type][file_key]
|
| 229 |
+
print(f"[gQIR] Missing local checkpoint; downloading {RUNTIME_HF_REPO_ID}/{hf_file}")
|
| 230 |
+
return _download_hf_checkpoint(hf_file)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def _prepare_single_cfg_paths(cfg: Any, pipeline_type: str) -> Any:
|
| 234 |
+
cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=False))
|
| 235 |
+
if "model" not in cfg or "vae_cfg" not in cfg.model:
|
| 236 |
+
raise ValueError("Single-frame config missing model.vae_cfg")
|
| 237 |
+
|
| 238 |
+
qvae_path_cfg = None
|
| 239 |
+
if "qvae_path" in cfg.model.vae_cfg:
|
| 240 |
+
qvae_path_cfg = cfg.model.vae_cfg.qvae_path
|
| 241 |
+
if not qvae_path_cfg and "qvae_path" in cfg:
|
| 242 |
+
qvae_path_cfg = cfg.qvae_path
|
| 243 |
+
|
| 244 |
+
cfg.weight_path = _resolve_checkpoint_path(cfg.get("weight_path"), pipeline_type, "single_lora")
|
| 245 |
+
resolved_qvae = _resolve_checkpoint_path(qvae_path_cfg, pipeline_type, "single_qvae")
|
| 246 |
+
cfg.model.vae_cfg.qvae_path = resolved_qvae
|
| 247 |
+
if "qvae_path" in cfg:
|
| 248 |
+
cfg.qvae_path = resolved_qvae
|
| 249 |
+
return cfg
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def _prepare_burst_cfg_paths(cfg: Any, pipeline_type: str) -> Any:
|
| 253 |
+
cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=False))
|
| 254 |
+
cfg.qvae_path = _resolve_checkpoint_path(cfg.get("qvae_path"), pipeline_type, "burst_qvae")
|
| 255 |
+
cfg.unet_weight_path = _resolve_checkpoint_path(cfg.get("unet_weight_path"), pipeline_type, "burst_lora")
|
| 256 |
+
cfg.fusion_vit_weight_path = _resolve_checkpoint_path(
|
| 257 |
+
cfg.get("fusion_vit_weight_path"), pipeline_type, "burst_fusion"
|
| 258 |
+
)
|
| 259 |
+
if "model" in cfg and "vae_cfg" in cfg.model:
|
| 260 |
+
cfg.model.vae_cfg.qvae_path = cfg.qvae_path
|
| 261 |
+
return cfg
|
| 262 |
+
|
| 263 |
+
|
| 264 |
def _ensure_rgb_image(arr: np.ndarray) -> np.ndarray:
|
| 265 |
arr = np.asarray(arr)
|
| 266 |
if arr.ndim == 2:
|
|
|
|
| 504 |
|
| 505 |
|
| 506 |
class SingleColorPipeline:
|
| 507 |
+
def __init__(self, config_path: Path, device: str, pipeline_type: str):
|
| 508 |
self.config_path = config_path
|
| 509 |
self.device = device
|
| 510 |
+
self.pipeline_type = pipeline_type
|
| 511 |
self.max_size = DEFAULT_MAX_SIZE
|
| 512 |
self.model: Optional[SD2Enhancer] = None
|
| 513 |
|
|
|
|
| 515 |
if self.model is not None:
|
| 516 |
return
|
| 517 |
cfg = OmegaConf.load(str(self.config_path))
|
| 518 |
+
cfg = _prepare_single_cfg_paths(cfg, self.pipeline_type)
|
| 519 |
if cfg.base_model_type != "sd2":
|
| 520 |
raise ValueError(f"Unsupported base_model_type for single pipeline: {cfg.base_model_type}")
|
| 521 |
self.model = SD2Enhancer(
|
|
|
|
| 590 |
|
| 591 |
|
| 592 |
class BurstColorPipeline:
|
| 593 |
+
def __init__(self, config_path: Path, device: str, pipeline_type: str):
|
| 594 |
self.config_path = config_path
|
| 595 |
self.device = device
|
| 596 |
+
self.pipeline_type = pipeline_type
|
| 597 |
self.cfg = None
|
| 598 |
self.out_size = 512
|
| 599 |
self.weight_dtype = torch.bfloat16 if str(device).startswith("cuda") else torch.float32
|
|
|
|
| 611 |
return
|
| 612 |
|
| 613 |
cfg = OmegaConf.load(str(self.config_path))
|
| 614 |
+
cfg = _prepare_burst_cfg_paths(cfg, self.pipeline_type)
|
| 615 |
self.cfg = cfg
|
| 616 |
self.out_size = int(cfg.dataset.val.params.out_size)
|
| 617 |
|
|
|
|
| 634 |
dropout = False
|
| 635 |
|
| 636 |
raft_model = RAFT(RAFTArgs())
|
| 637 |
+
raft_path = APP_ROOT / "pretrained_ckpts" / "models" / "raft-things.pth"
|
| 638 |
raft_dict = torch.load(str(raft_path), map_location="cpu")
|
| 639 |
corrected = {}
|
| 640 |
for k, v in raft_dict.items():
|
|
|
|
| 817 |
_SINGLE_PIPELINES[pipeline_type] = SingleColorPipeline(
|
| 818 |
RUNTIME_SINGLE_CONFIGS[pipeline_type],
|
| 819 |
RUNTIME_DEVICE,
|
| 820 |
+
pipeline_type,
|
| 821 |
)
|
| 822 |
_SINGLE_PIPELINES[pipeline_type].load()
|
| 823 |
return _SINGLE_PIPELINES[pipeline_type]
|
|
|
|
| 833 |
_BURST_PIPELINES[pipeline_type] = BurstColorPipeline(
|
| 834 |
RUNTIME_BURST_CONFIGS[pipeline_type],
|
| 835 |
RUNTIME_DEVICE,
|
| 836 |
+
pipeline_type,
|
| 837 |
)
|
| 838 |
_BURST_PIPELINES[pipeline_type].load()
|
| 839 |
return _BURST_PIPELINES[pipeline_type]
|
|
|
|
| 1333 |
<a href="https://arxiv.org/abs/2602.20417">ArXiv</a> |
|
| 1334 |
<a href="https://github.com/Aryan-Garg/gQIR">GitHub</a>
|
| 1335 |
</p>
|
|
|
|
| 1336 |
### What You Can Run
|
| 1337 |
- **Single Frame (Stage-2):** Reconstruct one frame from either a clean GT image (internally simulated to SPAD) or a real SPAD frame.
|
| 1338 |
- **Burst (Stage-3):** Reconstruct from a fixed **77-frame** window using either GT videos/cubes or real photon cubes.
|
| 1339 |
- **Pipelines:** Toggle between **Color** and **Monochrome** reconstruction in both tabs.
|
|
|
|
| 1340 |
### Supported Inputs
|
| 1341 |
- **Single GT:** Standard image uploads.
|
| 1342 |
- **Single Real:** Real SPAD frame image uploads.
|
| 1343 |
- **Burst GT:** Public-friendly videos (`.mp4`, `.mov`, `.wmv`, `.avi`, `.mkv`, `.webm`) plus research cube formats (`.npy`, `.npz`, `.pt`, `.h5`) or image folders.
|
| 1344 |
- **Burst Real:** Photon cubes (`.npy`, `.npz`, `.pt`, `.h5`) or image folders.
|
|
|
|
| 1345 |
### Quick Usage
|
| 1346 |
1. Pick pipeline and input mode.
|
| 1347 |
2. Load input and select burst start index (for Stage-3).
|
|
|
|
| 1470 |
|
| 1471 |
def main() -> None:
|
| 1472 |
global RUNTIME_SINGLE_CONFIGS, RUNTIME_BURST_CONFIGS, RUNTIME_DEVICE, RUNTIME_BURST_OUT_SIZES
|
| 1473 |
+
global RUNTIME_HF_REPO_ID, RUNTIME_HF_CACHE_DIR, RUNTIME_HF_TOKEN
|
| 1474 |
|
| 1475 |
args = parse_args()
|
| 1476 |
single_color_cfg = Path(args.single_config if args.single_config else args.single_config_color).resolve()
|
| 1477 |
burst_color_cfg = Path(args.burst_config if args.burst_config else args.burst_config_color).resolve()
|
| 1478 |
single_mono_cfg = Path(args.single_config_mono).resolve()
|
| 1479 |
burst_mono_cfg = Path(args.burst_config_mono).resolve()
|
| 1480 |
+
hf_token = args.hf_token
|
| 1481 |
+
if not hf_token:
|
| 1482 |
+
hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_HUB_TOKEN")
|
| 1483 |
|
| 1484 |
RUNTIME_SINGLE_CONFIGS = {
|
| 1485 |
PIPELINE_COLOR: single_color_cfg,
|
|
|
|
| 1489 |
PIPELINE_COLOR: burst_color_cfg,
|
| 1490 |
PIPELINE_MONO: burst_mono_cfg,
|
| 1491 |
}
|
| 1492 |
+
RUNTIME_DEVICE = args.device
|
| 1493 |
+
RUNTIME_HF_REPO_ID = str(args.hf_repo_id or HF_DEFAULT_REPO_ID).strip()
|
| 1494 |
+
RUNTIME_HF_CACHE_DIR = str(Path(args.hf_cache_dir).expanduser()) if args.hf_cache_dir else None
|
| 1495 |
+
RUNTIME_HF_TOKEN = hf_token
|
| 1496 |
RUNTIME_BURST_OUT_SIZES = {}
|
| 1497 |
for key, cfg_path in RUNTIME_BURST_CONFIGS.items():
|
| 1498 |
burst_cfg = OmegaConf.load(str(cfg_path))
|