import cv2 import numpy as np import platform from .labels import labels # 确保这个文件存在 from rknnlite.api import RKNNLite # ------------------- 核心:全局变量存储RKNN模型实例(确保只加载一次) ------------------- # 初始化为None,首次调用时加载模型,后续直接复用 _global_rknn_instance = None # device tree for RK356x/RK3576/RK3588 DEVICE_COMPATIBLE_NODE = '/proc/device-tree/compatible' def get_host(): # get platform and device type system = platform.system() machine = platform.machine() os_machine = system + '-' + machine if os_machine == 'Linux-aarch64': try: with open(DEVICE_COMPATIBLE_NODE) as f: device_compatible_str = f.read() if 'rk3562' in device_compatible_str: host = 'RK3562' elif 'rk3576' in device_compatible_str: host = 'RK3576' elif 'rk3588' in device_compatible_str: host = 'RK3588' else: host = 'RK3566_RK3568' except IOError: print('Read device node {} failed.'.format(DEVICE_COMPATIBLE_NODE)) exit(-1) else: host = os_machine return host def get_top1_class_str(result): """ 从推理结果中提取出得分最高的类别,并返回字符串 参数: result (list): 模型推理输出结果(格式需与原函数一致,如 [np.ndarray]) 返回: str:得分最高类别的格式化字符串 若推理失败,返回错误提示字符串 """ if result is None: print("Inference failed: result is None") return # 解析推理输出(与原逻辑一致:展平输出为1维数组) output = result[0].reshape(-1) # 获取得分最高的类别索引(np.argmax 直接返回最大值索引,比排序更高效) top1_index = np.argmax(output) # 处理标签(确保索引在 labels 列表范围内,避免越界) if 0 <= top1_index < len(labels): top1_class_name = labels[top1_index] else: top1_class_name = "Unknown Class" # 应对索引异常的边界情况 # 5. 格式化返回字符串(包含索引、得分、类别名称,得分保留6位小数) return top1_class_name def preprocess(raw_image, target_size=(640, 640)): """ 读取图像并执行预处理(BGR转RGB、调整尺寸、添加Batch维度) 参数: image_path (str): 图像文件的完整路径(如 "C:/test.jpg" 或 "/home/user/test.jpg") target_size (tuple): 预处理后图像的目标尺寸,格式为 (width, height),默认 (640, 640) 返回: img (numpy.ndarray): 预处理后的图像 异常: FileNotFoundError: 图像路径不存在或无法读取时抛出 ValueError: 图像读取成功但为空(如文件损坏)时抛出 """ # img = cv2.cvtColor(raw_image, cv2.COLOR_BGR2RGB) # 调整尺寸 img = cv2.resize(raw_image, target_size) img = np.expand_dims(img, 0) # 添加batch维度 return img # ------------------- 新增:模型初始化函数(控制只加载一次) ------------------- def init_rknn_model(model_path): """ 初始化RKNN模型(全局唯一实例): - 首次调用:加载模型+初始化运行时,返回模型实例 - 后续调用:直接返回已加载的全局实例,避免重复加载 """ global _global_rknn_instance # 声明使用全局变量 # 若模型未加载过,执行加载逻辑 if _global_rknn_instance is None: # 1. 创建RKNN实例(关闭内置日志) rknn_lite = RKNNLite(verbose=False) # 2. 加载RKNN模型 ret = rknn_lite.load_rknn(model_path) if ret != 0: print(f'[ERROR] Load CLS_RKNN model failed (code: {ret})') exit(ret) # 3. 初始化运行时(绑定NPU核心0) ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0) if ret != 0: print(f'[ERROR] Init CLS_RKNN runtime failed (code: {ret})') exit(ret) # 4. 将加载好的实例赋值给全局变量 _global_rknn_instance = rknn_lite print(f'[INFO] CLS_RKNN model loaded successfully (path: {model_path})') return _global_rknn_instance def yolov11_cls_inference(model_path, raw_image, target_size=(640, 640)): """ 根据平台进行推理,并返回最终的分类结果 参数: model_path (str): RKNN模型文件路径 image_path (str): 图像文件的完整路径(如 "C:/test.jpg" 或 "/home/user/test.jpg") target_size (tuple): 预处理后图像的目标尺寸,格式为 (width, height),默认 (640, 640) """ rknn_model = model_path img = preprocess(raw_image, target_size) # 只加载一次模型,避免重复加载 rknn = init_rknn_model(rknn_model) if rknn is None: return None, img outputs = rknn.inference([img]) # Show the classification results class_name = get_top1_class_str(outputs) # rknn_lite.release() return class_name if __name__ == '__main__': # 调用yolov11_cls_inference函数(target_size使用默认值640x640,也可显式传参如(112,112)) image_path = "/userdata/reenrr/inference_with_lite/cover_ready.jpg" bgr_image = cv2.imread(image_path) if bgr_image is None: print(f"Failed to read image from {image_path}") exit(-1) rgb_frame = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB) print(f"Read image from {image_path}, shape: {rgb_frame.shape}") result = yolov11_cls_inference( model_path="/userdata/PyQt_main_test/app/view/yolo/yolov11_cls.rknn", raw_image=rgb_frame, target_size=(640, 640) ) # 打印最终结果 print(f"\n最终分类结果:{result}")