360° Spherical Panorama Stitching
Turns one handheld phone sweep into a 360° panorama you can walk around in a browser.
My partBuilt solo
In short
A CPU-only Python and OpenCV pipeline that turns handheld phone video or stills into an equirectangular panorama and generates a Three.js viewer.
- What it is
- A CPU-only Python and OpenCV pipeline that turns handheld phone video or stills into an equirectangular panorama and generates a self-contained Three.js viewer.
- Why it matters
- General-purpose stitchers hide the geometric decisions behind a single call, which makes it hard to explain why a panorama tilts, ghosts, or drifts under real handheld capture.
- My part
- I built the pipeline, the viewer, the tests, and the technical documentation on my own.
Step by step
- 1
Extract
Frames are pulled from a phone video by interval, count, frame rate, or measured motion. Camera intrinsics come from EXIF when available, otherwise from an explicit field of view or calibration file.
- 2
Match
ORB features are matched between adjacent frames, filtered with Lowe’s ratio test, and validated by RANSAC. If an adjacent pair fails, the matcher tries across the gap and interpolates the missing step rather than silently discarding the frame.
- 3
Rotate
The relative rotation is recovered from R = K⁻¹HK under a pure-rotation model. Numerical noise means the matrix is rarely a perfect rotation, so singular-value decomposition projects it back onto the rotation manifold before chaining.
- 4
Warp
Each source frame is inverse-warped onto an equirectangular canvas. Each output pixel is a world direction; that direction is rotated into the camera, projected onto the image plane, and sampled.
- 5
Smooth
A moving average over the chained global rotations damps per-pair pitch and roll wobble. It is deliberately simple: not bundle adjustment, loop closure, or exposure matching.
- 6
View
The final 4096 × 2048 panorama is served through a self-contained Three.js viewer that makes the recovered geometry directly inspectable in a browser.
Results
- 309
- Sample frames
- phone video, single handheld sweep
- 333°
- Recovered sweep
- from a horizontal pan
- 921
- Median RANSAC inliers
- per adjacent pair
- 15 of 308
- Interpolated pairs
- recovered across a gap
- 36.9%
- Sphere imaged
- phone-height horizontal band
- 4096 × 2048
- Output resolution
- equirectangular
- ~2 minutes
- End-to-end time
- Ryzen 7 5800H, CPU only
- 13.5×
- Pitch wobble reduction
- temporal smoothing, on the sample run
- 5.2×
- Roll wobble reduction
- temporal smoothing, on the sample run
From the project






For engineersHow it is built, its limits, and its keywords.
How it works
Frames are extracted, matched with ORB features and RANSAC, related by homography under a pure-rotation camera model, projected back onto a sphere, and rendered in a browser viewer. Temporal smoothing damps the pitch and roll wobble left after per-pair estimation.
Limits
- Pure-rotation camera model — translation while sweeping introduces parallax that no homography can explain.
- A phone-height horizontal sweep sees a band around the viewer, so the poles are never captured; filling is not reconstruction.
- Blank walls and repeated textures weaken ORB matching and can force interpolation.
- No bundle adjustment or global loop closure; drift is damped rather than corrected.
- No exposure matching; brightness changes remain visible across seams.
Keywords
- panorama stitching
- equirectangular projection
- OpenCV
- ORB features
- RANSAC
- temporal smoothing
- Three.js viewer
