首页 分享 stm32方案——手写识别实验

stm32方案——手写识别实验

来源:花匠小妙招 时间:2024-11-28 17:35


       关于手写识别原理,我们就介绍到这里。如果想自己实现手写识别,那得花很多时间学习和研究,但是如果只是应用的话,那么就只需要知道怎么用就OK了,相对来说,简单的多。

       ALIENTEK提供了一个数字字母识别库,这样我们不需要关心手写识别是如何实现的,只需要知道这个库怎么用,就能实现手写识别。ALIENTEK提供的手写识别库由4个文件组成:

ATKNCR_M_V2.0.lib、ATKNCR_N_V2.0.lib、atk_ncr.c和atk_ncr.h。      

       ATKNCR_M_V2.0.lib和ATKNCR_N_V2.0.lib是两个识别用的库文件(两个版本),使用的时候,选择其中之一即可。ATKNCR_M_V2.0.lib用于使用内存管理的情况,用户必须自己实现alientek_ncr_malloc和alientek_ncr_free两个函数。而ATKNCR_N_V2.0.lib用于不使用内存管理的情况,通过全局变量来定义缓存区,缓存区需要提供至少3K左右的RAM。大家根据自己的需要,选择不同的版本即可。ALIENTEK手写识别库资源需求:FLASH:52K左右,RAM:6K左右。

       atk_ncr.c代码如下:

#include "atk_ncr.h"

#include "malloc.h"

//内存设置函数

void alientek_ncr_memset(char *p,char c,unsigned long len)

{

       mymemset((u8*)p,(u8)c,(u32)len);

}                                       

//内存申请函数

void *alientek_ncr_malloc(unsigned int size)

{

       return mymalloc(SRAMIN,size);

}

//内存清空函数

void alientek_ncr_free(void *ptr)

{

       myfree(SRAMIN,ptr);

}              

这里,主要实现了alientek_ncr_malloc、alientek_ncr_free和alientek_ncr_memset等三个函数。

       atk_ncr.h则是识别库文件同外部函数的接口函数声明

#ifndef __ATK_NCR_H

#define __ATK_NCR_H

//当使用ATKNCR_M_Vx.x.lib的时候,不需要理会ATK_NCR_TRACEBUF1_SIZE和

//ATK_NCR_TRACEBUF2_SIZE

//当使用ATKNCR_N_Vx.x.lib的时候,如果出现识别死机,请适当增加

//ATK_NCR_TRACEBUF1_SIZE和ATK_NCR_TRACEBUF2_SIZE的值

#define ATK_NCR_TRACEBUF1_SIZE      500*4   

//定义第一个tracebuf大小(单位为字节),如果出现死机,请把该数组适当改大

#define ATK_NCR_TRACEBUF2_SIZE      250*4     

//定义第二个tracebuf大小(单位为字节),如果出现死机,请把该数组适当改大

//输入轨迹坐标类型

__packed typedef struct _atk_ncr_point

{

       short x;   //x轴坐标

       short y;   //y轴坐标

}atk_ncr_point;            

//外部调用函数

//初始化识别器

//返回值:0,初始化成功

//       1,初始化失败

unsigned char alientek_ncr_init(void);

void alientek_ncr_stop(void);       //停止识别器

//识别器识别

//track:输入点阵集合

//potnum:输入点阵的点数,就是track的大小

//charnum:期望输出的结果数,就是你希望输出多少个匹配结果

//mode:识别模式

//1,仅识别数字

//2,进识别大写字母

//3,仅识别小写字母

//4,混合识别(全部识别)

//result:结果缓存区(至少为:charnum+1个字节)

void alientek_ncr(atk_ncr_point * track,int potnum,int charnum,unsigned char mode,char*result);

void alientek_ncr_memset(char *p,char c,unsigned long len); //内存设置函数

//动态申请内存,当使用ATKNCR_M_Vx.x.lib时,必须实现.

void *alientek_ncr_malloc(unsigned int size);                    

//动态释放内存,当使用ATKNCR_M_Vx.x.lib时,必须实现.

void alientek_ncr_free(void *ptr);                                             

#endif

       此段代码中,我们定义了一些外部接口函数以及一个轨迹结构体等。

alientek_ncr_init,该函数用与初始化识别器,该函数在.lib文件实现,在识别开始之前,我们应该调用该函数。

alientek_ncr_stop,该函数用于停止识别器,在识别完成之后(不需要再识别),我们调用该函数,如果一直处于识别状态,则没必要调用。该函数也是在.lib文件实现。

alientek_ncr,该函数就是识别函数了。它有5个参数,第一个参数track,为输入轨迹点的坐标集(最好200以内);第二个参数potnum,为坐标集点坐标的个数;第三个参数charnum,为期望输出的结果数,即希望输出多少个匹配结果,识别器按匹配程度排序输出(最佳匹配排第一);第四个参数mode,该函数用于设置模式,识别器总共支持4中模式:

1,仅识别数字

2,进识别大写字母

3,仅识别小写字母

4,混合识别(全部识别)

最后一个参数是result,用来输出结果,注意这个结果是ASCII码格式的。

alientek_ncr_memset、alientek_ncr_free和alientek_ncr_free这3个函数在atk_ncr.c里面实现,这里就不多说了。

最后,我们看看通过ALIENTEK提供的手写数字字母识别库实现数字字母识别的步骤:

1) 调用alientek_ncr_init函数,初始化识别程序

该函数用来初始化识别器,在手写识别进行之前,必须调用该函数。

2) 获取输入的点阵数据

此步,我们通过触摸屏获取输入轨迹点阵坐标,然后存放到一个缓存区里面,注意至少要输入2个不同坐标的点阵数据,才能正常识别。注意输入点数不要太多,太多的话,需要更多的内存,我们推荐的输入点数范围:100~200点。

3) 调用alientek_ncr函数,得到识别结果.

通过调用alientek_ncr函数,我们可以得到输入点阵的识别结果,结果将保存在result参数里面,采用ASCII码格式存储

4) 调用alientek_ncr_stop函数,终止识别.

如果不需要继续识别,则调用alientek_ncr_stop函数,终止识别器。如果还需要继续识别,重复步骤2和步骤3即可。  

以上4个步骤,就是使用ALIENTEK手写识别库的方法,十分简单。

51.2 硬件设计

本章实验功能简介:开机的时候先初始化手写识别器,然后检测字库,之后进入等待输入状态。此时,我们在手写区写数字/字符,在每次写入结束后,自动进入识别状态,进行识别,然后将识别结果输出在LCD模块上面(同时打印到串口)。通过按KEY0可以进行模式切换(4种模式都可以测试),通过按KEY2,可以进入触摸屏校准(如果发现触摸屏不准,请执行此操作)。DS0用于指示程序运行状态。

本实验用到的资源如下:

1)  指示灯DS0

2)  KEY0和KEY2两个按键

3)  串口

4)  TFTLCD模块(含触摸屏)

5)  SPI FLASH

这些用到的硬件,我们在之前都已经介绍过,这里就不再介绍了。

51.3 软件设计

打开上一章的工程,首先在HARDWARE文件夹所在的文件夹下新建一个ATKNCR的文件夹。将ALIETENK提供的手写识别库文件(ATKNCR_M_V2.0.lib、ATKNCR_N_V2.0.lib、atk_ncr.c和atk_ncr.h这四个个文件,在光盘à 4,程序源码à ATKNCR(数字字母手写识别库) 文件夹里面)拷贝到该文件夹下,然后在工程里面新建一个ATKNCR的组,将atk_ncr.c和ATKNCR_M_V2.0.lib加入到该组下面(这里我们使用内存管理版本的识别库)。最后,将ATKNCR文件夹加入头文件包含路径。

关于ATKNCR_M_V2.0.lib和atk_ncr.c前面已有介绍,我们这里就不再多说,我们在test.c里面修改main函数如下:

//最大记录的轨迹点数

atk_ncr_point READ_BUF[200];                              

int main(void)

{            

      u8 i=0;               

       u8 tcnt=0;   

       u8 res[10];

       u8 key;               

       u16 pcnt=0;

       u8 mode=4;                  //默认是混合模式                 

      Stm32_Clock_Init(9);    //系统时钟设置

       delay_init(72);                     //延时初始化

       uart_init(72,9600);      //串口1初始化      

       LCD_Init();                  //初始化液晶

       LED_Init();           //LED初始化

       KEY_Init();                  //按键初始化  

       TP_Init();                 //触摸屏初始化

       usmart_dev.init(72);      //usmart初始化     

      mem_init(SRAMIN);     //初始化内部内存池     

       alientek_ncr_init();        //初始化手写识别

       POINT_COLOR=RED;      

      while(font_init())         //检查字库

       {         

              LCD_ShowString(60,50,200,16,16,"Font Error!"); delay_ms(200);                  

              LCD_Fill(60,50,240,66,WHITE);//清除显示           

       }

RESTART:

      Show_Str(60,10,200,16,"战舰 STM32开发板",16,0);                                       

       Show_Str(60,30,200,16,"手写识别实验",16,0);                                   

       Show_Str(60,50,200,16,"正点原子@ALIENTEK",16,0);                                   

       Show_Str(60,70,200,16,"KEY0:MODE KEY2:Adjust",16,0);                     

       Show_Str(60,90,200,16,"识别结果:",16,0);                  

       LCD_DrawRectangle(19,114,220,315);

      POINT_COLOR=BLUE;      

       Show_Str(96,207,200,16,"手写区",16,0);   

       tcnt=100;

       while(1)

       {

              key=KEY_Scan(0);

              if(key==KEY_LEFT)

              {

                     TP_Adjust();        //屏幕校准

                     LCD_Clear(WHITE);

                     goto RESTART;     //重新加载界面

              }

              if(key==KEY_RIGHT)  

              {

                     LCD_Fill(20,115,219,314,WHITE);//清除当前显示

                     mode++;

                     if(mode>4)mode=1;

                     switch(mode)

                     {

                            case 1: Show_Str(80,207,200,16,"仅识别数字",16,0); break;                    

                            case 2: Show_Str(64,207,200,16,"仅识别大写字母",16,0); break;            

                            case 3: Show_Str(64,207,200,16,"仅识别小写字母",16,0); break;   

                            case 4: Show_Str(88,207,200,16,"全部识别",16,0); break;

                     }

                     tcnt=100;

              }               

             tp_dev.scan(0);//扫描

             if(tp_dev.sta&TP_PRES_DOWN)//有按键被按下

              {                           

                     delay_ms(1);//必要的延时,否则老认为有按键按下.

                    tcnt=0;//松开时的计数器清空                     

                     if((tp_dev.x<220&&tp_dev.x>=20)&&(tp_dev.y<315&&tp_dev.y>=115))

                     {                  

                            TP_Draw_Big_Point(tp_dev.x,tp_dev.y,BLUE);//画图

                            if(pcnt<200)//总点数少于200

                            {

                                   if(pcnt)

                                   {

                                          if((READ_BUF[pcnt-1].y!=tp_dev.y)&&(READ_BUF[pcnt-1].x!=

tp_dev.x))//x,y不相等

                                          {

                                                 READ_BUF[pcnt].x=tp_dev.x;

                                                 READ_BUF[pcnt].y=tp_dev.y;

                                                 pcnt++;

                                          }     

                                   }else

                                   {

                                          READ_BUF[pcnt].x=tp_dev.x;

                                          READ_BUF[pcnt].y=tp_dev.y;

                                          pcnt++;

                                   }              

                            }                                                                          

                     }  

              }else //按键松开了

              {

                     i++;tcnt++;delay_ms(10); //延时识别      

                     if(tcnt==40)

                     {

                            if(pcnt)//有有效的输入        

                            {

                                   printf("总点数:%d",pcnt);

                                   alientek_ncr(READ_BUF,pcnt,6,mode,(char*)res);

                                   printf("识别结果:%s",res);

                                   pcnt=0;                                                  

                                  POINT_COLOR=BLUE;//设置画笔蓝色

                                  LCD_ShowString(60+72,90,200,16,16,res);

                            }

                            LCD_Fill(20,115,219,314,WHITE);

                     }

              }  

              if(i==30) { i=0; LED0=!LED0;}                          

       }                                                                                                     

}

该函数同触摸屏实验的main函数有点类似,不过加入了一些处理,以实现51.1.2节提到的功能。其中,READ_BUF用来存储输入轨迹点阵,大小为200,即最大输入不能超过200点,注意:这里我们采集的都是不用的点阵(即相邻的坐标不相等)。这样可以大大减少重复点阵的大小,而重复点阵对识别是没有帮助的。

至此,本实验的软件设计部分结束。

51.4 下载验证

在代码编译成功之后,我们下载代码到ALIENTEK战舰STM32开发板上,得到,如图51.4.1所示:



图51.4.1 手写识别界面

此时,我们在手写区写数字/字母,即可得到识别结果,如图51.4.2所示:



图51.4.2 手写识别结果

按下KEY0可以切换识别模式,同时在识别区提示当前模式。按下KEY2可以进行屏幕校准。每次识别结束,会在串口打印本次识别的输入点数和识别结果,大家可以通过串口助手查看。


相关知识

深度学习文本识别数据集
基于STM32的智能花盆控制系统设计
基于STM32单片机的鲜花售卖机系统设计
基于STM32单片机的环境监测系统设计与实现
基于STM32的智能浇花系统
遗传标记的发展和分子标记的检测技术(2001年)资源
实验 种子识别和培养基质识别
基于STM32的植物浇水系统开发
【10月23日】机器学习实战(一)KNN算法:手写识别系统
在线识别汉字

网址: stm32方案——手写识别实验 https://www.huajiangbk.com/newsview764593.html

所属分类:花卉
上一篇: 【图】解读低配车 图解最低配北京
下一篇: iPhone有望提供实时手写识别

推荐分享