问题描述
在尝试使用micropython运行yolo程序时,屏幕正常显示2s左右,报错程序异常:get display buffer failed
复现步骤
===================== 1. 统一导入区域(顺序合理,无冗余) =====================
第三方库/工具类导入
from libs.PipeLine import PipeLine
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
from libs.Utils import *
from libs.YOLO import YOLOv8 # 保留必要导入,无冗余
系统/硬件库导入
import os
import sys
import ujson
import gc
#import math
import utime # 嵌入式专用计时/延时,无需同时导入time(若ScopedTiming仍报错,再添加time)
媒体/AI相关导入
from media.media import *
from media.sensor import *
from media.display import *
import nncase_runtime as nn
import ulab.numpy as np
import image
import aicube
import aidemo
import random
===================== 2. 核心外设配置(仅保留需要的,整洁清晰) =====================
DISPLAY_WIDTH = 960 # LCD物理宽度(原生)
DISPLAY_HEIGHT = 540 # LCD物理高度(原生)
对齐函数(按需保留,适配Camera要求)
def align_to_8(x):
return (x // 8) * 8
def align_to_16(x):
return (x // 16) * 16
Sensor输出尺寸(对齐后,替换原1280x720)
SENSOR_WIDTH = DISPLAY_WIDTH
SENSOR_HEIGHT = 536
===================== 3. 自定义检测类(模型逻辑完全保留,仅适配外设参数) =====================
class DetectionApp(AIBase):
def init(self,kmodel_path,labels,model_input_size=[640,640],
anchors=[10.13,16,30,33,23,30,61,62,45,59,119,116,90,156,198,373,326],
model_type="AnchorBaseDet",confidence_threshold=0.5,nms_threshold=0.25,
nms_option=False,strides=[8,16,32],
rgb888p_size=[SENSOR_WIDTH, SENSOR_HEIGHT],
display_size=[DISPLAY_WIDTH, DISPLAY_HEIGHT],debug_mode=0):
super().init(kmodel_path,model_input_size,rgb888p_size,debug_mode)
# 模型核心参数(完全未修改,仅外设参数适配)
self.kmodel_path=kmodel_path
self.labels=labels
self.model_input_size=model_input_size
self.anchors=anchors
self.model_type=model_type
self.confidence_threshold=confidence_threshold
self.nms_threshold=nms_threshold
self.nms_option=nms_option
self.strides=strides
# 外设尺寸(适配新配置,宽16对齐)
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]
# 其他参数(完全保留原逻辑)
self.debug_mode=debug_mode
self.color_four=get_colors(len(self.labels))
self.ai2d=Ai2d(debug_mode)
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)
# 预处理配置(模型核心逻辑完全未修改)
def config_preprocess(self,input_image_size=None):
with ScopedTiming("set preprocess config",self.debug_mode > 0):
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
top,bottom,left,right,_=center_pad_param(self.rgb888p_size,self.model_input_size)
self.ai2d.pad([0,0,0,0,top,bottom,left,right], 0, [114,114,114])
self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],
[1,3,self.model_input_size[1],self.model_input_size[0]])
# 后处理(模型核心逻辑完全未修改,无任何多余改动)
def postprocess(self,results):
with ScopedTiming("postprocess",self.debug_mode > 0):
if self.model_type == "AnchorBaseDet":
det_boxes = aicube.anchorbasedet_post_process( results[0], results[1], results[2],
self.model_input_size, self.rgb888p_size,
self.strides, len(self.labels),
self.confidence_threshold, self.nms_threshold,
self.anchors, self.nms_option)
elif self.model_type == "GFLDet":
det_boxes = aicube.gfldet_post_process( results[0], results[1], results[2],
self.model_input_size, self.rgb888p_size,
self.strides, len(self.labels),
self.confidence_threshold, self.nms_threshold,
self.nms_option)
elif self.model_type=="AnchorFreeDet":
det_boxes = aicube.anchorfreedet_post_process( results[0], results[1], results[2],
self.model_input_size, self.rgb888p_size,
self.strides, len(self.labels),
self.confidence_threshold, self.nms_threshold,
self.nms_option)
else:
det_boxes=None
return det_boxes
# 绘制结果(仅适配新外设尺寸,绘制逻辑完全未修改)
def draw_result(self,pl,det_boxes):
with ScopedTiming("draw osd",self.debug_mode > 0):
if det_boxes:
pl.osd_img.clear()
for det_boxe in det_boxes:
x1, y1, x2, y2 = det_boxe[2],det_boxe[3],det_boxe[4],det_boxe[5]
# 坐标映射适配新尺寸(仅此处适配,无其他改动)
sx=int(x1 * self.display_size[0] // self.rgb888p_size[0])
sy=int(y1 * self.display_size[1] // self.rgb888p_size[1])
w = int(float(x2 - x1) * self.display_size[0] // self.rgb888p_size[0])
h = int(float(y2 - y1) * self.display_size[1] // self.rgb888p_size[1])
pl.osd_img.draw_rectangle(sx , sy , w , h , color=self.get_color(det_boxe[0]))
label = self.labels[det_boxe[0]]
score = str(round(det_boxe[1],2))
pl.osd_img.draw_string_advanced(sx, sy-50,32, label + " " + score , color=self.color_four[det_boxe[0]])
else:
pl.osd_img.clear()
pl.osd_img.draw_rectangle(0, 0, 128, 128, color=(0,0,0,0))
# 获取颜色(完全保留原逻辑)
def get_color(self, x):
idx=x%len(self.color_four)
return self.color_four[idx]
===================== 4. 主程序(整洁无冗余,外设参数适配,模型逻辑不变) =====================
优化后主程序(添加退出捕获)
if name=="main":
# 基础配置(不变)
display_mode="lcd"
kmodel_path="/sdcard/examples/ai_test_kmodel/insect_det.kmodel"
labels=["leconte","boerner","armandi","linnaeus","coleoptera","acuminatus"]
confidence_threshold=0.5
nms_threshold = 0.5
anchors=[30,23,21,33,29,43,44,29,41,39,41,68,71,43,59,61,71,72]
# 初始化变量(提前定义,方便异常释放)
pl = None
det = None
try:
rgb888p_size = [SENSOR_WIDTH, SENSOR_HEIGHT]
display_size = [DISPLAY_WIDTH, DISPLAY_HEIGHT]
# 初始化PipeLine
pl=PipeLine(rgb888p_size=rgb888p_size,display_mode=display_mode, display_size=display_size)
#pl=PipeLine(rgb888p_size=rgb888p_size,display_mode=display_mode)
pl.create()
actual_display_size=pl.get_display_size()
# 校验实际显示尺寸与配置尺寸是否一致
if actual_display_size[0] != DISPLAY_WIDTH or actual_display_size[1] != DISPLAY_HEIGHT:
print(f"警告:显示尺寸不匹配,配置[{DISPLAY_WIDTH},{DISPLAY_HEIGHT}],实际[{actual_display_size[0]},{actual_display_size[1]}]")
# 初始化检测类
det=DetectionApp(
kmodel_path=kmodel_path,
labels=labels,
model_input_size=[640,640],
anchors=anchors,
rgb888p_size=rgb888p_size,
display_size=actual_display_size,
debug_mode=0
)
det.config_preprocess()
# 推理循环
while True:
with ScopedTiming("total",1):
img=pl.get_frame()
det_boxes=det.run(img)
det.draw_result(pl,det_boxes)
print(f"剩余内存g:{gc.mem_free()} 字节")
pl.show_image() #g打印h没打印,在这一行卡住且因为get display buffer failed
#Display.show_image(det_boxes, 0, 0, Display.LAYER_OSD0)
print(f"剩余内存h:{gc.mem_free()} 字节")
gc.collect()
print(f"剩余内存i:{gc.mem_free()} 字节")
utime.sleep_ms(1)
except KeyboardInterrupt:
print("用户退出程序")
except Exception as e:
print(f"程序异常:{str(e)}")
finally:
# 确保资源释放
if det is not None:
det.deinit()
if pl is not None:
pl.destroy()
print("资源已释放")
硬件板卡
rt-smart ai学习套件
软件版本
k230_canmv_dongshanpi_sdcard__nncase_v2.9.0
其他信息
我在主程序加打印后,发现程序运行到 pl.show_image(),程序运行错误