Download app.py from Rausda6/Handheld: direct link, hf CLI and curl.
- Browser
- Download file 2.51 kB
-
https://huggingface.co/spaces/Rausda6/Handheld/resolve/main/app.py
- Command line
-
hf download hf://spaces/Rausda6/Handheld/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Rausda6/Handheld/resolve/main/app.py
2.51 kB
| """Minimal Gradio frontend for raw burst reconstruction.""" | |
| from pathlib import Path | |
| import shutil | |
| import tempfile | |
| import spaces | |
| import gradio as gr | |
| import numpy as np | |
| def reconstruct(files, scale): | |
| # Import CUDA modules only after a GPU has been allocated. | |
| from handheld_super_resolution.config import Config | |
| from handheld_super_resolution.monte_carlo import generate_noise_lut | |
| from handheld_super_resolution.noise_lut import save_noise_lut | |
| from handheld_super_resolution.utils_dng import read_dng_noise_profile | |
| from handheld_super_resolution.super_resolution import process | |
| with tempfile.TemporaryDirectory(prefix="handheld-") as directory: | |
| burst = Path(directory) | |
| for index, source in enumerate(sorted(files, key=lambda p: Path(p).name)): | |
| shutil.copyfile(source, burst / f"{index:04d}.dng") | |
| alpha, beta = read_dng_noise_profile(burst / "0000.dng") | |
| lut = generate_noise_lut(alpha, beta, show_progress=False) | |
| lut_path = burst / "noise.npz" | |
| save_noise_lut(lut_path, lut, trials=10_000_000, seed=0) | |
| config = Config(scale=float(scale)) | |
| config.noise_model.lut_path = lut_path | |
| config.robustness.save_mask = False | |
| result, _ = process(burst, config) | |
| return np.round(np.clip(np.nan_to_num(result), 0, 1) * 255).astype(np.uint8) | |
| def run(files, scale): | |
| if not files or len(files) < 2: | |
| raise gr.Error("Upload at least two DNG images from the same burst.") | |
| if any(Path(path).suffix.lower() != ".dng" for path in files): | |
| raise gr.Error("This pipeline accepts raw DNG images.") | |
| try: | |
| return reconstruct(files, scale) | |
| except Exception as error: | |
| raise gr.Error(f"Reconstruction failed: {error}") from error | |
| with gr.Blocks(delete_cache=(3600, 3600)) as demo: | |
| gr.Markdown("# Handheld Super-Resolution\nUpload raw DNG images from one burst. " | |
| "The first image alphabetically is the reference. " | |
| "Noise calibration is automatic; the first run may take longer.") | |
| images = gr.File(label="DNG burst", file_count="multiple", file_types=[".dng"], type="filepath") | |
| scale = gr.Radio([1, 2], value=2, label="Output scale") | |
| button = gr.Button("Reconstruct", variant="primary") | |
| result = gr.Image(label="Result", format="png") | |
| button.click(run, inputs=[images, scale], outputs=result, concurrency_limit=1) | |
| if __name__ == "__main__": | |
| demo.queue(max_size=8).launch() | |