云天 发表于 2023-4-11 09:29:41

行空板——手写点阵屏

本帖最后由 云天 于 2023-4-11 09:29 编辑



【项目背景】
本项目要实现行空板无线手写投点阵屏。
【项目设计】
本项目结合行空板屏幕上手写加python os库截屏,再分析图像上的手写痕迹,获取坐标,通过TCP发送给Ardunio,点亮点阵屏。
【点阵屏】
https://mc.dfrobot.com.cn/forum.php?mod=attachment&aid=Nzg3Mzh8ZWIzMzkxMjd8MTY4MTAzODQyNHw4Mjc3ODR8Mjk2NzQ1&noupdate=yes
通过DF官网学习一下如何使用。https://wiki.dfrobot.com.cn/_SKU_DFR0471_32x16_RGB_LED_Matrix_-_6mm_pitch
https://mc.dfrobot.com.cn/forum.php?mod=attachment&aid=Nzg3Mzl8ZTQ0MmQ4NzJ8MTY4MTAzODQyNHw4Mjc3ODR8Mjk2NzQ1&noupdate=yes

https://mc.dfrobot.com.cn/forum.php?mod=attachment&aid=Nzg3NDB8ZWRhMDNmYTh8MTY4MTAzODQyNHw4Mjc3ODR8Mjk2NzQ1&noupdate=yes
结合以上两图,连接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 OE9
#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())) {
Stringmystr=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([, ])
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()
    high = np.array()

    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()
    if len(pos_xy) > 1:
      point_start = pos_xy
      for pos_tmp in pos_xy:
            point_end = pos_tmp
            line_text = u_gui.draw_line(x0=point_start,y0=point_start,x1=point_end,y1=point_end,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 OE9
#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));
// drawtext!
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;
int i=0;
do
{
    weizhi = str.indexOf(fen);
    if(weizhi != -1)
    {
      temps =str.substring(0,weizhi);
      str = str.substring(weizhi+fen.length(),str.length());
      i++;
      }
      else {
      if(str.length()>0)
      temps = str;
      }
}
while(weizhi>=0);

if(index>i)return "-1";
return temps.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=="";
      }
}




【演示视频】
https://www.bilibili.com/video/BV1L24y1w7oc/?share_source=copy_web&vd_source=98855d5b99ff76982639c5ca6ff6f528



macCosmo 发表于 2023-4-13 15:46:56

66666666666

若晗 发表于 2023-5-4 14:29:14

学习了,感谢分享

少东 发表于 2024-2-22 11:13:16

看完直呼过瘾,哈哈哈哈哈{:7_216:}

刘睿鹏 发表于 2024-6-16 12:35:59

厉害666学到了!
页: [1]
查看完整版本: 行空板——手写点阵屏