这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » ESP32手写识别

共1条 1/1 1 跳转至

ESP32手写识别

高工
2026-04-19 13:38:14     打赏
一、硬件介绍Elecrow ESP32 4.3 英寸显示屏是一款性能强劲的 HMI 触摸屏,配备 480*272 分辨率的 LCD 显示屏。其主控处理器采用 ESP32 - S3 - WROOM - 1 - N4R2 模组,具备双核 32 位 LX7 处理器,集成 WiFi 和蓝牙无线功能,主频高达 240MHz,强大的性能使其适用于物联网应用设备等多种场景。不过,该开发板的触摸屏为电阻屏,显示效果欠佳,且触摸反应较慢。

 LED 灯板,由 64 颗 LED 构成显示屏,使用 HC959 进行级联。


二、任务选择

可供选择的任务具有一定难度,本次选择任务一:手写识别显示,使用 LVGL 编程实现。具体要求为在 LCD 屏幕上设置正方形写字区域,用户可在该区域内书写 0 - 9 的数字,系统对书写数字进行识别后,将结果传递给灯板并在灯板上显示相关信息。


三、任务分析手写识别显示任务可分解为手写数据收集和手写识别两个部分:手写数据收集:借助 LVGL 构建用户交互 UI 界面,获取用户输入。将用户输入内容转换为指定格式的图片,获取后续识别结果并展示。手写识别:针对 UI 提供的数字图片进行数字识别,需引入 AI 技术,有以下两种思路:思路 1:通过串口或网络将图片上传至上位机,上位机利用成熟的框架(如 Scikit - learn、TensorFlow、PyTorch 等)进行识别,再将结果返回下位机展示。此思路优势在于上位机 AI 模型选择不受限,下位机压力小;缺点是 ESP32 - S3 无法独立完成识别,依赖后台及网络或串口。思路 2:直接在 ESP32 - S3 上调用 AI 模型识别图片。优势是所有任务可在开发板上实现;缺点是对 ESP32 - S3 压力较大,可选 AI 框架有限,已知仅有 tinyml 框架可用。本项目采用手搓 tinyml 的方式实现任务,edgeimpulse 网站可提供机器学习在开发板上部署的完整方案。


image.png

手写识别显示任务可分解为手写数据收集和手写识别两个部分:手写数据收集:借助 LVGL 构建用户交互 UI 界面,获取用户输入。原本考虑使用 LVGL 下的 lv_lib_100ask 包,该包实现了对画板的增强接口,理论上能更便捷地实现手写功能。然而,在实际尝试使用过程中,总是遭遇编译报错问题,经过多次排查仍无法解决。因此,只能转而使用 LVGL 里边的“canvas”控件来设置手写区域,以提供给用户手写输入。为了最终获取 28X28 的图片,手写区域设定为 28 的倍数,这里采用了 196X196 个像素的矩形用作用户输入区域。在实现手写模拟方面,当检测到用户触摸到指定区域时,就在该坐标上绘制一个指定半径的圆,通过这种方式来模拟用户在屏幕上的绘制动作,为用户营造出较为自然的手写体验环境。手写识别:针对 UI 提供的数字图片进行数字识别,需引入 AI 技术,有以下两种思路:通过串口或网络将图片上传至上位机,上位机利用成熟的框架(如 Scikit - learn、TensorFlow、PyTorch 等)进行识别,再将结果返回下位机展示。此思路优势在于上位机 AI 模型选择不受限,下位机压力小;缺点是 ESP32 - S3 无法独立完成识别,依赖后台及网络或串口。直接在 ESP32 - S3 上调用 AI 模型识别图片。优势是所有任务可在开发板上实现;缺点是对 ESP32 - S3 压力较大,可选 AI 框架有限,已知仅有 tinyml 框架可用。本项目采用手搓 tinyml 的方式实现任务,edgeimpulse 网站可提供机器学习在开发板上部署的完整方案。


代码

// 绘制小圆圈 半径固定为 
void draw_circle_on_canvas(int16_t x, int16_t y)
{
    lv_draw_arc_dsc_t arc_dsc;              // 创建弧线绘制描述符
    lv_draw_arc_dsc_init(&arc_dsc);         // 初始化描述符
    arc_dsc.color = lv_color_hex(0xFF4500); // 设置弧线颜色
    arc_dsc.width = 5;                      // 设置弧线宽度
    // 绘制一个完整的圆形
    lv_canvas_draw_arc(canvas, x, y, 5, 0, 360, &arc_dsc);
}
// 创建一个 CANVAS 绘画区
static void lv_drawimage_cavas(void)
{
    canvas = lv_canvas_create(lv_scr_act());
    lv_canvas_set_buffer(canvas, imgbuffer, IMAGE_LENGTH, IMAGE_LENGTH, LV_IMG_CF_TRUE_COLOR);
    lv_obj_align(canvas, LV_ALIGN_CENTER, 0, 0);
    lv_canvas_fill_bg(canvas, lv_color_hex(0x0000CD), LV_OPA_COVER);
    identifyNUM = ' ';
    memset(identifyNUMdetail, 0, 160);
    lv_event_send(identify_value_lable, LV_EVENT_VALUE_CHANGED, NULL);
}

手绘数据收集转换过程如下:以屏幕上 196×196 像素矩形区域为输入,得到(196,196,2)阶点数据矩阵(RGB565 格式)。背景色为蓝色,手写轨迹为偏红色(0xFF4500)。识别需用(28,28)字节矩阵,因此进行转换。鉴于手写轨迹颜色集中于高字节,背景色在低字节,直接舍弃低字节保留高字节。接着,将每 7×7(196/28)矩阵数据累加求均值,作为新矩阵点数据,最终获得 28×28 矩阵,各点数据范围在 0~255 之间。

代码

/ 获取手写数字,变成28X28的矩阵图片 绘图区缓存使用的是 RGB565结构,低位在前,高位在后 背景色为蓝色。笔迹使用红色,简单处理只需要使用高位值即可。
void get_hand_write_number(void)
{
    // 将结果矩阵置0
    memset(identifyimg, 0, sizeof(identifyimg));
    for (uint8_t y = 0; y < IMAGE_LENGTH; y++)
    {
        for (uint8_t x = 0; x < ((int)(IMAGE_LENGTH / IMAGE_NODE_LENGTH)) * IMAGE_NODE_LENGTH; x++)
        {
            identifyimg[y / IMAGE_NODE_LENGTH * ((int)(IMAGE_LENGTH / IMAGE_NODE_LENGTH)) + x / IMAGE_NODE_LENGTH] += imgbuffer[y * IMAGE_LENGTH * 2 + x * 2 + 1];
        }
        // printf("|\r\n");
    }


    for (uint16_t i = 0; i < ((int)(IMAGE_LENGTH / IMAGE_NODE_LENGTH)) * ((int)(IMAGE_LENGTH / IMAGE_NODE_LENGTH)); i++)
        identifyimg[i] = identifyimg[i] / (IMAGE_NODE_LENGTH * IMAGE_NODE_LENGTH);
}
建立神经网络并训练是实现数字识别的关键环节,借助深度学习框架来完成这一任务。由于 ESP32S3 资源有限,无法直接在其上进行复杂的模型训练,所以需要预先在 PC 机上生成模型文件,之后 ESP32S3 只需加载该模型文件,当获取到 28×28 的手写矩阵数据时,通过与模型文件进行计算即可得到识别结果。这种方式有效地解耦合了模型文件的生成和使用之间的联系,提高了系统的灵活性和可维护性。

具体而言,模型文件的生成需要经历以下几个关键步骤:

image.png

效果展示画面直观呈现了手写识别显示系统的运行成果。屏幕中间那片蓝色区域是专门为用户提供的手写输入区域,其清晰的边界和醒目的颜色,方便用户准确地在该区域内进行数字书写操作。在屏幕左侧,上部分设有一个清除按钮,当用户书写错误或想要重新输入时,只需轻轻点击该按钮,即可快速清空手写区域,为下一次输入做好准备。左侧下边则实时显示着识别结果,让用户能够及时了解系统对自己书写内容的判断。

屏幕右侧展示的是识别结果矩阵,以直观的矩阵形式呈现数字识别的相关数据信息。不仅如此,灯板与屏幕实现了同步显示,用户在屏幕上看到的识别结果会同时呈现在灯板上,进一步增强了信息的展示效果和交互体验。

展示效果

image.png

image.png



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]