🚰🔌 Power Meter and Water Meter OCR
🚰 🔌 ระบบสำหรับอ่านตัวเลขบนมิเตอร์ไฟฟ้าและมิเตอร์น้ำ
Water Meter OCR is an iApp's AI service that automatically reads and digitizes water meter and power meter readings. The service can detect and extract numbers from both round and rectangular meter faces.
Try Demo!
Getting Started
-
Prerequisites
- An API key from iApp Technology
- Clear images of water/power meters
- Internet connection
-
Quick Start
- Fast meter reading recognition
- Support for multiple meter types
- Simple REST API interface
-
Key Features
- Automated meter reading detection
- High accuracy digit recognition
- Fast response time
- Easy integration
-
Security & Compliance
- GDPR and PDPA compliant
- No data retention after processing
How to get API Key?
Please visit API Key Management page to view your existing API key or request a new one.
API Endpoints
| Endpoint | Method | Description | Cost |
|---|---|---|---|
/v3/store/smart-city/power-meter-and-water-meterLegacy: /meter-number-ocr | POST | Extract readings from power/water meters | 1 IC per request |
/v3/store/smart-city/power-meter-and-water-meter/fileLegacy: /meter-number-ocr/file | POST | Extract readings from meter image file | 1 IC per request |
/v3/store/smart-city/power-meter-and-water-meter/base64Legacy: /meter-number-ocr/base64 | POST | Extract readings from base64 meter image | 1 IC per request |
Example
Power and Water Meter in Real Life Application
1. Water Meter With Round Face
Example 1

Example 2

2. Water Meter With Rectangle Face

Request
curl --location --request POST 'https://api.iapp.co.th/meter-number-ocr/file' \
--header 'apikey: ----Your API Key----' \
--form 'file=@"/Users/id_1016_value_367_003.jpg"'
Response
{
"infer_time": 0.16,
"label": "024963",
"message": "success",
"status": 200
}
Features & Capabilities
Core Features
- Automatic detection of meter faces (round and rectangular)
- High-accuracy digit recognition
- Fast processing time
- Support for multiple image formats
Supported Fields
- Meter reading numbers
- Meter face type detection
API Reference
Endpoint
POST https://api.iapp.co.th/meter-number-ocr/file
Headers
| Name | Type | Description |
|---|---|---|
| apikey | string | Your API key |
Request Body
| Name | Type | Description |
|---|---|---|
| file | image | Clear meter image |
Code Example
Python
import requests
url = "https://api.iapp.co.th/meter-number-ocr/file"
payload = {}
files=[
('file',('{YOUR UPLOADED FILE NAME}',open('{YOUR UPLOADED FILE PATH}','rb'),'image/png'))
]
headers = {
'apikey': '{YOUR_API_KEY}'
}
response = requests.request("POST", url, headers=headers, data=payload, files=files)
print(response.text)
JavaScript
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
let data = new FormData();
data.append('file', fs.createReadStream('{YOUR UPLOADED FILE PATH}'));
let config = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://api.iapp.co.th/meter-number-ocr/file',
headers: {
'apikey': '{YOUR_API_KEY}',
...data.getHeaders()
},
data : data
};
axios.request(config)
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
});
PHP
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.iapp.co.th/meter-number-ocr/file',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => array('file'=> new CURLFILE('{YOUR UPLOADED FILE PATH}')),
CURLOPT_HTTPHEADER => array(
'apikey: {YOUR_API_KEY}'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
Swift
let parameters = [
[
"key": "file",
"src": "{YOUR UPLOADED FILE PATH}",
"type": "file"
]] as [[String: Any]]
let boundary = "Boundary-\(UUID().uuidString)"
var body = Data()
var error: Error? = nil
for param in parameters {
if param["disabled"] != nil { continue }
let paramName = param["key"]!
body += Data("--\(boundary)\r\n".utf8)
body += Data("Content-Disposition:form-data; name=\"\(paramName)\"".utf8)
if param["contentType"] != nil {
body += Data("\r\nContent-Type: \(param["contentType"] as! String)".utf8)
}
let paramType = param["type"] as! String
if paramType == "text" {
let paramValue = param["value"] as! String
body += Data("\r\n\r\n\(paramValue)\r\n".utf8)
} else {
let paramSrc = param["src"] as! String
let fileURL = URL(fileURLWithPath: paramSrc)
if let fileContent = try? Data(contentsOf: fileURL) {
body += Data("; filename=\"\(paramSrc)\"\r\n".utf8)
body += Data("Content-Type: \"content-type header\"\r\n".utf8)
body += Data("\r\n".utf8)
body += fileContent
body += Data("\r\n".utf8)
}
}
}
body += Data("--\(boundary)--\r\n".utf8);
let postData = body
var request = URLRequest(url: URL(string: "https://api.iapp.co.th/meter-number-ocr/file")!,timeoutInterval: Double.infinity)
request.addValue("{YOUR_API_KEY}", forHTTPHeaderField: "apikey")
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
}
task.resume()
Kotlin
val client = OkHttpClient()
val mediaType = "text/plain".toMediaType()
val body = MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file","{YOUR UPLOADED FILE NAME}",
File("{YOUR UPLOADED FILE PATH}").asRequestBody("application/octet-stream".toMediaType()))
.build()
val request = Request.Builder()
.url("https://api.iapp.co.th/meter-number-ocr/file")
.post(body)
.addHeader("apikey", "{YOUR_API_KEY}")
.build()
val response = client.newCall(request).execute()
Java
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file","{YOUR UPLOADED FILE NAME}",
RequestBody.create(MediaType.parse("application/octet-stream"),
new File("{YOUR UPLOADED FILE PATH}")))
.build();
Request request = new Request.Builder()
.url("https://api.iapp.co.th/meter-number-ocr/file")
.method("POST", body)
.addHeader("apikey", "{YOUR_API_KEY}")
.build();
Response response = client.newCall(request).execute();
Dart
var headers = {
'apikey': '{YOUR_API_KEY}'
};
var request = http.MultipartRequest('POST', Uri.parse('https://api.iapp.co.th/meter-number-ocr/file'));
request.files.add(await http.MultipartFile.fromPath('file', '{YOUR UPLOADED FILE PATH}'));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
Accuracy and Performance
Evaluation done based on Water-Meter image data of both rectangle and round faces (107 images)
Model Evaluation
| Model | Description | Accuracy (%) |
|---|---|---|
| Water Meter Detection Model | Detects the water meter from the input image | 96.22 |
| OCR Model | Recognizes the Digits | 76.47 |
| Overall Accuracy | Overall accuracy of the system | 73.58 |
Character Evaluation
| Numbers | Total Count | Correct Count | Accuracy (%) |
|---|---|---|---|
| 0 | 197 | 188 | 95.43 |
| 1 | 85 | 80 | 94.12 |
| 2 | 58 | 53 | 91.38 |
| 3 | 69 | 63 | 91.3 |
| 4 | 65 | 62 | 95.38 |
| 5 | 57 | 50 | 87.72 |
| 6 | 51 | 43 | 84.31 |
| 7 | 52 | 48 | 92.31 |
| 8 | 48 | 40 | 83.33 |
| 9 | 59 | 50 | 84.75 |
Overall Accuracy based on True detection of numbers = 90 %
History/Change Logs
Version 1.0 - 2021-10-05
Added
- Introducing iApp's water meter OCR
- Supports all kind of water meter faces
Version 1.1 - 2021-12-02
Fixed
- Detection of 2 digits on same x coordinate
- Increased Accuracy from 62.26 to 73.58
Code Examples
Curl
curl -X POST https://api.iapp.co.th/v3/store/smart-city/meter-reading \
-H "apikey: YOUR_API_KEY" \
-F "file=@/path/to/meter.jpg"
Python
import requests
url = "https://api.iapp.co.th/v3/store/smart-city/meter-reading"
files = {"file": ("("/path/to/meter.jpg", "rb"))}
headers = {"apikey": "YOUR_API_KEY"}
response = requests.post(url, headers=headers, files=files)
print(response.json())
JavaScript
const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");
let data = new FormData();
data.append("file", fs.createReadStream("/path/to/meter.jpg"));
let config = {
method: "post",
url: "https://api.iapp.co.th/v3/store/smart-city/meter-reading",
headers: {
apikey: "YOUR_API_KEY",
...data.getHeaders(),
},
data: data,
};
axios(config)
.then((response) => console.log(response.data))
.catch((error) => console.log(error));
PHP
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.iapp.co.th/v3/store/smart-city/meter-reading',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => array(
'file'=> new CURLFILE('/path/to/meter.jpg')
),
CURLOPT_HTTPHEADER => array(
'apikey: YOUR_API_KEY'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
Swift
import Foundation
let url = URL(string: "https://api.iapp.co.th/v3/store/smart-city/meter-reading")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("YOUR_API_KEY", forHTTPHeaderField: "apikey")
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
body.append("--\(boundary)\r\n".data(using: .utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"file.jpg\"\r\n".data(using: .utf8)!)
body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
if let fileData = try? Data(contentsOf: URL(fileURLWithPath: "/path/to/meter.jpg")) {
body.append(fileData)
}
body.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
request.httpBody = body
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
print(String(data: data, encoding: .utf8)!)
}
}
task.resume()
Kotlin
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
val client = OkHttpClient()
val file = File("/path/to/meter.jpg")
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.name, file.asRequestBody("image/jpeg".toMediaTypeOrNull()))
.build()
val request = Request.Builder()
.url("https://api.iapp.co.th/v3/store/smart-city/meter-reading")
.addHeader("apikey", "YOUR_API_KEY")
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
println(response.body?.string())
}
Java
import okhttp3.*;
import java.io.File;
OkHttpClient client = new OkHttpClient();
File file = new File("/path/to/meter.jpg");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse("image/jpeg"), file))
.build();
Request request = new Request.Builder()
.url("https://api.iapp.co.th/v3/store/smart-city/meter-reading")
.addHeader("apikey", "YOUR_API_KEY")
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println(response.body().string());
}
Dart
import 'package:http/http.dart' as http;
var request = http.MultipartRequest(
'POST',
Uri.parse('https://api.iapp.co.th/v3/store/smart-city/meter-reading')
);
request.files.add(await http.MultipartFile.fromPath(
'file',
'/path/to/meter.jpg'
));
request.headers.addAll({
'apikey': 'YOUR_API_KEY'
});
var response = await request.send();
var responseBody = await response.stream.bytesToString();
print(responseBody);
Pricing
| AI API Service Name | IC Per Request | On-Premise |
|---|---|---|
| Power and Meter OCR | 1 IC/Request | Contact |
