【教程】M5Stack UnitV2应用之手写识别简易计算器
本帖最后由 沧海笑1122 于 2021-8-14 20:50 编辑【项目故事】这是一个M5Stack UnitV2的趣味应用,使用V-Training平台训练自己的手写数字笔迹,然后用M5Stack UnitV2利用目标检测识别出你的手写算式,将结果用Json串发送到M5Stack Basic上进行展示(屏显并发出语音提示)。关于M5StackUnitV2这块AI智能摄像头的基本情况,我在前一篇文章中详述,在此不再赘述,大家可以参考我的上一篇《工业应用场景下的M5Stack UnitV2应用之不良品分选》https://www.arduino.cn/thread-104690-1-1.html。一起先看看手写识别简易计算器的效果。https://www.bilibili.com/video/BV1F44y1y7D9/所谓简易计算器,是指本文仅实现了个位数的加减法计算,目的是展示UnitV2的训练、使用方式,抛砖引玉,吸引更多玩家以及更好的玩法。有趣度:★★★★难度:★★这是我一如既往的风格:好玩不难。话不多说,我们开始制作吧。
【软硬件准备】软件:
名称版本备注
1UIFLOW1.8.1设计Basic端的界面
2Thonny IDE3.3.13调试Basic的micropython程序
3V-Training平台
训练手写数字及运算符
4M5Stack UnitV2内置应用目标检测,固件版本0604
5串口调试工具
用于分步调试
硬件:
名称型号备注
1M5Stack UnitV2V2.0AI智能摄像头
2M5Stack Basic
上位机,用于解析、展示手写式以及计算结果
3USB-TTLCH340调试串口时使用,正常不需要
4Uart线三根(Tx\Rx\Gnd)
再就是一支笔、一张白纸、一个俯拍支架,再就是您的手(手写嘛)。【软件原理】lM5Stack UnitV2侧:使用内置应用的目标检测功能,将手写的数字以及运算符(如+、-、=)进行识别,并且以json格式通过uart发送至上位机处理。lM5Stack Basic侧: 这是M5Stack Basic侧的UI以及主循环设计。【制作步骤】Step1:训练手写数字及运算符模型(1) 准备若干纸卡片,用墨水笔手写数字,尽可能大小一致、字体保持一致。我准备了约30张卡片,每张有2个算式。为了简化期间,只训练了+、-、=三种运算符以及若干数字。(2) 使用自己编写的连拍程序,用UnitV2连续拍摄样本,做好取样准备。
(3) 将拍摄的样本,上传http://v-training.m5stack.com/,进行上传、建立lable以及标注工作,这些工作在M5Stack官网以及我上篇文章中都有详述,此处不再赘述。Step2:上传模型后,打开目标检测功能,测试识别以及json串的传送情况
将UnitV2固定在俯拍支架上,光源充足的情况下,手写算式,测试目标检测的效果。效果如下:注:1是刚才训练好并且上传的模型,UnitV2就是靠这个模型通过目标检测来识别你的手写录入。2是识别并且标注兴趣框的情况,3是识别后的json字符,通过uart发送至上位机进行展示。Step3:分步调试,用usb-ttl模块加上串口调试器,与M5Stack Basic通信,将收到的json串进行解析和展示。
将UnitV2识别出的Json字符串,复制在串口调试器里,就可以脱离UnitV2进行分步调试。好处是可以简化调试步骤,减少不定因素,分别对M5StackBasic以及UnitV2进行调试。注:1、减号识别并且替换成“-”;2、等号识别并且替换成“=”,3、4分别是数字的识别。
Step4:整体联调:将UnitV2(grove)与M5Stack Basic(pin21\pin22\gnd)连接,实现整体联调,在手写一个算式后,V2识别出来并且发送给M5Stack Basic,后者解析、组装算式、计算结果,并且将带有运算结果的算式展示在屏幕上,同时发出“滴”声,提醒玩家识别、计算过程结束。
如果你需要再算一组算式,只需要按“reset”键,即可清屏,为下一次识别计算做准备。
【代码】
M5Stack Basic侧:# UNITV2 之手写计算器
# 2021-08-06 测试uart1接受V2传送来的识别串,并且生成算式、计算结果并且在屏幕展示
# 2021-08-08 v2送来的Num=4的json串已经可以解析,且放入一个四元素二维数组。
# 2021-08-11 一是按钮reset。二是识别后,显示计算式以及答案,并且确保只要识别到就仅处理一次。三是识别后带语音提示
# 沧海
from m5stack import *
from m5ui import *
from uiflow import *
from easyIO import *
import json
setScreenColor(0x222222)
print("Begin...")
# 变量init
rev_str = None
rev_obj = None
rev_obj_num = None
vprob = None
vtype = None
vx = None
vy = None
vw = None
vh = None
string_result= None
#生成一个2维、四元素数组temp1 ,放置中间结果
temp1 = [['' for i in range(2)] for j in range(4)]
#temp2 是表达式以及答案
temp2 =None
#vexe 执行控制字,确保目标进入执行框后,只执行一次(计数以及吹不良品)
vexe=0
#UI INIT
Calculator = M5Title(title="Calculator 2021-08", x=3, fgcolor=0xFFFFFF, bgcolor=0x0034ff)
label1 = M5TextBox(52, 71, "Text", lcd.FONT_DejaVu56, 0xff8d08, rotate=0)
rectangle0 = M5Rect(30, 187, 80, 40, 0x0efdf9, 0xFFFFFF)
label2 = M5TextBox(37, 194, "Reset", lcd.FONT_Comic, 0x100000, rotate=0)
#Uart INIT
uart1 = machine.UART(1, tx=22, rx=21)
uart1.init(115200, bits=8, parity=None, stop=1)
def buttonA_wasPressed():
global vexe
label1.setText('') #清屏
vexe=0 #复位执行控制字
pass
btnA.wasPressed(buttonA_wasPressed)
#Main loop
while True:
try:
if uart1.any():
wait_ms(100)
rev_str = json.loads((uart1.read()).decode())
rev_obj_num=rev_str["num"]
rev_obj=rev_str["obj"]
#print(rev_obj_num)
#print(vexe)
if rev_obj_num==4 and vexe==0: #识别出完整表达式(四元素)且vexe=0
x=0
for zidian in rev_obj:
#print(type(zidian))
vtype=zidian.get("type")
vprob=zidian.get("prob")
vx=zidian.get("x")
vy=zidian.get("y")
vw=zidian.get("w")
vh=zidian.get("h")
print(vx,vy,vw,vh,vtype,vprob)
temp1=vx
if vtype is 'plus':
temp1='+'
print(temp1)
elif vtype is 'minus':
temp1='-'
print(temp1)
elif vtype is 'equal':
temp1='='
print(temp1)
else:
temp1=vtype.strip('n')
print(temp1)
x=x+1
temp1.sort() #按照坐标排序
temp2=temp1+temp1+temp1+temp1 #组装算式
temp2=temp2.strip('=')#去除'='符号
#print(temp2)
#print(eval(temp2)) #运行计算式
#eval(temp2)为执行表达式,并组装成结果字符串
string_result= temp2+'='+str(eval(temp2))
label1.setText(string_result) #在Basic上显示
speaker.sing(489, 1/4) #提示音
wait_ms(2)
vexe=1 #每次识别+显示只进行一次,随后手动清零
print('ok')
except:
print("except")
【软件知识点简述】这个小玩具里面有三个知识点需要关注学习。1、识别的中间结果怎么保存?我们建立了一个一个二维、四元素数组temp1 ,放置中间结果:temp1 = [['' for i in range(2)] for j inrange(4)]temp1 放置x坐标,temp1 放置识别出来的类型(数字或者运算符)2、我们对这个二维数组进行排序,使用以下语句:temp1.sort() 。实际上是按照temp1(即x坐标)排序,这样就使得识别出来的数据按照从左往右的顺序排列好,和我们的手写习惯是一致的。3、根据字符表达式计算运算结果, str(eval(temp2))这个语句就是完成此功能。整个M5Stack Basic侧的代码,加上注释也不到100行。UI设计及主逻辑搭建是通过UIFLOW完成的,调试工作通过thonny ide这个轻量级调试工具完成。【小结】
[*]简易手写计算器是一个有趣但简单的小玩具,由于手写数字比较简单,所以我训练了大概不到50组数据,就可以达到不错的识别效果。这也是V2的硬件支撑以及软件优化的结果吧,作为玩家,我感觉用户体验还不错。
[*]在B站有玩家留言,是否可以做得更复杂些(比如三角函数、对数运算),答案是:当然可以。
这是一个深度学习的应用,只要你的样本足够多、足够合理,识别出更加复杂的数学表达式当然没有问题,本文只是抛砖引玉,我连乘除功能都没有训练,请玩家一起进阶更加有趣的玩法吧。
[*]感谢笑笑师兄的指导以及M5Stack一众师兄的指导、鼓励,谢谢大家。
沧海抱拳。
代码和UIFLOW设计文件附后。
沧海笑1122老师写的文章条理清晰,逻辑严密值得推荐,一起学习一起进步。 topdog 发表于 2021-8-14 22:27
沧海笑1122老师写的文章条理清晰,逻辑严密值得推荐,一起学习一起进步。
感谢师兄支持
:lol 点赞,这个模块没有用过
页:
[1]