Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
LittlevGL_LVGL
OPENMV
RA8-M85-vision-board
【RA8D1-Vision Board】在 OpenMV 上运行 lvgl 与 tflite
发布于 2024-06-15 00:50:52 浏览:1033
订阅该版
[TOC] > 在之前的文章中已经完成了 RA8D1-Vision Board 上运行 LVGL V8.3.5 版本,这次就在 OpenMV 上运行 lvgl 和 tflite ## 板级适配 得益于官方团队对 RA8D1-Vision Board 的 SDK 贴心地维护,对于板级配置文件 configuration.xml 板载的摄像头、SDRAM、LCD、TOUCH 等众多外设都已经配置好了 ![Pasted image 20240613113808.png](https://oss-club.rt-thread.org/uploads/20240615/bac71ec44474529dce205cd63805098a.png.webp) ## LVGL 适配到 OpenMV 工程 ### menuconfig 配置 #### LVGL 配置 在 SDK 中的 openmv 工程的基础上进行修改,添加 LVGL V8 的 packages 包,使用 `scons --menuconfig` 命令进入配置窗口,直接键入 / 来查找 `PKG_USING_LVGL` 这个宏 ![Pasted image 20240613173355.png](https://oss-club.rt-thread.org/uploads/20240615/aaf9b7acc920e14ff1b5a846dee8e9eb.png) 然后按 1 跳转到 LVGL 的设置界面,修改版本为 V8.3.5 版本,因为之后使用 GUI Guider 设计界面,我用的 GUI Guider 的 LVGL 版本是 V8.3.5,当然也可以用别的版本,porting 的代码可能有些许不一样 ![Pasted image 20240613173433.png](https://oss-club.rt-thread.org/uploads/20240615/209b1a9537b48cb9e28f10b4b0d55114.png) 还需要在 > Hardware Drivers Config > On-chip Peripheral Drivers 中使能 LVGL for LCD ![Pasted image 20240614155035.png](https://oss-club.rt-thread.org/uploads/20240615/cb71fae8c4541034208474bb1754dcd6.png.webp) #### 触摸配置 在官方 SDK 的 openmv 例程中触摸是没有被使能的,这里需要使能一下,在 > RT-Thread online packages > peripheral libraries and drivers > touch drivers 中使能 cst812t 的驱动 ![Pasted image 20240614192801.png](https://oss-club.rt-thread.org/uploads/20240615/8f0dac246ab1734b0d3610ec4f8dc128.png.webp) 然后在 > RT-Thread Components > Device Drivers 中使能触摸中断管脚的驱动 ![Pasted image 20240614175103.png](https://oss-club.rt-thread.org/uploads/20240615/21a4fbec906156997212bc1bede76ac5.png.webp) 最后把 packages 包下载下来 ``` pkgs --update ``` ### porting 配置 这时 lvgl 的完整代码已经自动添加到编译环境中,下一步就是在 board 文件夹中适配 porting,和之前的文章类似,依然是 lv_conf.h、lv_port_disp.c、lv_port_indev.c 这些文件,这里就不再赘述,直接上代码 > lv_port_disp.c 和之前文章的代码不太一样,修改成了全屏刷新的方式 #### lv_port_disp.c ```c #include
#include "ra8/lcd_config.h" #include "hal_data.h" static rt_sem_t _SemaphoreVsync = RT_NULL; static uint8_t lvgl_init_flag = 0; void DisplayVsyncCallback(display_callback_args_t *p_args) { rt_interrupt_enter(); if (DISPLAY_EVENT_LINE_DETECTION == p_args->event) { if (lvgl_init_flag != 0) rt_sem_release(_SemaphoreVsync); } rt_interrupt_leave(); } static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { #if defined(RENESAS_CORTEX_M85) #if (BSP_CFG_DCACHE_ENABLED) int32_t size; /* Invalidate cache - so the HW can access any data written by the CPU */ size = sizeof(fb_background[0]); SCB_CleanInvalidateDCache_by_Addr(color_p, size); #endif #endif R_GLCDC_BufferChange(&g_display0_ctrl, color_p, (display_frame_layer_t)0); lv_disp_flush_ready(disp_drv); rt_sem_take(_SemaphoreVsync, RT_WAITING_FOREVER); } void lv_port_disp_init(void) { static rt_device_t device; /* LCD Device Init */ device = rt_device_find("lcd"); RT_ASSERT(device != RT_NULL); _SemaphoreVsync = rt_sem_create("lvgl_sem", 1, RT_IPC_FLAG_PRIO); if (RT_NULL == _SemaphoreVsync) { rt_kprintf("lvgl semaphore create failed\r\n"); RT_ASSERT(0); } static lv_disp_draw_buf_t draw_buf_dsc_3; lv_disp_draw_buf_init(&draw_buf_dsc_3, fb_background[1], fb_background[0], LV_HOR_RES_MAX * LV_VER_RES_MAX); /*Initialize the display buffer*/ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.hor_res = LV_HOR_RES_MAX; disp_drv.ver_res = LV_VER_RES_MAX; disp_drv.flush_cb = disp_flush; disp_drv.draw_buf = &draw_buf_dsc_3; disp_drv.full_refresh = 1; lv_disp_drv_register(&disp_drv); lvgl_init_flag = 1; } ``` #### lv_port_indev.c ```c #include
#include
#include "cst812t.h" #define DBG_TAG "lv_port_indev" #define DBG_LVL DBG_LOG #include
#include "hal_data.h" static rt_device_t touch_dev = RT_NULL; static struct rt_touch_data read_data; lv_indev_t *indev_touchpad; static rt_err_t touch_probe() { touch_dev = rt_device_find("cst8xx"); if (touch_dev == RT_NULL) { LOG_E("can't find device cst8xx"); return -RT_ERROR; } if (rt_device_open(touch_dev, RT_DEVICE_FLAG_INT_RX) != RT_EOK) { LOG_E("open device failed!"); return -RT_ERROR; } return RT_EOK; } static void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) { if (rt_device_read(touch_dev, 0, &read_data, 1) == 1) { data->point.x = read_data.x_coordinate; data->point.y = read_data.y_coordinate; switch (read_data.event) { case TOUCH_EVENT_UP: data->state = LV_INDEV_STATE_REL; break; case TOUCH_EVENT_DOWN: data->state = LV_INDEV_STATE_PR; break; case TOUCH_EVENT_MOVE: data->state = LV_INDEV_STATE_PR; break; default: break; } } } #define RST_PIN "p000" #define INT_PIN "p010" #define TOUCH_DEVICE_NAME "sci3i" int rt_hw_cst812t_register(void) { struct rt_touch_config cfg; rt_base_t int_pin = rt_pin_get(INT_PIN); rt_base_t rst_pin = rt_pin_get(RST_PIN); cfg.dev_name = TOUCH_DEVICE_NAME; cfg.irq_pin.pin = int_pin; cfg.irq_pin.mode = PIN_MODE_INPUT_PULLUP; cfg.user_data = &rst_pin; rt_hw_cst8xx_init("cst8xx", &cfg); cst8xx_probe(); cst8xx_reset(20); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_cst812t_register); void lv_port_indev_init(void) { static lv_indev_drv_t indev_drv; if (touch_probe() != RT_EOK) { rt_kprintf("probe cst812t failed.\n"); return; } /*Register a touchpad input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = touchpad_read; indev_touchpad = lv_indev_drv_register(&indev_drv); LV_IMG_DECLARE(mouse_cursor_icon) lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /* Create an image object for the cursor */ lv_img_set_src(cursor_obj, &mouse_cursor_icon); /* Set the image source*/ lv_indev_set_cursor(indev_touchpad, cursor_obj); /* Connect the image object to the driver*/ } ``` #### lv_conf.h ```c #ifndef LV_CONF_H #define LV_CONF_H #include
#define LV_USE_SYSMON 1 #define LV_USE_PERF_MONITOR 1 #define LV_COLOR_DEPTH 16 #define LV_HOR_RES_MAX 480 #define LV_VER_RES_MAX 360 #define LV_COLOR_16_SWAP 0 #ifdef BSP_USING_LVGL_DAVE2D #define LV_USE_DRAW_DAVE2D 1 #endif /*turn-on helium acceleration when Arm-2D and the Helium-powered device are detected */ #ifdef BSP_USING_LVGL_ARM2D #if defined(__ARM_FEATURE_MVE) && __ARM_FEATURE_MVE #define LV_USE_DRAW_SW_ASM LV_DRAW_SW_ASM_HELIUM #define LV_USE_DRAW_ARM2D 1 #define LV_USE_DRAW_ARM2D_SYNC 1 #endif #endif #ifdef BSP_USING_LVGL_WIDGETS_DEMO #define LV_USE_DEMO_WIDGETS 1 #define LV_DEMO_WIDGETS_SLIDESHOW 0 #endif /* BSP_USING_LVGL_WIDGETS_DEMO */ /*Benchmark your system*/ #ifdef BSP_USING_LVGL_BENCHMARK_DEMO #define LV_USE_DEMO_BENCHMARK 1 /*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ #define LV_DEMO_BENCHMARK_RGB565A8 1 #define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_24 1 #endif /* BSP_USING_LVGL_BENCHMARK_DEMO */ /*Stress test for LVGL*/ #ifdef BSP_USING_LVGL_STRESS_DEMO #define LV_USE_DEMO_STRESS 1 #endif /* BSP_USING_LVGL_STRESS_DEMO */ /*Render test for LVGL*/ #ifdef BSP_USING_LVGL_RENDER_DEMO #define LV_USE_DEMO_RENDER 1 #endif /* BSP_USING_LVGL_RENDER_DEMO */ /*Music player demo*/ #ifdef BSP_USING_LVGL_MUSIC_DEMO #define LV_USE_DEMO_MUSIC 1 #define LV_DEMO_MUSIC_SQUARE 1 #define LV_DEMO_MUSIC_LANDSCAPE 0 #define LV_DEMO_MUSIC_ROUND 0 #define LV_DEMO_MUSIC_LARGE 0 #define LV_DEMO_MUSIC_AUTO_PLAY 0 #define LV_FONT_MONTSERRAT_12 1 #define LV_FONT_MONTSERRAT_16 1 #endif /* BSP_USING_LVGL_MUSIC_DEMO */ #endif ``` #### demo 测试 适配好了 LVGL,下面运行个 demo 试一下,在 LVGL 的设置中,将 `Enable built-in demos` 使能 ![Pasted image 20240613173433.png](https://oss-club.rt-thread.org/uploads/20240615/209b1a9537b48cb9e28f10b4b0d55114.png) board/Kconfig 中关于 LVGL 的配置是 V9 版本的,所以需要改一下 ![Pasted image 20240614160441.png](https://oss-club.rt-thread.org/uploads/20240615/34c603dafdfd7bbb1b8abc0e600f07ea.png) 修改为 ``` menuconfig BSP_USING_LVGL_DEMO bool "Enable LVGL demo for LCD" if BSP_USING_LVGL_DEMO config BSP_USING_LVGL_WIDGETS_DEMO bool "Enable LVGL widgets demo" default n endif ``` 然后使能 widgets 的 demo ![Pasted image 20240614160648.png](https://oss-club.rt-thread.org/uploads/20240615/436a29c7e6afd518444410350afba892.png.webp) 在 hal_entry.c 中添加代码,lv_user_gui_init 会自动被调用 ```c #include "lv_demos.h" void lv_user_gui_init(void) { lv_demo_widgets(); } ``` --- #### Overflow 修改 Surprise,此时,最关键的一步来了,这个时候直接编译的话,会 overflow,region \`FLASH\' overflowed by 165240 bytes,足足超了100多KB的Flash,这就需要缩减一些配置了 ![Pasted image 20240614180130.png](https://oss-club.rt-thread.org/uploads/20240615/74fdc9c831a7e8554880c12c1c9fa4e3.png.webp) --- 因为开发板上的摄像头是 OV5640,所以把其他的摄像头驱动都删掉 ![Pasted image 20240614192801.png](https://oss-club.rt-thread.org/uploads/20240615/8f0dac246ab1734b0d3610ec4f8dc128.png.webp) 将 openmv 的 buffer 从默认的 512000 改成 384000,或者改到 256000 ![Pasted image 20240614200428.png](https://oss-club.rt-thread.org/uploads/20240615/d24af598274c74c5575b50ef5e5ad13b.png.webp) 编译烧录到开发板,可以看到 openmv 运行 hello world 例程的时候同时运行着 LVGL V8 的 widgets 的 demo ![Snipaste_2024-06-14_21-32-51.png](https://oss-club.rt-thread.org/uploads/20240615/60b19a840aa4ee891a9eaf1a6a6cf9b6.png.webp) 触摸也可以正常使用 ![Snipaste_2024-06-14_21-33-33.png](https://oss-club.rt-thread.org/uploads/20240615/fd3c23992101241362485054b443937b.png.webp) 至此,实现了 openmv 和 LVGL 的共存,实现了同时运行,当然这还不够,下面开始介绍 GUI guider 设计界面和如何在 openmv IDE 上使用 micropython 调用 LVGL ## 界面设计 ### GUI Guider 使用 GUI Guider 来进行 LVGL 的拖拽式设计一个简单界面,左边用来显示摄像头内容,右边用来显示识别结果和 logo ![Pasted image 20240614230600.png](https://oss-club.rt-thread.org/uploads/20240615/2c9ebe1016905119864f5ad14f81340e.png.webp) 生成代码后添加到工程当中,然后在 custom 和 generated 文件夹中添加两个 SConscript 文件,内容如下 ```python from building import * import os cwd = GetCurrentDir() src = Glob("*.c") path = [cwd] group = DefineGroup('LVGL-GUI', src, depend = ['BSP_USING_LVGL'], CPPPATH = path) Return('group') ``` ```python from building import * import os cwd = GetCurrentDir() src = Glob("*.c") src += Glob("images/*.c") src += Glob("guider_fonts/*.c") path = [cwd] path += [cwd + '/guider_customer_fonts'] path += [cwd + '/guider_fonts'] group = DefineGroup('LVGL-GUI', src, depend = ['BSP_USING_LVGL'], CPPPATH = path) Return('group') ``` 目录树如下 ![Pasted image 20240614225631.png](https://oss-club.rt-thread.org/uploads/20240615/658b381e14445752231b2ef69ec2bc09.png.webp) 然后把刚刚的 demo 代码修改为如下内容,载入 GUI Guider 生成的界面 ```c #include "gui_guider.h" #include "custom.h" lv_ui guider_ui; void lv_user_gui_init(void) { lv_obj_clean(lv_scr_act()); setup_ui(&guider_ui); custom_init(&guider_ui); } ``` 编译烧录到开发板,可以看到刚刚设计的这个界面,左边的因为是 canvas 控件,为了节省 RAM 空间,把生成的代码删除了一部分,所以是透明的 ![Pasted image 20240614231254.png](https://oss-club.rt-thread.org/uploads/20240615/41289e5cff1eec065fc6061b59349e70.png.webp) 效果如下 ![Pasted image 20240614231054.png](https://oss-club.rt-thread.org/uploads/20240615/df0e0f1fadf5194e03dd39e5db4cd1c7.png.webp) LVGL 和 GUI Guider 界面完成,下面就开始接入到 mpy 了 ## 添加 mpy 自定义库 解释型语言本质上都是词法解析、解释执行,或者直接点讲就是脚本,mpy 就属于解释型语言,添加一个自定义的库和方法也是十分容易的,在 mpy 的模块和方法的定义中,大量使用了宏的方式来对 C API 进行添加,当然这些宏的种类也有很多 ### 添加模块与方法 #### 模块的添加 模块的定义程序范式如下,需要定义一个表放入模块的名字,然后使用 MP_DEFINE_CONST_DICT 宏来定义一个字典,然后定义一个 mp_obj_module_t 变量 ```c STATIC const mp_rom_map_elem_t mp_module_guider_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_guider) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_guider_globals, mp_module_guider_globals_table); const mp_obj_module_t mp_module_guider = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_guider_globals, }; ``` 此时仅仅是定义了一个模块,并没有加入到 mpy 中,下一步 打开 packages/micropython-v1.13.0/port/mpconfigport.h 这个文件添加三行代码 ```c // extern 刚才定义模块的全局变量 extern const struct _mp_obj_module_t mp_module_guider; // 使用宏来转换成 BUILTIN_MODULES #define GUIDER_PORT_BUILTIN_MODULES { MP_ROM_QSTR(MP_QSTR_guider), MP_ROM_PTR(&mp_module_guider) }, ``` 然后添加到 MICROPY_PORT_BUILTIN_MODULES 这个宏中,就会参与到编译当中了 ![Pasted image 20240614221652.png](https://oss-club.rt-thread.org/uploads/20240615/26e5c061faa191c183d2627d8466f99a.png.webp) #### 一般型方法 RT-Thread 也提供了一个生成器,仓库地址: [https://github.com/SummerGift/RT-MicroPython-Generator](https://github.com/SummerGift/RT-MicroPython-Generator),或者点开即用可以访问我的网站上面放的 [https://docs.pomin.top/codetools/RT-MicroPython-Generator](https://docs.pomin.top/codetools/RT-MicroPython-Generator) 使用这个生成器,传入参数设置为 1 的时候,生成代码如下,使用的宏是 MP_DEFINE_CONST_FUN_OBJ_1,传入一个泛型指针 arg_1_obj,使用 mp_obj_is_true 来获取布尔类型的传入参数 > mpy 对于参数使用泛型指针的 typedef 类型 `mp_obj_t` 来传参,然后使用一些 C 函数来获取对应的类型以及值,例如 `mp_obj_get_int`、`py_image_cobj` 等 C 函数来获取整数值、图像指针等 ![Pasted image 20240614215700.png](https://oss-club.rt-thread.org/uploads/20240615/b31ef3ecc75b2e3bd7389ed86e4adc27.png.webp) #### main 型方法 以此类推也有 MP_DEFINE_CONST_FUN_OBJ_0、MP_DEFINE_CONST_FUN_OBJ_2、MP_DEFINE_CONST_FUN_OBJ_3,但是参数过多的时候就不适合这样定义了,因为在 ARM 中需要控制参数的数量,这时就引出了 main 形式的定义宏,类似与 main 函数的 argc 和 argv,输入参数有 n_args 和泛型指针的指针 args ![Pasted image 20240614215645.png](https://oss-club.rt-thread.org/uploads/20240615/ee0b8704ba28a63f92340aa3dbaaf29a.png.webp) ### 添加一个 log 方法 #### QSTR 的生成 > QSTR 宏定义也可以用前文的生成器来生成 QSTR 的内容存放在 packages/micropython-v1.13.0/port/genhdr/qstrdefs.generated.h 中,可以使用 packages/micropython-v1.13.0/port/genhdr/gen_qstr.py 来生成,这里生成了三个后面需要用到的字符串,其中 guider 是模块名字,下面两个是模块的方法 ![Pasted image 20240614222339.png](https://oss-club.rt-thread.org/uploads/20240615/ea727ba7085497c18e93b13358fec609.png) #### 添加方法 这里定义一个名字为 guider 的模块,带有一个名为 lv_print 的方法 ```c STATIC mp_obj_t lv_print(void) { LOG_I("This is a my module's logging."); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(lv_print_obj, lv_print); STATIC const mp_rom_map_elem_t mp_module_guider_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_guider) }, { MP_ROM_QSTR(MP_QSTR_lv_print), MP_ROM_PTR(&lv_print_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_guider_globals, mp_module_guider_globals_table); const mp_obj_module_t mp_module_guider = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_guider_globals, }; ``` 按照前文的方法加入到 built module 宏中然后编译烧录到开发板中 mpy 代码如下。import guider 模块然后调用 lv_print 方法 ```python import guider guider.lv_print() ``` ![Pasted image 20240614222921.png](https://oss-club.rt-thread.org/uploads/20240615/4f144b880d7a4f4105f4d6ca13f93b5a.png) 连接到开发板然后运行这个代码,可以看到 RTT 的终端打印出了代码中写的 log ![Pasted image 20240614222820.png](https://oss-club.rt-thread.org/uploads/20240615/b1f3c2d3df2fe30afed679f05eba0038.png.webp) ### 添加 LVGL 的自定义方法 定义一个 main 型的方法,代码如下,实现传参一个图像类型的参数,获取了参数后拷贝到缓冲区,交由 canvas 控件来显示,并且根据图像大小自适应调节控件大小 ```c #include "py_image.h" STATIC mp_obj_t lv_canvas_show(size_t n_args, const mp_obj_t *args) { /* set a my buffer to display. */ static uint16_t img_buffer[240 * 320]; /* get camera stream. */ image_t *arg_img = py_image_cobj(args[0]); /* copy pixels to my buffer. */ rt_memcpy(img_buffer, arg_img->pixels, (arg_img->w * arg_img->h) << 1); /* change widget size and set buffer. */ lv_obj_set_size(guider_ui.screen_canvas_1, arg_img->w, arg_img->h); lv_canvas_set_buffer(guider_ui.screen_canvas_1, img_buffer, arg_img->w, arg_img->h, LV_IMG_CF_TRUE_COLOR); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lv_canvas_show_obj, 1, 1, lv_canvas_show); ``` 添加到 guider 模块中 ```c STATIC const mp_rom_map_elem_t mp_module_guider_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_guider) }, { MP_ROM_QSTR(MP_QSTR_lv_print), MP_ROM_PTR(&lv_print_obj) }, { MP_ROM_QSTR(MP_QSTR_lv_canvas_show), MP_ROM_PTR(&lv_canvas_show_obj) }, }; ``` 此时就可以实现传入摄像头的图像到 canvas 控件来显示了,编译烧录到开发板,然后连接到 openmv IDE 运行如下 mpy 代码 ```python import sensor, image import guider sensor.reset() # Reset and initialize the sensor. sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE) sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240) sensor.skip_frames(time=2000) # Let the camera adjust. while(True): img = sensor.snapshot() guider.lv_canvas_show(img) ``` 摄像头,启动! ![Pasted image 20240614234145.png](https://oss-club.rt-thread.org/uploads/20240615/5e41a35bea574715d75852b96a5f9f68.png.webp) 再添加一个显示识别结果的方法,实现对传入的字符串显示到 LVGL 界面的 label 控件上 ```c STATIC mp_obj_t lv_result_show(mp_obj_t arg) { lv_label_set_text(guider_ui.screen_label_1, mp_obj_str_get_str(arg)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(lv_result_show_obj, lv_result_show); // { MP_ROM_QSTR(MP_QSTR_lv_result_show), MP_ROM_PTR(&lv_result_show_obj) }, ``` 编译烧录到开发板中,在 openmv IDE 中运行如下代码 ```python import guider guider.lv_result_show('$') ``` 将 $ 显示到了界面的 label 控件上 ![Pasted image 20240615003956.png](https://oss-club.rt-thread.org/uploads/20240615/af4ef13f784908b2c9d2c9d08acbc271.png.webp) ## 运行 tflite 对于怎么完成对于 tflite 模型的训练这里就不再重复介绍,可以参考这位大佬的文章 https://club.rt-thread.org/ask/article/69ef73018d63deef.html ,跟着一步步操作即可 ![Pasted image 20240615002113.png](https://oss-club.rt-thread.org/uploads/20240615/68550db15f4dfda4640e7a4e516a30ba.png.webp) 下载生成的可以部署到 openmv 的代模型和代码 ![Pasted image 20240615002137.png](https://oss-club.rt-thread.org/uploads/20240615/bd234b0eaf6e901840fb841b5dc74595.png.webp) 得到一个如下文件 ![Pasted image 20240614230408.png](https://oss-club.rt-thread.org/uploads/20240615/80dee174f43fe79a29fbadfe54c89680.png.webp) 将 edge impulse 中生成的代码稍作修改,加入 guider 模块 ```python # Edge Impulse - OpenMV Image Classification Example import sensor, image, time, os, tf, uos, gc import guider sensor.reset() # Reset and initialize the sensor. sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE) sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240) sensor.set_windowing((240, 240)) # Set 240x240 window. sensor.skip_frames(time=2000) # Let the camera adjust. net = None labels = None try: # load the model, alloc the model file on the heap if we have at least 64K free after loading net = tf.load("trained.tflite", load_to_fb=uos.stat('trained.tflite')[6] > (gc.mem_free() - (64*1024))) except Exception as e: print(e) raise Exception('Failed to load "trained.tflite", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') try: labels = [line.rstrip('\n') for line in open("labels.txt")] except Exception as e: raise Exception('Failed to load "labels.txt", did you copy the .tflite and labels.txt file onto the mass-storage device? (' + str(e) + ')') clock = time.clock() while(True): clock.tick() img = sensor.snapshot() guider.lv_canvas_show(img) # default settings just do one detection... change them to search the image... for obj in net.classify(img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5): print("**********\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect()) img.draw_rectangle(obj.rect()) # This combines the labels and confidence values into a list of tuples predictions_list = list(zip(labels, obj.output())) predictions_max = 0 predictions_num = 0 for i in range(len(predictions_list)): if predictions_list[i][1] > predictions_max: predictions_max = predictions_list[i][1] predictions_num = predictions_list[i][0] print("%s = %f" % (predictions_list[i][0], predictions_list[i][1])) print(predictions_num) guider.lv_result_show(predictions_num) print(predictions_max) print(clock.fps(), "fps") ``` 在 openmv IDE 上运行识别 ![Pasted image 20240615002303.png](https://oss-club.rt-thread.org/uploads/20240615/9679e30f2c840ea5ba27adae2505b7a7.png.webp) ![Pasted image 20240615002445.png](https://oss-club.rt-thread.org/uploads/20240615/d8911c989b2584c86eb2a87d9e51bb1d.png.webp) 在开发板屏幕上显示 LVGL 界面、识别结果与摄像头画面 ![Pasted image 20240615002624.png](https://oss-club.rt-thread.org/uploads/20240615/f0d1c0c9fd8dd8d3f3f65daa42b2e3a6.png.webp) ![Pasted image 20240615002637.png](https://oss-club.rt-thread.org/uploads/20240615/f42574c158daf8e2db3f2464f13f3004.png.webp) 最终工程可见 Github 仓库 https://github.com/POMIN-163/RA8D1-Vision-Board-OpenMV-with-LVGL-V8
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
pomin
这家伙很懒,什么也没写!
文章
5
回答
0
被采纳
0
关注TA
发私信
相关文章
1
LittlevGL + DMA2D 显示图案扭曲
2
LittleVGL2RTT软件包还有在维护吗,测试遇到一些问题求解
3
使用littlevgl2rtt软件包实例运行不成功,emwin正常
4
关于littlevgl2rtt软件包刷频慢的解决方案?
5
移植了littlevGUI之后,用动态 线程去跑例程会卡死
6
lvgl的字体、图片文件如何升级?
7
qemu-vexpress-a9bsp下的littvgl工程可以实现触屏操作吗?
8
LVGL控件刷新死机问题
9
在lvgl上设置一个时间显示的label,一段时间后所有控件消失。
10
littlevgl2rtt和littlevgl的pc模拟器源码不兼容吗?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部