家庭燃气表微信抄表识别系统
1.背景需求
目前家里燃气度数的读数上报,每个月在社区微信群里面将手机拍摄的燃气表读数截图(加住址信息水印),发到群里给抄表员。
2.总体设计
设计目标
功能一:手机上随时可以远程采集读数图片(自动加住址信息水印),在微信上发送给社区抄表员。
功能二:每小时采集一次,统计燃气每日使用状况,对使用情况进行分析和预警(由于OCR还需要进一步提升识别能力,暂不实现)。
功能三:燃气漏气检测(因测试有一定危险,暂不实现)。
3.采集系统
使用树莓派,部署Docker环境。
3.1 功能描述
接收管理服务器实时采集请求,实现燃气表拍照的采集上报,摄像头采集之前要自动打开小夜灯照明,厨柜内较黑拍不清楚。
3.2 容器环境配置
3.2.1 Dockerfile文件
FROM ubuntu:latest
ENV LANG C.UTF-8
ENV DEBIAN_FRONTEND noninteractiveRUN apt-get update
RUN apt install -y openssh-client openssh-server
RUN apt-get install -y wget curl git telnet vim make gcc
RUN apt-get install -y python3 python3-pip libpcre3 libpcre3-dev python3-opencvRUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
RUN echo "Port 8422" >> /etc/ssh/sshd_config
RUN echo 'root:cw' | chpasswd
RUN mkdir /var/run/sshdEXPOSE 8422RUN apt clean \&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp* \
RUN apt autoremoveWORKDIR /tmp
RUN apt-get update
RUN apt-get upgrade -y
RUN apt install -y libusb-1.0-0-dev
RUN git clone https://github.com/mvp/uhubctl
WORKDIR /tmp/uhubctl
RUN make && make installRUN pip3 install paho-mqtt pytest-shutil requests -i https://pypi.mirrors.ustc.edu.cn/simple/ WORKDIR /home
CMD ["/usr/sbin/sshd","-D"]
3.2.2 docker-compose.yaml文件
version: "3.0"
services:#燃气采集设备端#docker exec -it gas_meter_reading_t /bin/bashgas_meter_reading_t:build: .image: gas_meter_reading:v1container_name: gas_meter_reading_tworking_dir: /home
# devices:
# - /dev/video0:/dev/video0ports:- 8422:8422volumes:- ./home:/homerestart: alwaystty: trueprivileged: true
3.3 代码样例
3.3.1 控制USB小夜灯代码样例
#uhubctl 控制 usb 的供电情况,然后控制灯的状态
#控制命令:sudo uhubctl -l location -p port -a off
#location是USB集线起的位置,port是USB编号,off关闭,on打开;
uhubctl --help
uhubctl -l 2 -p 1 -a off
uhubctl -l 2 -p 1 -a on
3.3.2 摄像头拍摄代码样例
import cv2 as cv
cap = cv.VideoCapture(0)
if cap.isOpened():_, frame = cap.read()farm = cv.resize(frame, dsize = (1080,1080) )cv.imwrite(r"/20231020/220301.jpg",farm)
4.管理系统
系统环境要求:LINUX系统,支持Docker环境。
4.1 容器环境配置
4.1.1 Dockerfile文件
FROM ubuntu
RUN apt update
RUN apt upgrade -y
RUN apt install -y wget libgl1 libglib2.0-dev python3 pip curl inetutils-ping graphicsmagick# Install nvm
RUN apt install -y git
RUN git clone http://github.com/creationix/nvm.git /root/.nvm;
RUN chmod -R 777 /root/.nvm/;
RUN bash /root/.nvm/install.sh;
RUN export NVM_DIR="$HOME/.nvm";
RUN echo "[[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh" >> $HOME/.bashrc;RUN bash -i -c 'nvm install 16'
RUN bash -i -c 'npm install -g pnpm'CMD ["/bin/bash"]
4.1.2 Dockerfile_OCR
FROM ubuntu
RUN apt update
RUN apt upgrade -y
RUN apt install -y wget libgl1 libglib2.0-dev python3 pip curl inetutils-ping graphicsmagick# Install nvm
RUN apt install -y git
RUN git clone http://github.com/creationix/nvm.git /root/.nvm;
RUN chmod -R 777 /root/.nvm/;
RUN bash /root/.nvm/install.sh;
RUN export NVM_DIR="$HOME/.nvm";
RUN echo "[[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh" >> $HOME/.bashrc;RUN bash -i -c 'nvm install 16'
RUN bash -i -c 'npm install -g pnpm'CMD ["/bin/bash"]
4.1.3 docker-compose.yaml
version: '3.3'
services:#Gas meter reading platform:燃气采集平台#docker exec -it gmrplat_t /bin/bashgmrplat_t:build: .image: gmrplat:v1volumes:- ./home:/homecontainer_name: gmrplat_tports:- 8477:8477- 8488:8488restart: alwayscommand: /bin/bashtty: truenetworks:back_net:ipv4_address: 172.77.1.5#百度AI/图像识别#docker exec -it paddle_ocr_t /bin/bash paddle_ocr_t:container_name: paddle_ocr_tbuild:context: ./dockerfile: Dockerfile-OCRimage: gmr_paddle_ocrvolumes:- ./PaddleOCR:/PaddleOCRtty: trueprivileged: truerestart: alwayscommand: /bin/bashnetworks:back_net:ipv4_address: 172.77.1.6#开源物联网MQTT服务器(https://www.emqx.com/)#初始用户名密码:admin/public#docker exec -it emq_t /bin/bashemq_t:container_name: emq_timage: emqx/emqx:5.3.0ports:- 1883:1883- 8083:8083- 8084:8084- 8883:8883- 18083:18083restart: alwaystty: truenetworks:back_net:ipv4_address: 172.77.1.7#开源数据库,兼容MYSQLmariadb_t:container_name: mariadb_timage: mariadbenvironment:- MYSQL_ROOT_PASSWORD=cjy- MYSQL_DATABASE=gmrplat- MYSQL_USER=cjy- MYSQL_PASSWORD=cjyrestart: alwaysnetworks:back_net:ipv4_address: 172.77.1.8#数据库WEB后台管理phpmyadmin_t:container_name: phpmyadmin_timage: phpmyadmin:5.2-apacheports:- 4090:80environment:- PMA_ARBITRARY=1- PMA_HOST=172.77.1.8- PMA_PORT=3306- PMA_USER=root- PMA_PASSWORD=cjyrestart: alwaysnetworks:back_net:ipv4_address: 172.77.1.9#自定义容器网络
networks:back_net:ipam:driver: defaultconfig:- subnet: 172.77.1.0/24
4.2 图像识别系统
百度开源AI:https://github.com/PaddlePaddle/PaddleOCR
照片OCR识别样例代码
from paddleocr import PaddleOCR, draw_ocr
ocr = PaddleOCR(use_angle_cls=True, lang="en")
img_path = './ppocr_img/imgs/11.jpg'
result = ocr.ocr(img_path, cls=True)
for idx in range(len(result)):res = result[idx]for line in res:print(line)
4.3 远程抄表前台系统
主要代码,不是全部。
<script setup>
import { ref } from 'vue'
import 'weui';
import axios from 'axios';async function get_gmr_img() {console.log('get_gmr_img')try{let res = await axios.get('/api/gmr_img_now');console.log(res);let result = res.data;console.log(result);res = await axios.get('/api/gmr_get_last_img');console.log(res);result = res.data[0];console.log(result.img_name);const imgUrl = 'http://58.212.21.66:8488/images/mask_' + result.img_name;document.getElementById('gmr_img').src = imgUrl}catch{console.log('请求失败');}
}
</script><template><img id="gmr_img" src="/favicon.ico" class=gmr_img><button class="weui-btn weui-btn_primary" @click="get_gmr_img">立即更新</button><div style="text-align:center;" id="actionsheet1" class="weui_actionsheet_cell">长按燃气表图片2秒转发给抄表员</div>
</template><style scoped>
.gmr_img {width: 100vw;height: 80vh;
}
</style>
4.4 远程抄表后台系统
CREATE TABLE `gmrinfo` (`id` bigint(12) NOT NULL,`gather_time` datetime NOT NULL DEFAULT current_timestamp(),`img_name` varchar(30) NOT NULL,`img_ocr` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
const {promises:fs} = require("fs");
const moment = require('moment');
const Koa = require('koa');
const Router = require('koa-router');
const koa_static = require('koa-static');
const bodyParser = require('koa-bodyparser');
const mqtt = require('mqtt');
const axios = require('axios');
const knex = require('knex'); //https://knexjs.org/
const gm = require('gm');const OCR_SERVER_IP = '172.77.1.6'
const OCR_SERVER_PORT = 8466const MQTT_SERVER_IP = '172.77.1.7'
const MQTT_SERVER_PORT = 1883const DB_SERVER_IP = '172.77.1.8'
const DB_USER = 'cjy'
const DB_PWD = 'cjy'
const DB_NAME = 'gmrplat'const GMRPLAT_SERVER_PORT = 8488const db = knex({client: "mysql2",connection: {host: DB_SERVER_IP,port: 3306,user: DB_USER,password: DB_PWD,database: DB_NAME,},
});const WWWROOT = __dirname + '/public'
const IMGDIR = WWWROOT + '/images/'//图像识别
const GMRToOCR = async (imgfile) => {const url = "http://" + OCR_SERVER_IP + ":" + OCR_SERVER_PORT + "/GMROCR"const bitmap = await fs.readFile(imgfile);const adata = {request_id: '001',img_base64: ''}adata['img_base64'] = Buffer.from(bitmap).toString('base64');const res = await axios.post(url, adata);console.log(res.data)console.log(res.data.ocr_res)return res.data
}const client = mqtt.connect("mqtt://" + MQTT_SERVER_IP + ":" + MQTT_SERVER_PORT);
client.subscribe("gmrdev/fixedtime")client.on('message', async (topic, payload) => {console.log('Received Message:', topic);const base64EncodedfileData = payload.toString();const fileDataDecoded = Buffer.from(base64EncodedfileData,'base64');const img_name = moment(Date.now()).format('YYYYMMDDHHmmss');fs.writeFile(IMGDIR + img_name + ".jpg", fileDataDecoded, err => {})await gmr_add_img(img_name + ".jpg")gm(IMGDIR + img_name + ".jpg").stroke("blue") //字体外围颜色.fill("blue") //字体内围颜色(不设置默认为黑色).font("./AlibabaPuHuiTi-3-65-Medium.ttf", 60) //字库所在文件夹和字体大小.drawText(50,50, img_name + "\nXX街道X小区X幢X室").write(IMGDIR + "mask_" + img_name + ".jpg", function (err) {if (!err) console.log('gm_ok');else console.log(err);});//const ocr_res = await GMRToOCR(IMGDIR + img_name + ".jpg");
});const app_http = new Koa()
app_http.use(bodyParser());app_http.use(async (ctx, next) =>{await next();ctx.set("Access-Control-Allow-Origin", "*");ctx.set("Access-Control-Allow-Headers", "Content-Type");ctx.set("Access-Control-Allow-Methods", "*");
});app_http.use(koa_static(WWWROOT, {index: true, hidden: false,defer: true
}))const gmr_add_img = async (img_name) => {console.log('gmr_add_img:' + img_name)await db('gmrinfo').insert({img_name: img_name})
}const gmr_img_now = async (ctx) => {console.log('gmr_img_now')client.publish('gmrplat/nowtime', 'now')ctx.body = 'OK'
}const gmr_get_last_img = async (ctx) => {let result = await db("gmrinfo").select(["id", "gather_time","img_name","img_ocr"]).orderBy('id', 'desc').limit(1)console.log(result)ctx.body = result
}const router = new Router();
router.get('/api/gmr_img_now', gmr_img_now);
router.get('/api/gmr_get_last_img', gmr_get_last_img);app_http.use(router.routes());app_http.listen(GMRPLAT_SERVER_PORT, '0.0.0.0', () => {console.log(`服务启动:http://58.212.21.66:${GMRPLAT_SERVER_PORT}`);
})
5.系统演示
配套代码
相关文章:

家庭燃气表微信抄表识别系统
1.背景需求 目前家里燃气度数的读数上报,每个月在社区微信群里面将手机拍摄的燃气表读数截图(加住址信息水印),发到群里给抄表员。 2.总体设计 设计目标 功能一:手机上随时可以远程采集读数图片(自动加住…...

EF执行迁移时提示provider: SSL Provider, error: 0 - 证书链是由不受信任的颁发机构颁发的
ef在执行时提示provider: SSL Provider, error: 0 - 证书链是由不受信任的颁发机构颁发的。 只需要在数据库链接字符串后增加EncryptTrue;TrustServerCertificateTrue;即可 再次执行...

视频标注的两个主要方法
视频标注技术 单一图像法 在自动化工具面世之前,视频标注效率不高。各公司使用单一图像法提取视频中的所有帧,然后使用标准图像标注技术将它们作为图像来标注。在30fps的视频中,每分钟有1800帧。这个过程没有利用视频标注的优势,…...
学成在线第一天-项目介绍、项目的搭建、开发流程以及相关面试题
目录 一、项目介绍 二、项目搭建 三、开发流程 四、相关面试题 五、总结 一、项目介绍 背景 业务 技术 背景:首先是整个这个行业的背景 然后基于这个行业的背景引出当前项目的背景 业务:功能模块 功能业务流程 技术:整体架构&am…...

《数据结构与算法之美》读书笔记1
Java的学习 方法参数多态(向上和向下转型) 向上转型: class Text{public static void main(String[] args) {Animals people1 new NiuMa();people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调…...

接口测试经验合集
一 、接口测试常见问题 前景提要:由于本人测试小白,可能所遇问题都较为基础,测试小白可以参考 1.1 postman会报 connect ECONNREFUSED jemeter会报 org.apache.http.conn.HttpHostConnectException: Connect tofailed: Connection refus…...

Leetcode—2331.计算布尔二叉树的值【简单】
2023每日刷题(六) Leetcode—2331.计算布尔二叉树的值 递归实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ bool evaluateTree(struct TreeNod…...

Java面试(基础篇)——解构Java常见的基础面试题 结合Java源码分析
fail-safe 和fail-fast机制 Fail-fast:快速失败 Fail-fast : 表示快速失败,在集合遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException 异常,从而导致遍历失败 package …...

Ubuntu 17.10的超震撼声音权限
从GNOME GUADEC 2017开发者大会归来之后,Canonical的Didier Roche就开始了一个日更博客系列,主要讲述即将带来的Ubuntu 17.10(Artful Aardvark)发行版将如何从Unity到GNOME Shell的转变。有趣的是,Ubuntu Unity桌面环境…...

图像信号处理板设计原理图:2-基于6U VPX的双TMS320C6678+Xilinx FPGA K7 XC7K420T的图像信号处理板
综合图像处理硬件平台包括图像信号处理板2块,视频处理板1块,主控板1块,电源板1块,VPX背板1块。 一、板卡概述 图像信号处理板包括2片TI 多核DSP处理器-TMS320C6678,1片Xilinx FPGA XC7K420T-1FFG1156,1片X…...

【数组】移除元素(暴力遍历×双指针√)
一、力扣题目链接 27.移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 你不需要考虑数组中超出新长度后面的元素。 二、思路 要知道数组的元素在内存地址中是连续的,不…...
【笔试题】华为研发工程师编程题
1.汽水瓶 某商店规定:三个空汽水瓶可以换一瓶汽水,允许向老板借空汽水瓶(但是必须要归还)。 小张手上有n个空汽水瓶,她想知道自己最多可以喝到多少瓶汽水。 数据范围:输入的正整数满足 1≤n≤100 1≤n≤…...

如何转换Corona和Vray材质?cr材质转vr材质的方法
cr材质转vr材质的方法一:使用CG Magic插件,一键转换 CG Magic是一款基于3ds Max深度开发的智能化辅助插件,上千项实用功能,降低渲染时长,节省时间和精力,大幅简化工作流程,助力高效完成创作。 …...

蓝桥每日一题(day 4: 蓝桥592.门牌制作)--模拟--easy
#include <iostream> using namespace std; int main() {int res 0;for(int i 1; i < 2021; i ){int b i;while(b){if (b % 10 2) res ;b / 10;}}cout << res; return 0; }...
leetcode(2)栈
leetcode 155 最小栈 stack相当于栈,先进后出 存储全部栈元素 [-3,2,-1] min_stack,存储栈当前位置最小的元素 [-3,-3,-3] class MinStack:def __init__(self):self.stack []self.min_stack [math.inf]def push(self, x: int) :self.stack.append(x)self.min_sta…...

有什么小程序可以下载视频号的视频?
最近有一些朋友问我,【视频号下载助手】和【视频下载bot】小程序,有什么作用? 首先视频号下载助手是协助用户进行下载的,但由于下载要符合平台规定,我们就将视频下载助手与视频下载bot小程序想结合的模式࿰…...

GDB调试简单介绍
最近和许多同事交流时,发现好多人只是在IDE上debug,但是gdb却一点都不了解;校招新来的同事更是都没听过gdb这个工具,所以在培训时给他们培训了一下;另外好久也没写blog了,刚好把这篇笔记简单分享一下。 0 …...

关于opencv的contourArea计算方法
cv::contourArea计算的轮廓面积并不等于轮廓点计数,原因是cv::contourArea是基于Green公式计算 老外的讨论 github 举一个直观的例子,图中有7个像素,橙色为轮廓点连线,按照contourArea的定义,轮廓的面积为橙色所包围…...

《机器学习》第6章 支持向量机
文章目录 6.1 间隔与支持向量6.2 对偶问题6.3 核函数支持向量展式核函数 6.4 软间隔与正则化6.5 支持向量回归6.6 核方法6.7 阅读材料 6.1 间隔与支持向量 分类学习最基本的想法就是基于训练集D在样本空间中找到一个划分超平面,将不同类别的样本分开.但能将训练样本分开的划分…...

Python学习基础笔记七十七——json序列化
客户端和服务端之间需要交换数据才能完成各种功能。 假设 服务端程序都是用Python语言开发的话,那么 服务端从数据库中获取的最近的交易列表,可能就是像下面这样的一个Python列表对象: historyTransactions [{time : 20170101070311, #…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...