Pointer gauge reader powered by YOLO pose estimation.
Automatically reads analog pointer gauges (pressure gauges, voltmeters, ammeters, etc.) from images or live video streams.
- Upload single or multiple images — results appear side-by-side with the original
- Live MJPEG video stream with real-time keypoint annotation and reading overlay
- Supports local USB/built-in cameras and RTSP IP cameras
- Single-command startup — backend serves the frontend at the same port
- Zero-dependency single-file web UI (no npm, no build step)
-
YOLO Pose model detects 10 keypoints per gauge:
kp_id Role Scale value 0 Pointer base / rotation pivot — 1 Pointer mid — 2 Pointer tip — 3–9 Dial scale marks 0.0 → 6.0 -
Perspective-robust algorithm (
gauge_reader.py):- Uses
kp_id 0directly as the angular origin — avoids circle-fitting failure under perspective distortion - Computes pointer direction via confidence-weighted average of
kp_id 1/2 - Piecewise linear interpolation onto the scale arc
- Returns reading value + out-of-range flag
- Uses
-
FastAPI backend exposes:
GET /orGET /ui— web UIPOST /detect— image inferenceGET /video_feed?source=<cam>— MJPEG streamGET /video_stop— stop streamGET /health— health check
meter-vision/
├── backend/
│ ├── main.py # FastAPI server
│ ├── gauge_reader.py # Core reading algorithm
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/
│ └── index.html # Single-file web UI
├── models/
│ └── best.pt # YOLO pose weights
├── docker-compose.yml
└── README.md
git clone https://github.com/your-username/meter-vision.git
cd meter-vision
# Install dependencies
pip install -r backend/requirements.txt
# Start (serves both API and UI on port 9090)
uvicorn backend.main:app --host 0.0.0.0 --port 9090Open http://localhost:9090 in your browser.
Note: Run
uvicornfrom themeter-vision/root directory, not from insidebackend/.
docker-compose up --build- Web UI: http://localhost:8080
- API docs: http://localhost:9090/docs
- Open http://localhost:9090
- Drag & drop one or more gauge images onto the upload area
- Detection runs automatically — results appear in the right panel with annotated overlay, reading value, and keypoint table
- Hover over a thumbnail to delete it; click
+to add more images
- Click the 视频流 tab
- Enter camera source:
- Local camera:
0(built-in) or1(external USB) - IP camera:
rtsp://192.168.1.100:554/stream
- Local camera:
- Click 开始推流 — the annotated live feed appears immediately
Request: multipart/form-data, field file
Response:
{
"people": [
{
"person_id": 0,
"keypoints": [{"kp_id": 0, "x": 613.2, "y": 976.8, "conf": 0.984}, "..."],
"box": [483.6, 782.9, 1186.1, 972.5]
}
],
"reading": {
"value": 3.45,
"out_of_range": false,
"confidence": 0.987,
"pointer_angle_deg": -12.3,
"pivot": [613.2, 976.8],
"scale_points": [[1195.5, 863.8], "..."]
}
}Returns an MJPEG stream (multipart/x-mixed-replace).
| source | Meaning |
|---|---|
0, 1 |
Local camera index |
rtsp://… |
RTSP IP camera URL |
Stops the active stream. Returns {"status": "stopped"}.
Uses Ultralytics YOLO with a custom keypoint config.
- Annotate images in COCO keypoint format (10 keypoints per gauge, order as above)
- Train:
yolo pose train data=your_data.yaml model=yolov8n-pose.pt epochs=200 imgsz=640
- Replace
models/best.ptwith your trained weights
To adapt to a different scale range, edit SCALE_MAP in backend/gauge_reader.py.
- Python 3.10+
- PyTorch (CPU or CUDA)
- See
backend/requirements.txt
MIT License. See LICENSE.
If this project helps you, please give it a ⭐
