30.11.2021
Another project with OpenCV. This time learning how to digitize/read analog gauges. Using currently sample images to read pressure values.


Final goal is to have a “real time” view of water meter. Will be connected to home automation system to give alerts of abnormal water consumption (during night, away from home etc).
27.02.2026 update
Took some time to gain motivation for this project but it’s finally finnished.
I built a “digital twin” of my water meter. The idea is simple: whenever I read values from the meter, certain consistency conditions must be satisfied before the reading is accepted.
Because the counters in the meter are mechanically linked, the faster rotating dial always slightly leads the slower rotating dial — you can actually see this in the decimal digit (100 liter decimal is the next ten liter and so on). This mechanical coupling creates a predictable relationship between adjacent digits. It is like mechanical safety net.
So I modeled that behavior in software. If a captured reading does not match the expected mechanical progression pattern, it gets rejected. In practice, this works like a mechanical filter implemented digitally.
How it works:
- Initial setup (bootstrapping)
- Use all dials to find the best-fit total. Accept only if error is < 10%
- Once accepted, system becomes “alive”
- Normal operation (port bootstrapping)
- Only use the fastest dial (0.0001) to drive the model
- Reset trigger
- If the total sum of model vs. observed “raw” values get bigger than 10 liters -> trigger bootstrapping (step 1)
Camera feed:
ESP32-S3 acts as a USB-HOST and uses old Logitech C505 USB camera connected to it. Video is streamed through network where OpenCV can import it (10 frames buffer). Max FPS from camera is 15 with 800×600 resolution.

Detection of elements
Digits:
- Preprocessing: grayscale, 3×3 median blur, Gaussian adaptive threshold (binary inverted)
- Detected by using OCR (tesseract)
Dial gauges:
- Preprocessing: circular ROI, gaussian smoothing, needle color mask in HSV (custom ranges)
- Detection: needle_color: contours → largest blob → contour smoothing → PCA on points outside hub → principal axis → tip = farthest projection → angle; rejection by area, elongation, and min/max radius
Summary
I’ll be still playing this for a while. For example adding the warnings for possible leakage (small consumption that takes place all the time over extended periods). Program also publishes mqtt messages to my home automation with 2 separate topics (total consumption large value, and instant consumption). In overlay image also rate of change is presented. Software runs in small linux computer (headless mode). Also plans to improve the lightning (ring light maybe)?
