Spaces:
Sleeping
Sleeping
| """OracleZoom demo: upload a photo, watch it zoom 4x to 256x.""" | |
| import gradio as gr | |
| import spaces | |
| from PIL import Image, ImageDraw | |
| import geometry | |
| import video | |
| import zoom | |
| MODELS = zoom.Models() | |
| UPSCALE = 4 | |
| ACCENT = "#f5b942" | |
| LABELS = {1: "input", 4: "4x", 16: "16x", 64: "64x", 256: "256x"} | |
| SAMPLES = ["0479", "0064", "0245", "0393", "0457"] | |
| # Shipped output of a real run, so the page shows the payoff before anyone spends any quota. | |
| EXAMPLE_CLIP = "samples/example_zoom.mp4" | |
| EXAMPLE_LEVELS = [("samples/example_1x.png", "input")] + \ | |
| [(f"samples/example_{f}x.png", f"{f}x") for f in (4, 16, 64, 256)] | |
| EXAMPLE_COMPARE = ("samples/example_256x_input.png", "samples/example_256x.png") | |
| EXAMPLE_NOTE = "_An example run. Upload a photo above to make your own._" | |
| HEADER = """ | |
| <div style="text-align:center;max-width:820px;margin:0 auto 4px"> | |
| <h1 style="margin:0;font-size:2.1em;letter-spacing:-.02em">OracleZoom 🔎</h1> | |
| <p style="margin:.5em 0 .9em;font-size:1.08em;line-height:1.5;opacity:.85"> | |
| Zoom into any photo far past what it holds. Four steps of 4x take you to | |
| <b>256x</b>, each one drawn from the last. | |
| </p> | |
| <p style="margin:0;font-size:.95em"> | |
| <a href="https://arxiv.org/abs/2609.06490">Paper</a> · | |
| <a href="https://github.com/dipta007/OracleZoom">Code</a> · | |
| <a href="https://dipta007.github.io/OracleZoom/">Project page</a> · | |
| <a href="https://huggingface.co/dipta007/OracleZoom">Model</a> | |
| </p> | |
| </div> | |
| """ | |
| HOW = """ | |
| ##### How it goes | |
| 1. Crop your photo to a 512 square. | |
| 2. Zoom 4x into the amber box. That crop is blurry, so a vision language model describes it. | |
| 3. Super-resolve it with that description as the guide. | |
| 4. Repeat on the result. Four rounds reach 256x. | |
| Runs free on ZeroGPU, so the first zoom after a quiet spell waits for a GPU. | |
| """ | |
| FOOTER = """ | |
| ### What you are looking at | |
| Standard super-resolution models break down well before 16x. OracleZoom gets to 256x by | |
| zooming one 4x step at a time and feeding each result into the next step. At every step a | |
| vision language model writes a short description of the crop, and that description guides | |
| the detail the super-resolution model draws. | |
| Past the first step or two there is no ground truth to recover, so the deep levels are | |
| **plausible detail, not measured detail**. The zoom point is a crop of your photo, not a | |
| real camera lens moving closer. Read the paper for what we do and do not claim. | |
| ```bibtex | |
| @inproceedings{dipta2027oraclezoom, | |
| title = {OracleZoom: Reference-Constrained Recursive Super-Resolution}, | |
| author = {Roy Dipta, Shubhashis and Saha, Sourajit and Saha, Shaswati and Sarwar, Nobin}, | |
| year = {2027} | |
| } | |
| ``` | |
| """ | |
| CSS = """ | |
| #hero video {border-radius:12px} | |
| .contain {max-width:1400px !important} | |
| footer {display:none !important} | |
| """ | |
| def preview(image, levels, cx, cy): | |
| """Show where the zoom will go, so nobody spends a run to find out.""" | |
| if image is None: | |
| return None | |
| canvas = geometry.resize_and_center_crop(image).convert("RGB") | |
| rects = geometry.nested_rects(canvas.size, int(levels), UPSCALE, (cx, cy)) | |
| dimmed = Image.blend(canvas, Image.new("RGB", canvas.size, (0, 0, 0)), 0.45) | |
| dimmed.paste(canvas.crop(rects[0]), rects[0][:2]) | |
| draw = ImageDraw.Draw(dimmed) | |
| for rect in rects: | |
| if rect[2] - rect[0] >= 3: | |
| draw.rectangle(rect, outline=ACCENT, width=2) | |
| return dimmed | |
| def pick_point(evt: gr.SelectData): | |
| x, y = evt.index | |
| return x / geometry.PROCESS_SIZE, y / geometry.PROCESS_SIZE | |
| def estimate_duration(image, levels, cx, cy): | |
| # Checked against the visitor's remaining quota BEFORE the run, so a loose number locks | |
| # out low-quota visitors, and a tight one gets the run killed mid-way. Provisional until | |
| # measured on the real hardware. | |
| return int(15 + 9 * int(levels)) | |
| def _stream(image, levels, cx, cy): | |
| if image is None: | |
| raise gr.Error("Upload a photo first.") | |
| levels = int(levels) | |
| gallery, prompts, frames, compare = [], [], [], None | |
| for step, factor, prompt, blurry, result in zoom.zoom(MODELS, image, levels, UPSCALE, (cx, cy)): | |
| frames.append(result) | |
| gallery.append((result, LABELS.get(factor, f"{factor}x"))) | |
| if step: | |
| compare = (blurry, result) | |
| prompts.append(f"**{LABELS[factor]}** {prompt or '_(no prompt)_'}") | |
| left = levels - step | |
| if not step: | |
| status = f"Warmed up. Zooming {levels} step{'s' if levels > 1 else ''}…" | |
| elif left: | |
| status = f"At **{LABELS[factor]}**, {left} step{'s' if left > 1 else ''} to go…" | |
| else: | |
| status = f"At **{LABELS[factor]}**. Rendering the clip…" | |
| # First yield clears any clip left from the previous run; later ones leave it alone. | |
| yield status, (None if not step else gr.skip()), gallery, compare, "\n\n".join(prompts) | |
| yield ("Done. 🔎", video.render(frames, UPSCALE, (cx, cy)), gallery, compare, | |
| "\n\n".join(prompts)) | |
| def run(image, levels, cx, cy): | |
| yield from _stream(image, levels, cx, cy) | |
| def run_example(image): | |
| """One input, so the examples render as thumbnails instead of a four-column table. | |
| Its results are cached, which is how a visitor with no quota left still sees output.""" | |
| yield from _stream(image, 4, 0.5, 0.5) | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber"), css=CSS, | |
| title="OracleZoom: zoom to 256x") as demo: | |
| gr.HTML(HEADER) | |
| with gr.Row(): | |
| with gr.Column(scale=4): | |
| image = gr.Image(label="Your photo", type="pil", height=300, sources=["upload", "clipboard"]) | |
| # Seeded with the example so the box overlay explains itself before any upload. | |
| target = gr.Image(value=preview(Image.open(EXAMPLE_LEVELS[0][0]), 4, 0.5, 0.5), | |
| label="Click to move the zoom point", type="pil", | |
| interactive=False, height=340, show_download_button=False) | |
| levels = gr.Slider(1, 4, value=4, step=1, label="Zoom steps", | |
| info="1 step = 4x, 4 steps = 256x. Fewer steps finish sooner.") | |
| with gr.Accordion("Set the point by hand", open=False): | |
| cx = gr.Slider(0, 1, value=0.5, step=0.01, label="Horizontal") | |
| cy = gr.Slider(0, 1, value=0.5, step=0.01, label="Vertical") | |
| go = gr.Button("🔎 Zoom in", variant="primary", size="lg") | |
| gr.Markdown(HOW) | |
| with gr.Column(scale=6): | |
| status = gr.Markdown("Upload a photo, then press **Zoom in**.") | |
| clip = gr.Video(value=EXAMPLE_CLIP, label="The zoom", elem_id="hero", autoplay=True, | |
| loop=True, show_share_button=True, height=400) | |
| gallery = gr.Gallery(value=EXAMPLE_LEVELS, label="Every level", columns=5, height=175, | |
| object_fit="cover", show_download_button=True) | |
| compare = gr.ImageSlider(value=EXAMPLE_COMPARE, height=400, | |
| label="256x: plain enlargement (left) vs OracleZoom (right)") | |
| gr.Markdown("##### What the model said it saw, step by step") | |
| prompts = gr.Markdown(EXAMPLE_NOTE) | |
| controls = [image, levels, cx, cy] | |
| for c in controls: | |
| c.change(preview, controls, target, show_api=False) | |
| target.select(pick_point, None, [cx, cy], show_api=False) | |
| go.click(run, controls, [status, clip, gallery, compare, prompts]) | |
| gr.Examples( | |
| examples=[f"samples/{n}.png" for n in SAMPLES], | |
| inputs=[image], | |
| outputs=[status, clip, gallery, compare, prompts], | |
| fn=run_example, | |
| cache_examples=True, | |
| label="Or try one of these (already computed, costs you nothing)", | |
| ) | |
| gr.Markdown(FOOTER) | |
| if __name__ == "__main__": | |
| demo.queue(max_size=20).launch() | |