*November 15, 2025 · 6 min read*
Manual meter reading is one of those problems that looks simple on the surface: a technician visits a property, reads a number, and writes it down. In practice, it generates a surprising amount of errors — misread digits, transposed numbers, inaccessible meters, and costly re-visits. For utility companies managing thousands of meters across a city or rural region, these errors add up fast.
At AIVerse, we built an automated meter reading system for a utilities company in Romania. Here's how it actually works.
The Core Problem
The system needed to:
- Read electric meter displays in variable lighting conditions
- Run on Android devices carried by field technicians
- Work offline (no guaranteed connectivity in rural areas)
- Achieve accuracy high enough to eliminate the need for manual verification
A key constraint: the model had to run directly on the device, not on a cloud API. Latency, connectivity, and data privacy all pointed toward on-device inference.
Step 1: Data Collection
The first challenge with any computer vision project is data. We needed thousands of meter images taken in real-world conditions — different meter models, different lighting, different angles, dirty glass covers, worn-out digit displays.
We collected images in two ways:
- Field collection by technicians over several weeks
- Synthetic augmentation — taking clean images and applying random transformations (rotation, blur, brightness shifts, simulated glare)
After labeling, we had approximately 8,000 annotated images across multiple meter types. Each image was annotated with bounding boxes around the digit display area and individual digit labels.
Step 2: Model Selection — Why YOLOv5
We evaluated several architectures before settling on YOLOv5:
- EfficientDet — accurate, but too slow for real-time preview on mid-range Android devices
- MobileNetSSD — fast, but struggled with small digit regions and low-contrast displays
- YOLOv5s — the sweet spot: fast inference, good accuracy on small objects, clean PyTorch implementation, straightforward TFLite export
YOLOv5s gave us roughly 94% digit-level accuracy on our validation set after fine-tuning, which translated to ~98% full-reading accuracy (all 5 digits correct).
Step 3: Training
Training ran on a single GPU (NVIDIA RTX 3090) for approximately 8 hours. Key decisions:
- Input resolution: 640×640 — higher than default improves small digit detection
- Transfer learning: started from YOLOv5s pretrained on COCO, then fine-tuned on our dataset
- Data augmentation: mosaic augmentation, random horizontal flip disabled (meter digits shouldn't be mirrored), brightness/contrast jitter
We also trained a secondary model for meter display localization — finding the meter display region first, then cropping it before running digit detection. This two-stage approach improved accuracy on cluttered backgrounds.
Step 4: Converting to TFLite
TensorFlow Lite is the standard runtime for on-device ML on Android. Converting from PyTorch (YOLOv5) to TFLite requires an intermediate step through ONNX:
PyTorch → ONNX → TensorFlow SavedModel → TFLite
The conversion introduces some accuracy loss. We benchmarked FP32, FP16, and INT8 quantization:
| Format | Model size | Inference time (mid-range device) | Accuracy drop |
|---|---|---|---|
| FP32 | 14 MB | 280ms | baseline |
| FP16 | 7 MB | 180ms | ~0.3% |
| INT8 | 3.5 MB | 95ms | ~1.8% |
We shipped INT8 — the accuracy drop was acceptable and the performance difference was significant enough to matter for user experience.
Step 5: The Android App
The Android application was built around Android's Camera2 API with a live preview showing the technician where to aim the camera. When the model detects a meter display with high confidence, it automatically captures and processes the reading.
Key UX decisions:
- Visual overlay showing the detected meter region in real-time
- Confidence score displayed to the technician (they can retake if confidence is low)
- Readings saved locally with GPS coordinates and a photo — synced to the backend when connectivity is available
- Offline-first architecture: readings queue locally and upload in batch
Results
After deployment across a network of ~3,000 meters:
- Error rate: down from ~4.2% (manual) to ~0.8% (automated)
- Reading time per meter: down from ~3 minutes to ~45 seconds
- Re-visit rate: reduced by 60% in the first quarter post-deployment
The remaining 0.8% error rate occurs mainly on meters with physically damaged displays or extreme glare conditions — cases where the system flags low confidence and prompts the technician to read manually.
What We Learned
A few things that weren't obvious at the start:
Data quality matters more than model architecture. The jump from our first 2,000 images to 8,000 well-labeled images improved accuracy more than any model change.
On-device deployment constraints force good decisions. The INT8 quantization requirement pushed us to build a cleaner pipeline and test more rigorously. Cloud-based inference would have hidden some of these issues.
Two-stage pipelines outperform single-stage for this problem. Localize the display first, then read the digits. It's slower to build but significantly more accurate.
Interested in a similar solution for your utility company or industrial setting? Contact us to discuss your use case.