naveenkm13/occupancyos
<!-- The YAML block above configures the Hugging Face Space (backend host) and must stay at the very top of this file. GitHub renders it as a small metadata table; everything below is the normal project README. -->
CCTV Workplace Occupancy Detection
YOLOv8l + OpenCV + FastAPI + React real-time workplace / classroom / coworking occupancy analytics. Detects people and chairs with COCO-pretrained YOLOv8l and marks each chair as occupied/free based on person-on-chair overlap. Broadcasts to a live dashboard over WebSockets.
Two detection modes (switchable via DETECTOR_MODE):
- `chair` (default) — dynamic chair detection; no setup, works on any camera angle.
- `zone` — predefined desk rectangles in pixel space (
config.DESK_ZONES).
VIDEO FILE / RTSP CCTV STREAM
↓ OpenCV
YOLOv8l Person Detection
↓
Desk Zone Mapping (centroid → rectangle)
↓
Occupancy Analytics
↓ FastAPI WebSocket
React DashboardFeatures
- YOLOv8l person detection (COCO-pretrained or fine-tuned)
- Centroid-based desk-zone occupancy (no chair detection)
- Video file, webcam, and RTSP support
- FastAPI + WebSocket real-time broadcast (~10 Hz)
- MJPEG snapshot stream for live preview
- Analytics: utilization %, peak/avg, per-desk dwell, alerts, CSV export
- React + Vite + Tailwind dashboard with charts, dark glassmorphism UI
- Full training pipeline (extract → annotate → split → train → validate → export)
Project layout
backend/
app/ FastAPI app + pipeline
detection/ YOLOv8l + occupancy engine
analytics/ history, alerts, CSV export
api/ REST endpoints
streams/ OpenCV video sources (file / webcam / RTSP)
websocket/ connection manager
training/ prepare_dataset, train, validate
scripts/ video_inference, websocket_server, extract_frames
models/ weights (yolov8l.pt, best.pt)
frontend/ React + Vite + Tailwind dashboardQuick start (backend)
1. Python environment
python -m venv .venv
.\.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/Mac
pip install -r requirements.txt2. CUDA-enabled PyTorch (recommended)
The default pip install of torch may install the CPU build. To use GPU:
pip install --index-url https://download.pytorch.org/whl/cu121 \
torch torchvisionVerify:
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"3. Place a model
The first run will auto-download yolov8l.pt via Ultralytics. Or place your fine-tuned best.pt at backend/models/best.pt and set:
set YOLO_WEIGHTS=backend\models\best.pt # Windows
# export YOLO_WEIGHTS=backend/models/best.pt4. Configure desk zones
Edit backend/config.py → DESK_ZONES. Each entry is {id, label, x1, y1, x2, y2} in pixel space of the camera view. Or PUT zones at runtime via /api/desks.
5. Run the API
python -m backend.scripts.websocket_server
# or
uvicorn backend.app.main:app --host 0.0.0.0 --port 8000Endpoints:
GET /service infoGET /docsOpenAPI / SwaggerWS /wslive JSON frame resultsGET /api/stream.mjpgannotated MJPEG previewGET /api/deskslist desksPUT /api/desksreplace desksPOST /api/source{ "source": "rtsp://..." | "path.mp4" | "0" }POST /api/control/stoppause pipelinePOST /api/control/restartGET /api/analytics/summary | series | alertsPOST /api/analytics/exportCSV downloadGET /api/latestlast frame result
6. Inference utilities
# Annotate a video to mp4
python -m backend.scripts.video_inference --source path/to/video.mp4 \
--output backend/output/annotated.mp4
# Live RTSP window
python -m backend.streams.rtsp_stream rtsp://user:pass@192.168.1.10:554/stream1Training
# 1. extract frames at 2 fps
python -m backend.scripts.extract_frames --input Dataset/videos \
--output Dataset/raw/images --fps 2
# 2. annotate with Label Studio / Roboflow → see backend/training/annotate_guide.md
# end with Dataset/raw/images/*.jpg and Dataset/raw/labels/*.txt
# 3. split + dataset.yaml
python -m backend.training.prepare_dataset --input Dataset/raw --output Dataset/yolo
# 4. train YOLOv8l
python -m backend.training.train_yolov8 --data Dataset/yolo/dataset.yaml \
--epochs 80 --batch 16 --imgsz 640 --device 0
# 5. validate
python -m backend.training.validate_model --weights backend/models/best.pt \
--data Dataset/yolo/dataset.yamlFrontend
cd frontend
npm install
npm run dev # http://localhost:5173Set the backend URL in frontend/.env (defaults to http://localhost:8000):
VITE_API_URL=http://localhost:8000
VITE_WS_URL=ws://localhost:8000/wsNotes
- The system is centroid-based: when a detected person's bounding-box center falls inside a desk rectangle, that desk is marked occupied.
- No chair detection, no segmentation, no pose model — by design.
- For best results, fine-tune YOLOv8l on a few thousand frames of your actual camera angles. Generic COCO weights work but degrade on extreme overhead views.
