仪表读数检测识别服务 API,基于 YOLO 检测和 ResNet OCR 识别技术,提供仪表区域的检测和数值读取功能。
| 信息 | 说明 |
|---|---|
| 服务名称 | Meter Reading API |
| 版本 | 1.0.0 |
| 作者 | noimank (康康) |
| 邮箱 | noimank@163.com |
| 基础URL | http://{host}:8000 |
| 协议 | HTTP/HTTPS |
| 数据格式 | JSON |
- 图片上传接口使用
multipart/form-data格式 - 请求头需设置
Content-Type: multipart/form-data - 支持的图片格式:JPEG、PNG、BMP、WEBP
所有接口统一返回 JSON 格式数据,包含以下通用字段:
| 字段 | 类型 | 说明 |
|---|---|---|
inference_time_ms |
number | 推理耗时(毫秒) |
边界框 (bounding box) 使用 [x1, y1, x2, y2] 格式:
x1, y1: 左上角坐标x2, y2: 右下角坐标- 坐标原点为图片左上角
检查服务状态和模型加载情况。
| 项目 | 内容 |
|---|---|
| URL | /health |
| 方法 | GET |
| Content-Type | 无 |
无
{
"status": "healthy",
"service": "meter-reading-api",
"models": {
"detection": true,
"recognition": true
}
}| 字段 | 类型 | 说明 |
|---|---|---|
status |
string | 服务状态,healthy 表示正常 |
service |
string | 服务名称 |
models.detection |
boolean | 检测模型是否加载成功 |
models.recognition |
boolean | 识别模型是否加载成功 |
检测图片中的仪表区域,返回所有检测到的仪表位置信息。
| 项目 | 内容 |
|---|---|
| URL | /api/detect |
| 方法 | POST |
| Content-Type | multipart/form-data |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
file | 是 | 待检测的图片文件 |
成功响应 (200 OK)
{
"detections": [
{
"bbox": [120.5, 85.2, 380.7, 290.4],
"confidence": 0.95,
"class_id": 0
},
{
"bbox": [450.0, 100.0, 700.0, 350.0],
"confidence": 0.88,
"class_id": 0
}
],
"count": 2,
"inference_time_ms": 45.32
}| 字段 | 类型 | 说明 |
|---|---|---|
detections |
array | 检测结果数组 |
detections[].bbox |
array[float] | 边界框坐标 [x1, y1, x2, y2] |
detections[].confidence |
float | 检测置信度,范围 0-1 |
detections[].class_id |
int | 类别ID |
count |
int | 检测到的仪表数量 |
inference_time_ms |
float | 推理耗时(毫秒) |
| 状态码 | 说明 | 响应示例 |
|---|---|---|
| 503 | 检测模型未加载 | {"detail": "Detection model not loaded"} |
读取已裁剪的仪表图片中的数值。适用于前端已裁剪好仪表区域的场景。
| 项目 | 内容 |
|---|---|
| URL | /api/read |
| 方法 | POST |
| Content-Type | multipart/form-data |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
file | 是 | 裁剪后的仪表图片 |
成功响应 (200 OK)
{
"reading": "12345.67",
"inference_time_ms": 12.58
}| 字段 | 类型 | 说明 |
|---|---|---|
reading |
string | 读取的数值字符串 |
inference_time_ms |
float | 推理耗时(毫秒) |
| 状态码 | 说明 | 响应示例 |
|---|---|---|
| 503 | 识别模型未加载 | {"detail": "Recognition model not loaded"} |
- 输入图片应为仪表区域的裁剪图
- 支持识别的字符:
0-9和. - 图片将被自动缩放到模型输入尺寸
一站式接口:检测图片中的所有仪表并读取每个仪表的数值。推荐使用此接口完成完整的仪表读数流程。
| 项目 | 内容 |
|---|---|
| URL | /api/detect_and_read |
| 方法 | POST |
| Content-Type | multipart/form-data |
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
file | 是 | 包含仪表的完整图片 |
成功响应 (200 OK)
{
"results": [
{
"bbox": [120.5, 85.2, 380.7, 290.4],
"confidence": 0.95,
"reading": "1234.56"
},
{
"bbox": [450.0, 100.0, 700.0, 350.0],
"confidence": 0.88,
"reading": "789.01"
}
],
"count": 2,
"inference_time_ms": {
"total": 68.45,
"detection": 42.12,
"reading": 26.33
}
}| 字段 | 类型 | 说明 |
|---|---|---|
results |
array | 检测和读数结果数组 |
results[].bbox |
array[float] | 边界框坐标 [x1, y1, x2, y2] |
results[].confidence |
float | 检测置信度,范围 0-1 |
results[].reading |
string | 读取的数值字符串 |
count |
int | 检测到的仪表数量 |
inference_time_ms.total |
float | 总耗时(毫秒) |
inference_time_ms.detection |
float | 检测阶段耗时(毫秒) |
inference_time_ms.reading |
float | 读数阶段耗时(毫秒) |
| 状态码 | 说明 | 响应示例 |
|---|---|---|
| 503 | 检测模型未加载 | {"detail": "Detection model not loaded"} |
| 503 | 识别模型未加载 | {"detail": "Recognition model not loaded"} |
| HTTP状态码 | 说明 |
|---|---|
| 200 | 请求成功 |
| 400 | 请求参数错误 |
| 422 | 请求格式错误(如缺少文件) |
| 500 | 服务器内部错误 |
| 503 | 服务不可用(模型未加载) |
curl -X GET "http://localhost:8000/health"curl -X POST "http://localhost:8000/api/detect" \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/meter_image.jpg"curl -X POST "http://localhost:8000/api/read" \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/cropped_meter.jpg"curl -X POST "http://localhost:8000/api/detect_and_read" \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/meter_image.jpg"async function checkHealth() {
const response = await fetch('http://localhost:8000/health');
const data = await response.json();
console.log(data);
}async function detectAndRead(imageFile) {
const formData = new FormData();
formData.append('file', imageFile);
const response = await fetch('http://localhost:8000/api/detect_and_read', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}
// 使用示例
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const result = await detectAndRead(file);
console.log('检测结果:', result);
});import requests
# 健康检查
def check_health():
response = requests.get('http://localhost:8000/health')
return response.json()
# 检测并读数
def detect_and_read(image_path: str):
with open(image_path, 'rb') as f:
files = {'file': f}
response = requests.post(
'http://localhost:8000/api/detect_and_read',
files=files
)
return response.json()
# 使用示例
if __name__ == '__main__':
# 检查服务状态
health = check_health()
print(f"服务状态: {health}")
# 检测并读数
result = detect_and_read('meter.jpg')
print(f"检测结果: {result}")
# 解析结果
for item in result['results']:
print(f"位置: {item['bbox']}")
print(f"置信度: {item['confidence']}")
print(f"读数: {item['reading']}")检查以下配置:
- 检测模型路径:
/app/onnx_model/yolo26_det.onnx - 识别模型路径:
/app/onnx_model/resnet_ocr.onnx - 识别配置路径:
/app/configs/rec/resnet_ocr.yaml
确保这些文件存在且有正确的读取权限。
- 支持格式:JPEG、PNG、BMP、WEBP
- 颜色空间:自动处理 GRAY、RGB、RGBA、BGR
- 推荐分辨率:宽度 >= 640px,高度 >= 480px
- 确保图片清晰,光线充足
- 仪表在图片中占比适中
- 避免遮挡和模糊
- 可通过
confidence字段判断可信度
默认支持:0123456789.(数字和小数点)
可在配置文件 /app/configs/rec/resnet_ocr.yaml 中自定义字符集。
建议使用异步方式批量调用,避免阻塞。可以并发发送多个请求以提高效率。
如有问题或建议,请联系:
- 作者: noimank (康康)
- 邮箱: noimank@163.com