本帖最后由 云天 于 2023-4-11 09:29 编辑
【项目背景】
本项目要实现行空板无线手写投点阵屏。
【项目设计】
本项目结合行空板屏幕上手写加python os库截屏,再分析图像上的手写痕迹,获取坐标,通过TCP发送给Ardunio,点亮点阵屏。
【点阵屏】
通过DF官网学习一下如何使用。https://wiki.dfrobot.com.cn/_SKU_DFR0471_32x16_RGB_LED_Matrix_-_6mm_pitch
结合以上两图,连接Arduino与点阵屏。
【Arduino连接WIFI】
使用WiFiBee-MT7681,插在Arduino扩展板上。
【硬件展示】
【测试显示】
行空板联网,加载socket库,按下A键发送“A”,按下B键发送“B”。
- s.connect(('192.168.31.38',1000))
复制代码
“192.168.31.38”,是WiFiBee-MT7681联网IP地址。
-
- import socket
- from unihiker import GUI
- i=0
- # 事件回调函数
- def on_buttonb_click_callback():
- s.send(b'B')
- def on_buttona_click_callback():
- s.send(b'A')
-
- u_gui=GUI()
- u_gui.on_a_click(on_buttona_click_callback)
- u_gui.on_b_click(on_buttonb_click_callback)
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.connect(('192.168.31.38',1000))
-
- while True:
- pass
复制代码
Arduino利用串口接收WiFiBee-MT7681信息,接收“A”点阵屏显示字母“A",接收“B”清屏。
-
-
- #include <Adafruit_GFX.h>
- #include <RGBmatrixPanel.h>
-
- #define CLK 8
- #define LAT A3
- #define OE 9
- #define A A0
- #define B A1
- #define C A2
- RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
-
- void setup() {
- Serial.begin(115200);
- matrix.begin();
- matrix.fillScreen(matrix.Color333(0, 0, 0));
-
- matrix.setCursor(1, 0);
- matrix.setTextSize(1);
- matrix.setTextColor(matrix.Color333(7,0,0));
- }
-
- void loop() {
-
-
- if ((Serial.available())) {
- String mystr=Serial.readString();
- if(mystr=="B"){
- matrix.fillScreen(matrix.Color333(0, 0, 0));
- }
- else{
- matrix.print(mystr);
- }
-
- }
-
复制代码
【发送坐标信息】
行空板Python程序获取手写痕迹,发痕迹坐标。
-
- import socket
- from unihiker import GUI
- import time
- import os
- import cv2
- import numpy as np
- pos_xy = []
- # 图像旋转(以原点(0,0)为中心旋转)
- def image_rotate(src, rotate=0):
- h,w,c = src.shape
- cos_val = np.cos(np.deg2rad(rotate))
- sin_val = np.sin(np.deg2rad(rotate))
- M = np.float32([[cos_val, -sin_val, 0], [sin_val, cos_val, 0]])
- img = cv2.warpAffine(src, M, (w,h))
- return img
- # 事件回调函数
- def on_buttonb_click_callback():
- u_gui.clear()
- s.send(b'B')
-
- def on_buttona_click_callback():
- os.system("scrot -a 0,0,240,320 sc.png")
- img = cv2.imread("sc.png")
- img=cv2.resize(img,(16,32))
-
- hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 色彩空间转换为hsv,分离.
-
- #色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等。
- #饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
- #明度(V),取0-100%。
- #OpenCV中H,S,V范围是0-180,0-255,0-255
- low = np.array([0, 0, 0])
- high = np.array([180, 255, 46])
-
- dst = cv2.inRange(src=hsv, lowerb=low, upperb=high) # HSV高低阈值,提取图像部分区域
-
- #寻找白色的像素点坐标。
- #白色像素值是255,所以np.where(dst==255)
- xy = np.column_stack(np.where(dst==255))
- mystr=b''
- k=0
- for c in xy:
-
- for d in c:
- mystr=mystr+b","+str(d).encode()
- k+=1
- if k==10:
- mystr=str(k).encode()+mystr
- print(mystr)
- s.send(mystr)
- k=0
- mystr=b''
- time.sleep(2)
- if k>0:
- mystr=str(k).encode()+mystr
- print(mystr)
- s.send(mystr)
-
- u_gui=GUI()
- u_gui.on_a_click(on_buttona_click_callback)
- u_gui.on_b_click(on_buttonb_click_callback)
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.connect(('192.168.31.38',1000))
- def mouse_move(x, y):# 画线
- global temp_time
- temp_time = time.time()
- '''
- 首先判断pos_xy列表中是不是至少有两个点了
- 然后将pos_xy中第一个点赋值给point_start
- 利用中间变量pos_tmp遍历整个pos_xy列表
- point_end = pos_tmp
- 画point_start到point_end之间的线
- point_start = point_end
- 这样,不断地将相邻两个点之间画线,就能留下鼠标移动轨迹了
- '''
- pos_xy.append([x,y])
- if len(pos_xy) > 1:
- point_start = pos_xy[0]
- for pos_tmp in pos_xy:
- point_end = pos_tmp
- line_text = u_gui.draw_line(x0=point_start[0],y0=point_start[1],x1=point_end[0],y1=point_end[1],width=20, color=(0,0,0))
- point_start = point_end
-
- def on_release(event):
- pos_xy.clear()
-
- u_gui.master.bind("<ButtonRelease>", on_release)# 抬笔检测
-
- u_gui.on_mouse_move(mouse_move) #鼠标检测
-
- while True:
- #增加等待,防止程序退出和卡住
- time.sleep(0.5)
-
复制代码
【Arduino接收显示】
使用自定义函数fenge,分割接收的字符串坐标,利用matrix.drawPixel点亮坐标。
- #include <Adafruit_GFX.h>
- #include <RGBmatrixPanel.h>
-
- #define CLK 8
- #define LAT A3
- #define OE 9
- #define A A0
- #define B A1
- #define C A2
- RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, false);
-
- void setup() {
- Serial.begin(115200);
- matrix.begin();
- matrix.fillScreen(matrix.Color333(0, 0, 0));
- // draw text!
- matrix.setCursor(1, 0);
- matrix.setTextSize(1);
- matrix.setTextColor(matrix.Color333(7,0,0));
- }
- int fenge(String str,String fen,int index)
- {
- int weizhi;
- String temps[str.length()];
- int i=0;
- do
- {
- weizhi = str.indexOf(fen);
- if(weizhi != -1)
- {
- temps[i] = str.substring(0,weizhi);
- str = str.substring(weizhi+fen.length(),str.length());
- i++;
- }
- else {
- if(str.length()>0)
- temps[i] = str;
- }
- }
- while(weizhi>=0);
-
- if(index>i)return "-1";
- return temps[index].toInt();
- }
-
- String Mystr = "";//声明字符串变量
-
- void loop() {
-
-
-
-
- if (Serial.available() > 0)
- { Mystr=Serial.readString();
- if(Mystr=="B"){
- matrix.fillScreen(matrix.Color333(0, 0, 0));
- }
- else{
- int num=fenge(Mystr,",",0);
- for(int i=1;i<=num-1;i=i+2){
- int pose0=31-fenge(Mystr,",",i);
- int pose1=fenge(Mystr,",",i+1);
- matrix.drawPixel(pose0,pose1, matrix.Color333(7, 7, 7));
- }
- }
- Mystr=="";
- }
- }
复制代码
【演示视频】
|