CameraVLM

When Left Is Right? Camera-Motion Understanding beyond Screen

Chong Cheng1,2*Ran Zhang2§Xinyuan Li2Alan Zhao2Hao Wang1†Xi Wang3

1The Hong Kong University of Science and Technology (Guangzhou)2Tencent3LIX, Ecole Polytechnique, IP Paris

* Work done during an internship at Tencent  ·  † Corresponding author  ·  § Project leader  ·  Joint supervision: Hao Wang and Xi Wang

Give CameraVLM a video. It reports how the camera moved.

1Input video
2CameraVLM output
Which camera movement best describes this shot?
ATrucking Right Shot
BTrucking Left Shot
CZoom In Shot
DDolly In Shot, then adds Trucking Left Shot
3Camera poseoff screen
4Point flowon screen

Overview

With 9B parameters, CameraVLM matches or surpasses GPT-6 Astra on average.

Camera, flow and language. Camera states describe how the camera moves off screen; flow states describe what moves on screen; the language model reads both to answer.
Average accuracy vs. model size
Mean accuracy over CameraBench, CineTechBench and ShotBench. The dashed line is the Pareto front of existing models; CameraVLM lies above it. Parameter counts of closed-source models are estimated.

Abstract

Can a vision–language model tell left from right? Modern VLMs solve visual puzzles and follow hour-long videos, yet when asked whether the camera moved left or right, most do no better than a coin flip. Adding camera-motion data or geometric representations has been tried, separately, and neither closes the gap. We argue that camera-motion understanding needs two conditions at once: the representation must couple off-screen camera motion with on-screen flow dynamics, and it must be interpreted by the language model rather than trained as a standalone pose or depth estimator. We propose CameraVLM, which pairs a motion-state representation with state–language alignment. Camera tokens capture how the camera moves off screen, flow tokens capture how the subject and background move on screen, and a two-stage training strategy keeps language in the loop so that both are learned together with camera-motion semantics. With only 9B parameters, CameraVLM outperforms all open-source and camera-motion-specific models by a wide margin across three benchmarks and more than 20 baselines, and matches or surpasses GPT-6 Astra as well as human viewers in a 48-participant study.

Asked whether the camera moved left or right, most VLMs do no better than a coin flip. We argue that camera-motion understanding needs two conditions at once: a representation that couples off-screen camera motion with on-screen flow dynamics, and a language model that interprets it. CameraVLM meets both with camera tokens, flow tokens and a two-stage state–language alignment. With only 9B parameters, it outperforms all open-source and camera-motion-specific models on three benchmarks, and matches or surpasses GPT-6 Astra and human viewers.

The problem

Most VLMs cannot tell left from right. CameraVLM can.

Why it is hard. The same scene gives opposite directions under different references, and different camera motions look alike on screen.
Accuracy on left/right questions (%)
Only GPT-6 Astra and CameraVLM (9B) come close to human viewers; the other models stay near chance.

Method

Camera tokens and flow tokens, read by one language model.

Two conditions, met at once

1

Couple the off-screen camera with the on-screen flow in one representation.

2

Let the language model read it under the reference the question gives.

Architecture. Camera, vision, flow and question tokens are jointly contextualized by the shared backbone. The Camera Head predicts camera parameters, the flow pathway predicts trajectories, visibility and confidence, and the LM Head answers under the query.

Camera states

One learnable token per frame; a Camera Head decodes per-frame pose.

Flow states

Point tracks from the vision encoder's features, pooled into flow tokens.

Two-stage alignment

Stage 1 aligns the new states with a frozen LLM; stage 2 trains everything jointly.

At inference, CameraVLM takes only the video and the question.

Examples

Same clip, same question: CameraVLM gets the camera move right.

    Benchmarks

    State-of-the-art average accuracy on three benchmarks.

    Accuracy (%). Bold: best per column; underline: second best (human study excluded from ranking).

    By motion type

    Strong across all eight camera-motion types.

    Accuracy per camera-motion category (%)
    Pooled accuracy (%)

    Applications

    From one video, CameraVLM writes the shot description and its attributes.

    Input video
    CameraVLM output

    Description

    Shot attributes

    Applications

    From previs to final render, CameraVLM describes both shots.

    Previsualization
    CameraVLM output

    Description

    Final render
    CameraVLM output

    Description

    Citation

    Cite CameraVLM.

    BibTeX

    @article{cheng2026cameravlm,
      title   = {When Left Is Right? Camera-Motion
                 Understanding beyond Screen},
      author  = {Cheng, Chong and Zhang, Ran and Li, Xinyuan
                 and Zhao, Alan and Wang, Hao and Wang, Xi},
      journal = {arXiv preprint arXiv:2610.17242},
      year    = {2026},
      url     = {https://arxiv.org/abs/2610.17242}
    }

    Use CameraVLM via API

    The hosted Hugging Face demo exposes one endpoint, /predict. It returns the text answer and an .npz file with per-frame camera poses and point tracks.

    Install
    pip install gradio_client numpy
    Python
    import numpy as np
    from gradio_client import Client, handle_file
    
    # a Hugging Face token raises your GPU quota
    client = Client("NicolasCC/CameraVLM", token="hf_...")
    
    answer, geometry = client.predict(
        video=handle_file("video.mp4"),  # local path or URL
        task="question",                 # "question" | "camera_motion"
        prompt="How does the camera move relative to the car?",
        num_frames=128,                  # 2–128 frames, sampled uniformly
        api_name="/predict",
    )
    print(answer)
    
    g = np.load(geometry)
    g["camera_to_world"]  # (S, 4, 4) per-frame camera poses
    g["intrinsics"]       # (S, 3, 3)
    g["tracks"]           # (S/2, 256, 2) point tracks in pixels

    With task="camera_motion" the answer is a JSON string with primary_motion, secondary_motion, direction, evidence and confidence; prompt is ignored. Full field list in the GitHub README.