CoolFace
Datasetpublic

facebook/actionbench

🎬 ActionBench: Paired Video-3D Synthetic Benchmark 📖 Overview ActionBench is a benchmark dataset of 128 paired video ↔ animated point-cloud samples for evaluating animated 3D mesh generation from video. The dataset consists of synthetic scenes of animated objects from ObjaverseXL, rendered using Blender 3.5.1. Each sample contains: Video: 16 RGBA frames with alpha mask Camera (camera.json): Camera parameters using Blender convention (X_cam = X @ R^T + T, camera looks… See the full description on the dataset page: https://huggingface.co/datasets/facebook/actionbench.

sourceHugging Faceotherupdated 4mo agoView on Hugging Face
9likes1.2kdownloads
projection.py95 linesDownload Raw Back to root
1"""Project animated point cloud onto image using camera parameters."""2 3import json4 5import numpy as np6from PIL import Image7from scipy.ndimage import gaussian_filter8 9 10def project_points(11    points: np.ndarray, camera: dict, img_size: int12) -> tuple[np.ndarray, np.ndarray]:13    """Project 3D points to pixel coordinates.14 15    Uses Blender camera convention:16      X_cam = points @ R^T + T, camera looks along -Z.17 18    Args:19        points: (N, 3) world-space points.20        camera: dict with R, T, focal_length_ndc, principal_point_ndc.21        img_size: output image resolution (square).22 23    Returns:24        (x_pixels, y_pixels): each (N,) array of pixel coordinates.25    """26    R = np.asarray(camera["R"], dtype=np.float64)27    T = np.asarray(camera["T"], dtype=np.float64)28    focal = camera["focal_length_ndc"]29    pp = camera["principal_point_ndc"]30 31    X_cam = points @ R.T + T32    depth = -X_cam[:, 2]33    Z = np.clip(depth, 1e-4, None)34 35    x_ndc = focal[0] * X_cam[:, 0] / Z + pp[0]36    y_ndc = focal[1] * X_cam[:, 1] / Z + pp[1]37 38    x_px = img_size / 2.0 * (1.0 + x_ndc)39    y_px = img_size / 2.0 * (1.0 - y_ndc)40    return x_px, y_px41 42 43def render_projection(44    image: Image.Image, x_px: np.ndarray, y_px: np.ndarray, img_size: int45) -> np.ndarray:46    """Overlay projected points as a heatmap on an image.47 48    Returns:49        (H, W, 3) float32 blended image in [0, 1].50    """51    valid = (x_px >= 0) & (x_px < img_size) & (y_px >= 0) & (y_px < img_size)52    mask = np.zeros((img_size, img_size), dtype=np.float32)53    mask[y_px[valid].astype(int), x_px[valid].astype(int)] = 1.054    mask = np.clip(gaussian_filter(mask, sigma=1.5) * 5.0, 0, 1)55 56    img_np = np.array(image.convert("RGB")).astype(np.float32) / 255.057    overlay = np.array([1.0, 0.3, 0.1])58    alpha = 0.4 * mask[..., None]59    blended = img_np * (1 - alpha) + overlay * alpha60    return np.clip(blended, 0, 1)61 62 63if __name__ == "__main__":64    import argparse65 66    parser = argparse.ArgumentParser(description="Project point cloud onto an image.")67    parser.add_argument("--image", required=True, help="Path to input image")68    parser.add_argument("--points", required=True, help="Path to surfaces.npy (T,V,6)")69    parser.add_argument(70        "-t",71        "--timestep",72        type=int,73        default=0,74        help="Keyframe index to project (default: 0)",75    )76    parser.add_argument("--camera", required=True, help="Path to camera.json")77    parser.add_argument("--output", required=True, help="Path to output image")78    args = parser.parse_args()79 80    # (T, V, 6) -> take keyframe t, xyz only81    surfaces = np.load(args.points)82    points = surfaces[args.timestep, :, :3].astype(np.float64)83 84    with open(args.camera) as f:85        camera = json.load(f)86    image = Image.open(args.image)87    img_size = image.size[0]88 89    x_px, y_px = project_points(points, camera, img_size)90    result = render_projection(image, x_px, y_px, img_size)91 92    out = Image.fromarray((result * 255).astype(np.uint8))93    out.save(args.output)94    print(f"Saved projection to {args.output}")95