问题描述
使用立创庐山派,创建多个lvgl页面,splash->main,splash页面跳转到main页面后,splash内容依然存在,清理方法无效
self.scr = lv.obj()
self.scr.clean()
...
self.scr.delete()
硬件板卡
庐山派
软件版本
CanMV_K230_LCKFB_micropython_v1.4-34-gc53089c_nncase_v2.9.0
使用立创庐山派,创建多个lvgl页面,splash->main,splash页面跳转到main页面后,splash内容依然存在,清理方法无效
self.scr = lv.obj()
self.scr.clean()
...
self.scr.delete()
庐山派
CanMV_K230_LCKFB_micropython_v1.4-34-gc53089c_nncase_v2.9.0
from libs.PipeLine import PipeLine
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
from libs.Utils import *
import nncase_runtime as nn
import ulab.numpy as np
import aidemo
from media.display import *
from media.media import *
from media.sensor import *
import time, os, sys, gc
import lvgl as lv
from machine import TOUCH
from machine import RTC
import _thread
from face_reg_rec import FaceRegAndRec
class FaceApp():
def init(self, rgb888p_size=[1280, 720], display_size=[800,480], debug_mode=0):
self.display_size = display_size
self.rgb888p_size = rgb888p_size
self.faceregandrec = FaceRegAndRec(rgb888p_size, debug_mode)
def recognize(self, input_np):
return self.faceregandrec.recognize(input_np)
def register(self, input_np, register_name):
return self.faceregandrec.register(input_np, register_name)
def clear_register_face(self):
self.faceregandrec.clear_register_face()
# 绘制检测结果到画面上
def draw_result(self, osd_img, det_boxes,recg_res):
osd_img.clear()
if det_boxes:
for i,det in enumerate(det_boxes):
# (1)画人脸框
x1, y1, w, h = map(lambda x: int(round(x, 0)), det[:4])
x1 = x1 * self.display_size[0]//self.rgb888p_size[0]
y1 = y1 * self.display_size[1]//self.rgb888p_size[1]
w = w * self.display_size[0]//self.rgb888p_size[0]
h = h * self.display_size[1]//self.rgb888p_size[1]
osd_img.draw_rectangle(x1,y1, w, h, color=(255,0, 0, 255), thickness = 4)
# (2)写人脸识别结果
recg_text = recg_res[i]
osd_img.draw_string_advanced(x1,y1,32,recg_text,color=(255, 255, 0, 0))
class touch_screen():
def init(self):
self.x = 0
self.y = 0
self.state = lv.INDEV_STATE.RELEASED
self.indev_drv = lv.indev_create()
self.indev_drv.set_type(lv.INDEV_TYPE.POINTER)
self.indev_drv.set_read_cb(self.callback)
self.touch = TOUCH(0)
def callback(self, driver, data):
x, y, state = self.x, self.y, lv.INDEV_STATE.RELEASED
tp = self.touch.read(1)
if tp != (): #发生触摸事件
for i in range(len(tp)):
pass
if len(tp):
x, y, event = tp[0].x, tp[0].y, tp[0].event
if event == 2 or event == 3:
state = lv.INDEV_STATE.PRESSED
data.point = lv.point_t({'x': x, 'y': y})
data.state = state
class XiaoZhi_UI:
def init(self):
print("LVGL UI init start")
self.src = None
self.disp_img1 = None
self.disp_img2 = None
self.tp = None
self.sensor = None
self.osd_img = None
self.register_btn = None
self.DISPLAY_WIDTH = ALIGN_UP(800, 16)
self.DISPLAY_HEIGHT = 480
self.rgb888p_size=[1280,720]
self.img_joke_path = "A:/sdcard/examples/24-xiaozhi/resource/img_joke.png"
self.img_naughty_path = "A:/sdcard/examples/24-xiaozhi/resource/img_naughty.png"
self.img_think_path = "A:/sdcard/examples/24-xiaozhi/resource/img_think.png"
self.face_detect_run = True
self.ui_status = 0
self.face_det = None
self.chinese_font = None
self.msg_box = None
self.have_person = False
self.have_reg_person = False
self.reg_person_name = ""
def get_person(self):
return self.have_person
def media_init(self):
self.sensor = Sensor(fps=30)
self.sensor.reset()
self.sensor.set_framesize(w = self.DISPLAY_WIDTH, h = self.DISPLAY_HEIGHT, chn=CAM_CHN_ID_0)
self.sensor.set_pixformat(Sensor.YUV420SP)
self.sensor.set_framesize(w = self.rgb888p_size[0], h = self.rgb888p_size[1], chn=CAM_CHN_ID_2)
self.sensor.set_pixformat(Sensor.RGBP888, chn=CAM_CHN_ID_2)
bind_info = self.sensor.bind_info(x = 0, y = 0, chn = CAM_CHN_ID_0)
Display.bind_layer(**bind_info, layer = Display.LAYER_VIDEO1)
Display.init(Display.ST7701, width = self.DISPLAY_WIDTH, height = self.DISPLAY_HEIGHT, to_ide = True, osd_num=1)
self.sensor.run()
_thread.start_new_thread(self.face_det_thread,())
def media_deinit(self):
self.img_0.clear()
self.img_2.clear()
del self.img_0
del self.img_2
self.sensor.stop()
Display.deinit()
def face_det_thread(self):
time.sleep_ms(500)
self.face_det = FaceApp(rgb888p_size=self.rgb888p_size, display_size=[self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT], debug_mode=0)
self.img_0 = image.Image(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT, image.ARGB8888)
while self.face_detect_run:
if self.ui_status == 0:
self.img_2 = self.sensor.snapshot(chn = CAM_CHN_ID_2)
img_np = self.img_2.to_numpy_ref()
det_boxes, recg_res, results= self.face_det.recognize(img_np) # 推理当前帧
self.face_det.draw_result(self.img_0, det_boxes,recg_res) # 绘制结果
if det_boxes:
self.have_person = True
else:
self.have_person = False
if 0 in results:
for name in recg_res:
if name == "unknown":
continue
self.reg_person_name = name
self.have_reg_person = True
else:
self.reg_person_name = ""
self.have_reg_person = False
Display.show_image(self.img_0, 0, 0, Display.LAYER_OSD1)
gc.collect()
time.sleep_ms(10)
#self.face_det.deinit()
def get_reg_result(self):
return self.have_reg_person, self.reg_person_name
def Update_llm(self, llm_status="joke"):
if llm_status in ["thinking", "confused"]:
self.llm_img.set_src(self.img_think_path)
elif llm_status in ["neutral", "surprised", "crying", "angry", "sad", "silly"]:
self.llm_img.set_src(self.img_naughty_path)
else:
self.llm_img.set_src(self.img_joke_path)
def Update_text(self, talk_text):
self.speak_text.set_text(talk_text)
def Update_status(self, status):
self.xiaozhi_status_text.set_text(status)
def btn_clicked_register_face(self, event):
self.ui_status = 1
self.xiaozhi_status_text.set_text("人脸注册中")
self.hide_normal_ui()
self.show_register_ui()
def btn_clicked_clear_database(self, evt):
self.face_det.clear_register_face()
def disp_drv_flush_cb(self, disp_drv, area, color):
if disp_drv.flush_is_last() == True:
if self.disp_img1.virtaddr() == uctypes.addressof(color.__dereference__()):
self.disp_img2.bytearray()[:]=bytearray(0)
Display.show_image(self.disp_img1,layer=Display.LAYER_OSD2)
else:
self.disp_img1.bytearray()[:]=bytearray(0)
Display.show_image(self.disp_img2,layer=Display.LAYER_OSD2)
time.sleep(0.01)
disp_drv.flush_ready()
def lvgl_init(self):
lv.init()
disp_drv = lv.disp_create(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT)
disp_drv.set_flush_cb(self.disp_drv_flush_cb)
disp_drv.set_color_format(lv.COLOR_FORMAT.ARGB8888)
self.disp_img1 = image.Image(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT, image.BGRA8888)
self.disp_img2 = image.Image(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT, image.BGRA8888)
self.disp_img1.clear()
self.disp_img2.clear()
disp_drv.set_draw_buffers(self.disp_img1.bytearray(), self.disp_img2.bytearray(), self.disp_img1.size(), lv.DISP_RENDER_MODE.FULL)
self.tp = touch_screen()
def lvgl_deinit(self):
self.disp_img1.clear()
self.disp_img2.clear()
lv.deinit()
del self.disp_img1
del self.disp_img2
def hide_normal_ui(self):
self.register_btn.add_flag(lv.obj.FLAG.HIDDEN)
self.clear_database_btn.add_flag(lv.obj.FLAG.HIDDEN)
self.llm_img.add_flag(lv.obj.FLAG.HIDDEN)
self.speak_text.add_flag(lv.obj.FLAG.HIDDEN)
def show_normal_ui(self):
self.xiaozhi_status_text.set_text("等待按键唤醒")
self.register_btn.clear_flag(lv.obj.FLAG.HIDDEN)
self.clear_database_btn.clear_flag(lv.obj.FLAG.HIDDEN)
self.llm_img.clear_flag(lv.obj.FLAG.HIDDEN)
self.speak_text.clear_flag(lv.obj.FLAG.HIDDEN)
def hide_register_ui(self):
self.main_cont.add_flag(lv.obj.FLAG.HIDDEN)
def show_register_ui(self):
# 清空输入框,准备下次注册
self.name_input.set_text("")
self.main_cont.clear_flag(lv.obj.FLAG.HIDDEN)
def create_register_ui(self):
self.main_cont = lv.obj(self.scr)
self.main_cont.set_size(600, 380) # 容器尺寸(800x480中居中,留边距)
self.main_cont.set_pos(100, 40) # 容器位置(水平居中:(800-600)/2=100)
self.main_cont.set_flex_flow(lv.FLEX_FLOW.COLUMN) # 垂直排列
self.main_cont.set_flex_align(
lv.FLEX_ALIGN.CENTER, # 水平居中
lv.FLEX_ALIGN.START, # 垂直顶部开始
lv.FLEX_ALIGN.CENTER # 子元素居中
)
# 容器样式(大屏美化)
self.main_cont.set_style_bg_color(lv.color_hex(0xF5F5F5), lv.PART.MAIN)
self.main_cont.set_style_radius(16, lv.PART.MAIN) # 更大圆角
self.main_cont.set_style_shadow_color(lv.color_hex(0xDDDDDD), lv.PART.MAIN)
self.main_cont.set_style_shadow_width(8, lv.PART.MAIN) # 阴影效果
self.main_cont.set_style_pad_all(20, lv.PART.MAIN) # 更大内边距
# 5. 创建姓名输入框(大屏尺寸)
self.name_input = lv.textarea(self.main_cont)
self.name_input.set_size(550, 80) # 输入框放大(适配大屏)
self.name_input.set_max_length(10) # 最大输入长度(姓名最多10个字)
self.name_input.set_placeholder_text("请输入姓名(如:Jerry)") # 更清晰的占位提示
# 输入框样式(大屏优化)
self.name_input.set_style_text_font(self.chinese_font, lv.PART.MAIN) # 输入文字放大
self.name_input.set_style_bg_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN)
self.name_input.set_style_border_color(lv.color_hex(0xCCCCCC), lv.PART.MAIN)
self.name_input.set_style_border_width(3, lv.PART.MAIN) # 更粗边框
self.name_input.set_style_radius(12, lv.PART.MAIN) # 更大圆角
self.name_input.set_style_pad_all(10, lv.PART.MAIN) # 更大内边距
# 输入框聚焦样式(大屏醒目)
self.name_input.set_style_border_color(lv.color_hex(0x4CAF50), lv.PART.MAIN | lv.STATE.FOCUSED)
# 6. 创建虚拟键盘(800x480全屏宽度适配)
kb = lv.keyboard(self.main_cont)
kb.set_size(600, 200) # 键盘尺寸(占满800宽度,高度200适配480)
kb.set_pos(0, 80) # 键盘位置(屏幕下方:480-200=280)
# 键盘样式(大屏优化)
kb.set_style_bg_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN)
kb.set_style_text_font(self.chinese_font, lv.PART.MAIN) # 键盘文字放大
kb.set_textarea(self.name_input)
btn_cont = lv.obj(self.main_cont)
btn_cont.set_size(600, 80) # 按钮容器高度
btn_cont.set_flex_flow(lv.FLEX_FLOW.ROW) # 水平排列按钮
btn_cont.set_flex_align(
lv.FLEX_ALIGN.CENTER, # 水平居中
lv.FLEX_ALIGN.CENTER, # 垂直居中
lv.FLEX_ALIGN.CENTER # 子元素居中
)
confirm_btn = lv.btn(btn_cont)
confirm_btn.set_size(120, 50) # 按钮放大(适配大屏)
confirm_btn.set_style_bg_color(lv.color_hex(0x4CAF50), lv.PART.MAIN) # 绿色主色
confirm_btn.set_style_bg_color(lv.color_hex(0x388E3C), lv.PART.MAIN | lv.STATE.PRESSED) # 按下颜色
confirm_btn.set_style_radius(12, lv.PART.MAIN) # 更大圆角
confirm_btn.set_style_shadow_color(lv.color_hex(0xAAAAAA), lv.PART.MAIN)
confirm_btn.set_style_shadow_width(6, lv.PART.MAIN)
btn_label = lv.label(confirm_btn)
btn_label.set_text("确定")
btn_label.set_style_text_font(self.chinese_font, lv.PART.MAIN) # 按钮文字放大
btn_label.set_style_text_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN) # 白色文字
btn_label.center() # 文字居中
exit_btn = lv.btn(btn_cont)
exit_btn.set_size(120, 50) # 按钮放大(适配大屏)
exit_btn.set_style_bg_color(lv.color_hex(0x4CAF50), lv.PART.MAIN) # 绿色主色
exit_btn.set_style_bg_color(lv.color_hex(0x388E3C), lv.PART.MAIN | lv.STATE.PRESSED) # 按下颜色
exit_btn.set_style_radius(12, lv.PART.MAIN) # 更大圆角
exit_btn.set_style_shadow_color(lv.color_hex(0xAAAAAA), lv.PART.MAIN)
exit_btn.set_style_shadow_width(6, lv.PART.MAIN)
btn_label = lv.label(exit_btn)
btn_label.set_text("取消")
btn_label.set_style_text_font(self.chinese_font, lv.PART.MAIN) # 按钮文字放大
btn_label.set_style_text_color(lv.color_hex(0xFFFFFF), lv.PART.MAIN) # 白色文字
btn_label.center() # 文字居中
# 绑定点击事件
confirm_btn.add_event(self.on_confirm_click, lv.EVENT.CLICKED, None)
exit_btn.add_event(self.on_exit_click, lv.EVENT.CLICKED, None)
def run_register_face_thread(self, register_name):
img_np = self.img_2.to_numpy_ref()
img_return=img_np.reshape((1,img_np.shape[0],img_np.shape[1],img_np.shape[2]))
result, ret_message = self.face_det.register(img_return, register_name)
if result == 0:
display_message = "注册成功"
else:
display_message = "注册失败"
self.msg_box = lv.msgbox(self.scr, display_message, ret_message, None, None)
self.msg_box.set_size(400, 200)
self.msg_box.set_pos(200, 140)
self.msg_box.set_style_text_font(self.chinese_font, lv.PART.MAIN)
_thread.start_new_thread(self.hide_and_go_normal,())
def on_exit_click(self, evt):
self.ui_status = 0
self.xiaozhi_status_text.set_text("等待按键唤醒")
self.show_normal_ui()
self.hide_register_ui()
def on_confirm_click(self, evt):
register_name = self.name_input.get_text()
# 校验输入(非空)
if not register_name:
# 弹出适配大屏的提示框
self.msg_box = lv.msgbox(self.scr, "提示", "姓名不能为空!", None, None)
# 调整提示框尺寸(适配800x480)
self.msg_box.set_size(400, 200)
self.msg_box.set_pos(200, 140) # 提示框居中
self.msg_box.set_style_text_font(self.chinese_font, lv.PART.MAIN)
_thread.start_new_thread(self.hide_and_go_normal,())
return
_thread.start_new_thread(self.run_register_face_thread,(register_name,))
def hide_and_go_normal(self):
time.sleep(2)
if self.msg_box is not None:
self.msg_box.delete()
self.msg_box = None
self.ui_status = 0
self.show_normal_ui()
self.hide_register_ui()
def user_gui_init(self):
self.media_init()
self.lvgl_init()
self.chinese_font = lv.freetype_font_create("/sdcard/res/font/SourceHanSansSC-Normal-Min.ttf", 20, 0)
self.scr = lv.scr_act()
# 设置屏幕背景完全透明
lv.scr_act().set_style_bg_opa(lv.OPA.TRANSP, lv.PART.MAIN)
# 创建一个半透明的侧边栏
label = lv.obj(lv.layer_sys())
label.set_size(800, 30)
label.set_pos(0, 0)
label.set_style_bg_color(lv.color_hex(0xa0a0a0), lv.PART.MAIN)
label.set_style_bg_opa(50, lv.PART.MAIN)
label.set_style_border_width(0, lv.PART.MAIN)
self.xiaozhi_status_text = lv.label(self.scr)
self.xiaozhi_status_text.set_text("系统初始化,请稍后")
self.xiaozhi_status_text.set_style_text_font(self.chinese_font, 0)
self.xiaozhi_status_text.set_width(310)
self.xiaozhi_status_text.align(lv.ALIGN.TOP_MID, 0, 0)
# 人脸检测按钮
self.register_btn = lv.btn(lv.layer_sys())
self.register_btn.set_size(120, 45)
self.register_btn.set_pos(680, 75)
self.register_btn.set_style_radius(20, lv.PART.MAIN)
self.register_btn.set_style_bg_color(lv.color_hex(0x0000FF), lv.PART.MAIN)
self.register_btn.set_style_bg_opa(255, lv.PART.MAIN) # 不透明背景
self.register_btn.add_event(self.btn_clicked_register_face, lv.EVENT.CLICKED, None)
label2 = lv.label(self.register_btn)
label2.set_style_text_font(self.chinese_font, 0)
label2.set_text("注册")
label2.align(lv.ALIGN.CENTER, 0, 0)
# 人脸检测按钮
self.clear_database_btn = lv.btn(lv.layer_sys())
self.clear_database_btn.set_size(120, 45)
self.clear_database_btn.set_pos(680, 140)
self.clear_database_btn.set_style_radius(20, lv.PART.MAIN)
self.clear_database_btn.set_style_bg_color(lv.color_hex(0x0000FF), lv.PART.MAIN)
self.clear_database_btn.set_style_bg_opa(255, lv.PART.MAIN) # 不透明背景
self.clear_database_btn.add_event(self.btn_clicked_clear_database, lv.EVENT.CLICKED, None)
label3 = lv.label(self.clear_database_btn)
label3.set_style_text_font(self.chinese_font, 0)
label3.set_text("清空数据库")
label3.align(lv.ALIGN.CENTER, 0, 0)
self.llm_img = lv.img(self.scr)
self.llm_img.set_src(self.img_joke_path)
self.llm_img.set_size(50, 50) # 宽120px,高90px
img_x = (800 - 50) // 2
self.llm_img.set_pos(img_x, 390)
self.llm_img.set_style_img_opa(255, lv.PART.MAIN)
self.speak_text = lv.label(self.scr)
self.speak_text.set_text("Hi,你好小智")
self.speak_text.set_style_text_font(self.chinese_font, 0)
self.speak_text.set_pos(img_x, 450)
self.speak_text.set_width(310)
self.speak_text.align(lv.ALIGN.BOTTOM_MID, 0, 0)
self.create_register_ui()
self.hide_register_ui()
lv.scr_load(self.scr)
def user_gui_deinit(self):
self.face_detect_run = False
self.lvgl_deinit()
self.media_deinit()
gc.collect()
if name == "main":
xiaozhi_gui = XiaoZhi_UI()
xiaozhi_gui.user_gui_init()
try:
while True:
time.sleep_ms(lv.task_handler())
except BaseException as e:
import sys
sys.print_exception(e)
cur_state=0
time.sleep_ms(100)
xiaozhi_gui.user_gui_deinit()
可以参考这个demo