|
本帖最后由 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[400:600,400:520]
- img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度处理
- #自动阈值二值化 把图片处理成黑底白字
- img_temp = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)[1]
- 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)[1]
- kernel = np.ones((10, 10), np.uint8)
- img_temp = cv2.dilate(img_temp, kernel, iterations = 1)
- img_t = []
- img_t.append(img_temp[400:600,280:400]) #裁剪第一个数字
- img_t.append(img_temp[400:600,400:520]) #裁剪第二个数字
- cv2.imshow("img_t0",img_t[0])
- cv2.imshow("img_t1",img_t[1])
- 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)[1]
- #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)[1]).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[0]+num[1]
- 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))
复制代码
|
|