A browser-based educational visualizer for understanding how OpenCV pinhole camera calibration parameters map to Three.js/WebGL rendering.
The app shows the same calibrated scene from two views:
- Observer View: an external 3D view of the camera, frustum, helper planes, rays, and world objects.
- Camera Image View: the rendered image produced by the calibrated camera.
It is organized as a set of labs. The current labs are:
Camera Projection Lab: camera calibration and projection inspectionRender Lab: independent rendering playground for comparing WebGL reference output with CPU rasterization modes
npm install
npm run devOpen the local Vite URL printed by the dev server, usually:
http://localhost:5173/
Run tests with:
npm testBuild a production bundle with:
npm run build- OpenCV intrinsic matrix
K = [fx skew cx; 0 fy cy; 0 0 1] - OpenCV world-to-camera extrinsics
[R | t] - Why
tis not the camera position - Camera pose as world-space camera center plus orientation
- OpenCV camera coordinates:
+Xright,+Ydown,+Zforward - Conversion from OpenCV camera space to Three.js/WebGL camera space
- WebGL projection matrix construction from
K, image size, near, and far - CPU projection checks against the WebGL-rendered camera image
- Physical camera interpretation through sensor size, pixel size, and focal length in mm
The main canvas is split into two panes:
Observer Viewfor camera helpers and the 3D sceneCamera Image Viewfor the calibrated render target
Use the top-left Change Lab menu to switch between independent labs. Switching labs disposes the active lab and mounts a fresh instance of the next lab.
The parameter editor is below the views and is split into focused panels:
Physical Camera: sensor width/height, focal length in mm, derived pixel sizeOpenCV Intrinsics: image size,fx,fy, FOV,cx,cy,skewRendering / Clipping: WebGLnearandfarCamera Pose (World): world-space camera center and yaw/pitch/rollPoint Inspector: user-defined world points and their projection valuesMatrix Inspector: computedK,R,t,[R | t], and WebGL matrices
The Render Lab keeps the same split view layout, but its Camera Image View includes a render-mode selector for WebGL Reference and CPU Raster. When CPU Raster is selected, a separate pipeline visualization selector exposes vertex projection, frustum clipping, triangle assembly, barycentric coverage, the depth buffer, and the final color buffer. Optional pixel grid and pixel-center overlays make the raster sampling step visible, and the Pixel Inspector can lock a sampled pixel to show its CPU pipeline trace.
Observer helpers can be toggled individually:
- Camera body
- Lens front
- CV axes
- Near image plane
- Normalized image plane
- Image axes
- Sensor plane
- Sensor axes
- Focal length
- Frustum
- Projection rays
The Point Inspector follows the OpenCV projection pipeline:
Pw
-> Pc = R * Pw + t
-> normalized image coordinate: x = X/Z, y = Y/Z
-> pixel coordinate: u, v
Physical sensor values are not required for projection. They are included so fx and fy can be interpreted in real-world units:
fx = focal_mm * image_width_px / sensor_width_mm
fy = focal_mm * image_height_px / sensor_height_mm
The app includes in-app notes loaded from Markdown:
docs/concepts.md: camera calibration conceptsdocs/app-design.md: how this visualizer renders and organizes helpersdocs/conventions.md: coordinate and projection conventions
src/camera/ OpenCV camera, extrinsic, intrinsic, and projection math
src/labs/ Lab registry and mounted lab implementations
src/three/ Three.js calibrated camera, render targets, and visual helpers
src/scene/ Test scene geometry
src/ui/ App shell, plain DOM panels, notes modal, and inspectors
src/tests/ Vitest coverage for projection and pose conversion
docs/ Concept, design, and convention notes
Lens distortion is intentionally out of scope for now. The project focuses on the pinhole camera model and the relationship between OpenCV calibration math and WebGL rendering.
No license has been selected yet.