Prompt-Depth-Anything-Large / image_processing_prompt_depth_anything.py
bigshanedogg's picture
Upload Prompt-Depth-Anything-Large (transformers port, original code)
d92a7a8 verified
Raw History Blame Contribute Delete
4.01 kB
"""Prompt Depth Anything preprocessing: the official ``load_image`` / ``load_depth`` (promptda/utils/io_wrapper.py @
9161547c) behind the transformers image-processor interface. That module also imports open3d / matplotlib for
visualisation, so its two loaders are re-typed here line by line (checked bit-exact against the originals).
Image: RGB in [0, 1] (the model normalises it), longer side at most ``max_size`` (cv2 INTER_AREA, sides floored to
multiples of 14). A path is read with imageio, as the original. Prompt depth: meters, (h, w); a .png path is
millimeters (/ 1000), a .npz path holds "depth", as the original."""
import cv2
import imageio
import numpy as np
import torch
from PIL import Image
from transformers.feature_extraction_utils import BatchFeature
from transformers.image_processing_utils import BaseImageProcessor
def _to_tensor(arr): # io_wrapper.to_tensor_func
if arr.ndim == 2:
arr = arr[:, :, np.newaxis]
return torch.from_numpy(arr).permute(2, 0, 1).unsqueeze(0)
def _ensure_multiple_of(x, multiple_of=14): # io_wrapper.ensure_multiple_of
return int(x // multiple_of * multiple_of)
class PromptDepthAnythingImageProcessor(BaseImageProcessor):
model_input_names = ["pixel_values", "prompt_depth"]
def __init__(self, max_size: int = 1008, **kwargs):
super().__init__(**kwargs)
self.max_size = max_size
def load_image(self, image, max_size: int, multiple_of: int = 14):
# io_wrapper.load_image, also taking a PIL image / RGB uint8 array
if isinstance(image, str):
image = np.asarray(imageio.imread(image)).astype(np.float32)
else:
image = np.asarray(image.convert("RGB") if isinstance(image, Image.Image) else image).astype(np.float32)
image = image / 255.
max_size = max_size // multiple_of * multiple_of
if max(image.shape) > max_size:
h, w = image.shape[:2]
scale = max_size / max(h, w)
tar_h = _ensure_multiple_of(h * scale)
tar_w = _ensure_multiple_of(w * scale)
image = cv2.resize(image, (tar_w, tar_h), interpolation=cv2.INTER_AREA)
return _to_tensor(image)
@staticmethod
def load_depth(depth):
# io_wrapper.load_depth, also taking an array / tensor in meters
if isinstance(depth, str):
if depth.endswith('.png'):
depth = np.asarray(imageio.imread(depth)).astype(np.float32)
depth = depth / 1000.
elif depth.endswith('.npz'):
depth = np.load(depth)['depth']
else:
raise ValueError(f"Unsupported depth format: {depth}")
elif isinstance(depth, torch.Tensor):
depth = depth.cpu().numpy()
return _to_tensor(np.asarray(depth))
def preprocess(self, images, prompt_depth=None, max_size: int | None = None, return_tensors=None, **kwargs) -> BatchFeature:
"""images: one image or a list (paths, PIL images or RGB uint8 arrays); prompt_depth: one depth map per image
(paths, or arrays in meters). pixel_values (B, 3, H, W) in [0, 1]; prompt_depth (B, 1, h, w)."""
if not isinstance(images, (list, tuple)):
images = [images]
tensors = [self.load_image(image, max_size or self.max_size)[0] for image in images]
if len({t.shape for t in tensors}) > 1:
raise ValueError("images resize to different shapes; process them one at a time")
data = {"pixel_values": torch.stack(tensors)}
if prompt_depth is not None:
if not isinstance(prompt_depth, (list, tuple)):
prompt_depth = [prompt_depth]
if len(prompt_depth) != len(images):
raise ValueError("give one prompt depth per image")
data["prompt_depth"] = torch.stack([self.load_depth(depth)[0] for depth in prompt_depth])
return BatchFeature(data, tensor_type=return_tensors)
__all__ = ["PromptDepthAnythingImageProcessor"]