立创庐山派lvgl页面无法清除

Viewed 60

问题描述


使用立创庐山派,创建多个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

1 Answers

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

自定义人脸检测类,继承自AIBase基类

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