CountIn
Real-time people counting with computer vision that runs entirely in the browser: a from-scratch tracker and line-crossing geometry, no server.
- Role
- Solo developer
- Stack
A real run on a busy street in Madrid (video "Calle Preciados Madrid" by OsvaldoGago, CC BY-SA 3.0; this capture shares the same licence): detections, tracks and the counting line.
- 0
- frames sent to a server: detection runs in the browser
- 1
- permission needed: the camera
- In / Out
- counted per line with a signed cross product
CountIn counts people in real time from a webcam with TensorFlow.js. Everything runs in the browser: no server, no install, and the camera feed never leaves the machine. The project is paused for now, kept online as a reference.
How it works
- Detection. A COCO-SSD model loaded through TensorFlow.js finds people in each frame. Detection runs on every other frame to keep the UI responsive.
- Tracking. A hand-written centroid tracker matches new detections to existing tracks by distance, with a confidence gate against flickering false positives and a short position history to survive occlusion.
- Line crossing. You draw counting lines; for each track the system tests whether the segment between its previous and current position intersects a line, using a cross product with a direction sign for in versus out.
- Dashboard. Counts update live per line, with running occupancy and a flow chart.
- Hub and camera stations. Several phones or webcams pair with a central dashboard by QR code. Each station runs detection locally and sends only numbers over WebSocket to a FastAPI backend, never video.
What is interesting
- The tracker is from scratch, so every stage is debuggable: when counts drift, you can see which stage is at fault.
- Counting is geometry, not ML: a cross product with a sign.
- The privacy story is short: the camera permission is the only permission, the model is fetched once and cached, and it works offline after the page loads.
TensorFlow.js performance varies a lot across hardware, so processing every other frame and rendering to canvas instead of the DOM is what keeps it feeling real-time.
Status
Paused. The live demo is offline right now; run it locally from the repo with Docker Compose (Vite frontend, FastAPI and PostgreSQL backend). The detection pipeline is covered by end-to-end tests with Playwright and a synthetic camera feed.
Drafted with AI, edited by hand. I publish it when it sounds like me.