Spaces:
Sleeping
Sleeping
| import os | |
| # Must be set BEFORE importing cv2 to enable the EXR codec. | |
| os.environ.setdefault("OPENCV_IO_ENABLE_OPENEXR", "1") | |
| import tempfile | |
| import spaces | |
| import gradio as gr | |
| import numpy as np | |
| import torch | |
| import cv2 | |
| import tifffile | |
| import matplotlib | |
| from PIL import Image | |
| from transformers import AutoImageProcessor, AutoModelForDepthEstimation | |
| MODEL_ID = "LiheYoung/depth-anything-large-hf" | |
| processor = AutoImageProcessor.from_pretrained(MODEL_ID) | |
| model = AutoModelForDepthEstimation.from_pretrained(MODEL_ID) | |
| model.eval() | |
| cmap = matplotlib.colormaps.get_cmap("Spectral_r") | |
| def _write_exr(path, depth_f32): | |
| """Write single-value float32 depth to EXR (RGB channels all = depth). | |
| Try OpenCV first, then the OpenEXR package. Return path or None.""" | |
| try: | |
| ok = cv2.imwrite(path, depth_f32) # cv2 writes float32 -> EXR | |
| if ok and os.path.exists(path) and os.path.getsize(path) > 0: | |
| return path | |
| except Exception as e: | |
| print("cv2 EXR write failed:", e) | |
| try: | |
| import OpenEXR, Imath | |
| h, w = depth_f32.shape | |
| header = OpenEXR.Header(w, h) | |
| ftype = Imath.Channel(Imath.PixelType(Imath.PixelType.FLOAT)) | |
| header["channels"] = {c: ftype for c in ("R", "G", "B")} | |
| out = OpenEXR.OutputFile(path, header) | |
| buf = np.ascontiguousarray(depth_f32).tobytes() | |
| out.writePixels({"R": buf, "G": buf, "B": buf}) | |
| out.close() | |
| return path | |
| except Exception as e: | |
| print("OpenEXR write failed:", e) | |
| return None | |
| def predict_depth(image: Image.Image): | |
| if image is None: | |
| return None, [] | |
| image = image.convert("RGB") | |
| model.to("cuda") | |
| inputs = processor(images=image, return_tensors="pt").to("cuda") | |
| outputs = model(**inputs) | |
| predicted_depth = outputs.predicted_depth | |
| prediction = torch.nn.functional.interpolate( | |
| predicted_depth.unsqueeze(1), | |
| size=image.size[::-1], # (H, W) | |
| mode="bicubic", | |
| align_corners=False, | |
| ).squeeze() | |
| # Raw float32 depth (full precision, NOT normalized) for TIFF/EXR. | |
| depth = prediction.detach().cpu().numpy().astype(np.float32) | |
| dmin, dmax = float(depth.min()), float(depth.max()) | |
| norm = (depth - dmin) / (dmax - dmin + 1e-8) # 0..1 for preview + 16-bit PNG | |
| # 8-bit colored preview (display only β precision doesn't matter here). | |
| colored = Image.fromarray((cmap(norm)[:, :, :3] * 255).astype(np.uint8)) | |
| tmp = tempfile.mkdtemp(prefix="depth_") | |
| png16_path = os.path.join(tmp, "depth_16bit.png") | |
| tiff_path = os.path.join(tmp, "depth_float32.tiff") | |
| exr_path = os.path.join(tmp, "depth_float32.exr") | |
| # 16-bit PNG: normalized depth mapped to the full 0..65535 range. | |
| cv2.imwrite(png16_path, (norm * 65535.0).astype(np.uint16)) | |
| # 32-bit float TIFF: raw depth, fully lossless. | |
| tifffile.imwrite(tiff_path, depth) | |
| # 32-bit float EXR: raw depth (best-effort). | |
| exr_ok = _write_exr(exr_path, depth) | |
| files = [png16_path, tiff_path] | |
| if exr_ok: | |
| files.append(exr_ok) | |
| return colored, files | |
| title = "# Depth Anything (ZeroGPU) β high-bit-depth export" | |
| description = ( | |
| "Monocular depth with Depth-Anything-Large on ZeroGPU.\n\n" | |
| "**Downloads preserve full precision** β the colored image is an 8-bit preview only:\n" | |
| "- `depth_16bit.png` β 16-bit grayscale, depth normalized to 0β65535\n" | |
| "- `depth_float32.tiff` β 32-bit float, raw depth values (lossless)\n" | |
| "- `depth_float32.exr` β 32-bit float OpenEXR, raw depth values" | |
| ) | |
| with gr.Blocks(title="Depth Anything") as demo: | |
| gr.Markdown(title) | |
| gr.Markdown(description) | |
| with gr.Row(): | |
| input_image = gr.Image(label="Input", type="pil") | |
| depth_color = gr.Image(label="Depth (colored preview, 8-bit)", type="pil") | |
| downloads = gr.Files(label="High-bit-depth downloads (PNG16 / TIFF32 / EXR32)") | |
| run = gr.Button("Compute depth", variant="primary") | |
| run.click(fn=predict_depth, inputs=input_image, outputs=[depth_color, downloads]) | |
| if __name__ == "__main__": | |
| demo.queue().launch() | |