# sparsemap A live **sparse feature map** built from your webcam, in one small Python file. Two windows, three things happening at once: - **Camera window** — your feed overlaid with sparse tracked feature points (Good-Features-to-Track corners) and **Lucas-Kanade optical-flow vectors**, drawn from previous to current position and colored by track age. - **Map window** — a SLAM-style top-down map: the camera's 2D **trajectory** (heading triangle) plus the sparse **landmarks** implied by those tracks, which settle into place and freeze as their tracks die. No exotic dependencies, no model downloads — just OpenCV and numpy, managed by [pixi](https://pixi.sh). ``` pixi run start ``` That's it — pixi auto-installs Python, numpy, and OpenCV into a local `.pixi/` environment on first run. (Prefer pip? `pip install -r requirements.txt` then `python3 sparsemap.py` works too.) ## What you'll see 1. Green/cyan dots appear on strong corners in the image — those are the sparse feature points. 2. Short vectors extend from where each point was last frame to where it is now — that's sparse optical flow (Lucas-Kanade, pyramid LK). 3. The map window fills with a trail and a cloud of dots. Each dot is a landmark: a tracked corner projected onto a world plane using a rigid 2D motion estimate (`estimateAffinePartial2D`, RANSAC) chained over time. Track a dot long enough and it locks in when it leaves view. 4. Move your camera sideways, forward, or rotate it — the trail bends and the landmark cloud reorganizes live. ## Controls | key | action | |-------|-----------------------------| | `r` | reset tracks + landmarks | | `f` | toggle flow vectors | | `p` | toggle feature points | | `m` | toggle map window | | `s` | toggle stats overlay | | space | pause / resume | | `q` / Esc | quit | ## Flags ``` --camera 0 webcam index (try 1, 2 ... if you have several) --width 1280 requested capture width --height 720 requested capture height --features 200 max tracked corners --scale 0.5 processing downscale for slower machines --map-size 560 map window size in px --no-map start with the map hidden ``` Examples: ``` pixi run start -- --camera 1 --features 300 # second webcam, denser map python3 sparsemap.py --scale 0.5 # cheaper LK on laptops ``` ## How it works (honest version) 1. `goodFeaturesToTrack` finds corners; `calcOpticalFlowPyrLK` tracks them frame to frame, with a forward-backward consistency check to prune drift. 2. `estimateAffinePartial2D` (RANSAC) fits a rigid 2D transform between the previous and current point sets. If at least 8 inliers survive, the transform is chained into a camera pose `(x, y, theta)`. 3. Each live track is projected onto a world plane at the current pose (planar-motion assumption — think "looking down at my desk"). Dying tracks freeze where they were projected, accumulating a sparse map. This is a toy planar "SLAM-lite": great for visualizing sparse flow, tracking quality, and 2D camera motion. It is **not** full 6-DoF SLAM — no depth, no loop closure, no bundle adjustment. Rotating the camera in place still produces a satisfying spinning trail, though. ## Requirements - [pixi](https://pixi.sh) (`curl -fsSL https://pixi.sh/install.sh | bash`) — or plain Python 3.8+ with `pip install -r requirements.txt` - Any webcam OpenCV can open (Linux V4L2, macOS AVFoundation, Windows MSMF) ## Troubleshooting - **`could not open camera N`** — try `--camera 1`. On Linux check `/dev/video*` permissions (add yourself to the `video` group). - **Laggy** — lower `--features`, or use `--scale 0.5`; or ask the camera for `--width 640 --height 480`. - **Map drifts** — expected; it's chained 2D estimation with no loop closure. Press `r` to reset when it bothers you. ## License MIT.