esp32cam+openCV图像分析传统家电LED面板数据反馈bliner APP
本帖最后由 yuezhiying 于 2022-4-27 17:56 编辑blinker改造一些传统家电时,比如热水器、空调等代有LED数字面板的设备时,用esp32或者8266进行远程红外遥控非常容,但无法得知遥控结果,不能得到返回数据。
此方案通过用blinker APP 控制ESP32CAM对LED面板拍照后,将图片通过TCP发送至python架设的openCV图像分析程序的服务器,对图像进行分析,得到面板数据上的数据后,返回给ESP32CAM,ESP32CAM得到数据后在反馈给blinker APP,从而实现传统家电的LED面板图像信息数字化的转换。
python openCV程序 就是开启了一个TCP server端等待图像接收,接受到图像后,通过openCV的模板匹配功能进行数字分析,因为这个应用场景时固定的,内容就上0-9的数字,所以不需要复杂的图形处理,只需要先把0-9的数字都拍照一遍制作成模板,在收到图像后对固定位置数字的图形区域进行裁剪,然后就行轮询匹配找到最相似的图形的索引号便得到数字结果。
python程序为3.1版本,需要安装openCV库。该代码模板匹配并通用,需要自行先将被识别的数字0-9先采集一遍保存至程序目录下的/num目录中作为模板,被识别的数字位置需要根据实际情况裁剪位置坐标。
import cv2
import numpy as np
from imutils import contours
import socket
import time
MaxBytes=1024*3024
def load_digits():
# 加载数字模板
dig= []
for q in range(0,10):
img = cv2.imread("./num/num"+str(q)+".jpg") # 读取图片
img = img
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度处理
#自动阈值二值化 把图片处理成黑底白字
img_temp = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)
kernel = np.ones((10, 10), np.uint8)
img_temp = cv2.dilate(img_temp, kernel, iterations = 1)
# cv2.imshow('num'+str(q), img_temp)
dig.append(img_temp)#数字模板存入dig
return dig
def cont_digits(img):
#模板匹配数字
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_temp = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)
kernel = np.ones((10, 10), np.uint8)
img_temp = cv2.dilate(img_temp, kernel, iterations = 1)
img_t = []
img_t.append(img_temp)#裁剪第一个数字
img_t.append(img_temp)#裁剪第二个数字
cv2.imshow("img_t0",img_t)
cv2.imshow("img_t1",img_t)
num_out = []
for img_T in img_t: #对每个数字循环匹配十个数字模板
source = []
for dig_T in dig:
res = cv2.matchTemplate(img_T, dig_T, cv2.TM_CCOEFF_NORMED)
max_val = cv2.minMaxLoc(res)
#print(max_val)
source.append(max_val) #每个模板匹配值存入source
num_out.append(str(source.index(max(source)))) #取source最大值的索引号为匹配到的数字
return num_out
#print(num_out)
def bytes2cv(im):
'''二进制图片转cv2
:param im: 二进制图片数据,bytes
:return: cv2图像,numpy.ndarray
'''
return cv2.imdecode(np.array(bytearray(im), dtype='uint8'), cv2.IMREAD_UNCHANGED)# 从二进制图片数据中读取
def cv2bytes(im):
'''cv2转二进制图片
:param im: cv2图像,numpy.ndarray
:return: 二进制图片数据,bytes
'''
return np.array(cv2.imencode('.png', im)).tobytes()
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.settimeout(None)
host = '192.168.2.162'
#host = socket.gethostname()
port = 8889
server.bind((host, port)) # 绑定端口
j = 0
server.listen(1) # 监听
dig = load_digits()
while True:
try:
client,addr = server.accept() # 等待客户端连接
imgdata = []
print(addr," 连接上了")
while True:
data = client.recv(MaxBytes)
if not data:
print('接收结束')
break
localTime = time.asctime( time.localtime(time.time()))
print(localTime,' 接收到数据字节数:',len(data))
if len(data) == 1 and data == b' ':
print('接收结束')
break
imgdata.append(data)
a = bytes()
for i in imgdata:
a = a + i
img = bytes2cv(a)#接收到的二进制图像数据转换成openCV图像
num = cont_digits(img)#进行图像分析
print(num)#打印分析结果
out_num = num+num
client.send(out_num.encode('utf-8'))#向客户端返回分析结果
cv2.imshow("fcrame",img)
key = cv2.waitKey(1) & 0xFF
# 按'q'健退出循环
if key == ord('q') or cv2.waitKey(1)&0xff == 27:
break
except BaseException as e:
print("出现异常:")
print(repr(e))
实测效果
该方案虽然有点绕弯子,但是适用方向比较广,只要可以拍照的面板都可做识别,无需修改硬件获取反馈数据。
图像识别服务器可以搭建在公网,给不同得设备公用,或者搭建在家里的nas、树莓派、香橙派等都可。
Arduino 代码中使用了esp32cam.h库在附件中下载,blinker程序只是测试返回数据,没有写其他功能。
#define BLINKER_WIFI
#include <Blinker.h>
#include <esp32cam.h>
static auto hiRes = esp32cam::Resolution::find(800, 600);
char auth[] = "*****";
char ssid[] = "******";
char pswd[] = "******";
const uint16_t port = 8889;//python openCV服务器端口
const char * host = "192.168.2.162"; //python openCV服务器地址
// 新建组件对象
BlinkerButton Button1("btn-up");
BlinkerButton Button2("btn-down");
BlinkerNumber Number1("num");
int counter = 0;
// 按下按键即会执行该函数
void button1_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
serveJpg();
}
void button2_callback(const String & state)
{
BLINKER_LOG("get button state: ", state);
serveJpg();
}
// 如果未绑定的组件被触发,则会执行其中内容
void dataRead(const String & data)
{
BLINKER_LOG("Blinker readString: ", data);
}
void serveJpg()
{
auto frame = esp32cam::capture();
if (frame == nullptr) {
Serial.println("CAPTURE FAIL");
return;
}
Serial.printf("CAPTURE OK %dx%d %db\n", frame->getWidth(), frame->getHeight(),
static_cast<int>(frame->size()));
WiFiClient client;
client.connect(host, port);
frame->writeTo(client);
delay(100);
client.write(" ");
while (client.connected() || client.available()){
if (client.available()){
String line = client.readString();
Serial.println(line);
Number1.print(line.toInt());
client.stop();
}
}
}
void setup()
{
// 初始化串口
Serial.begin(115200);
BLINKER_DEBUG.stream(Serial);
//BLINKER_DEBUG.debugAll();
// 初始化blinker
Blinker.begin(auth, ssid, pswd);
Blinker.attachData(dataRead);
Button1.attach(button1_callback);
Button2.attach(button2_callback);
{
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(hiRes);
cfg.setBufferCount(2);
cfg.setJpeg(80);
bool ok = Camera.begin(cfg);
Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
}
}
void loop() {
Blinker.run();
}
该项目未使用系统自带esp32cam库,使用附件中的库。
希望不是搬的,才刚刷到视频,支持ZR 刚在抖音看了,很棒。
其实我们也在服务器上装了OCR和人脸识别,但对服务器压力比较大,还在研究如何提供服务。
我觉得自己部署也是个很好的方式,我们会考虑下提供一个自己部署识别的方案。 点灯官方 发表于 2022-4-27 21:33
刚在抖音看了,很棒。
其实我们也在服务器上装了OCR和人脸识别,但对服务器压力比较大,还在研究如何提供服 ...
那可太好了,希望点灯科技越做越好! 15行的 img[ 200:540,120:670] 这个img的参数怎么解读?模板有什么要求吗,能有白边吗?我运行起来的识别正确率很低. 太棒了,我也真想用这种方法来改造一下我的热水器。
页:
[1]