Spaces:
Running on Zero
A newer version of the Gradio SDK is available: 6.24.0
title: Double Exposure Recovery
emoji: 🎞️
colorFrom: indigo
colorTo: gray
sdk: gradio
sdk_version: 6.19.0
app_file: space_app.py
pinned: false
Double Exposure Recovery
Recover the two original images from an accidentally double-exposed film negative. Upload a scan of the combined negative; the app proposes multiple physically-consistent scene separations, ranks them with a hybrid physics + perceptual loss, and returns the best reconstruction.
Results are best-effort AI reconstructions, not perfect recoveries. Perfect separation is information-theoretically impossible in many cases — the goal is the most plausible reconstruction consistent with the observed film densities and natural-image statistics.
How it works
Recovery is treated as an inverse problem grounded in film physics. Two exposures add
linearly in light energy on the emulsion, so after densitometry (inverting the
Hurter–Driffield characteristic curve) the total exposure Ĥ = H₁ + H₂ is directly
measurable per pixel. The problem then reduces to splitting a known non-negative field — the
same structure as single-image reflection removal — where priors do the disambiguation.
Candidate sources (all ranked by the same hybrid loss):
- Heuristic splits — fast percentile/spatial baselines (the offline demo floor).
- Residual demixing + VLM front-end — a physics-grounded alternating loop; uses hosted image/VLM models when API keys are present.
- Double-DIP — two small untrained CNNs optimized per-image against the film physics. Fully offline, no API key. On the 50-case 256px benchmark this is the strongest offline source (beats the heuristics in 37/45 cases). Opt-in in the UI (slower: ~1–2 min/image).
- Optional physics-guided refinement of the best candidate (opt-in; re-score gated so it never returns a result worse than its input on the ranking objective).
Running locally
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # optional: add REPLICATE_API_TOKEN / ANTHROPIC_API_KEY
python -m app.main # serves on http://127.0.0.1:7860
Demo mode works with no API keys — the heuristic and Double-DIP sources are fully offline. API keys unlock the generative demixing candidates.
Tests
pytest -m "not slow" # fast offline suite (~10 s)
pytest # includes the slow VAE-path test (downloads weights once)
Project layout
film_physics.py— differentiablePiecewiseFilmCurve(H&D curve) + stock presets.densitometry.py— scan → density → exposure, B&W and per-channel color.hybrid_loss.py— physics + LPIPS + anti-degeneracy loss (scoring and refinement).latent_optimizer.py— gradient-based refinement (VAE latent or pixel fallback).baselines/double_dip.py— the Double-DIP offline source.app/— Gradio UI, preprocessing, candidate generation, ranking.synth/— synthetic benchmark + metrics.MASTERPLAN.md— the binding technical strategy and work-package log.docs/WP9_DESIGN.md— design for projection-guided diffusion sampling (not yet built).
Deployment
See DEPLOY.md. The repo is Hugging Face Spaces–ready (the header above
configures the Space); the free CPU tier runs demo mode, and API keys are supplied via Space
secrets, never committed.