diff --git a/.gitignore b/.gitignore index ac7db21..9d74778 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,8 @@ results # resources resources +datasets +detection_results +*.svfs +*.mbank +output.md diff --git a/README.md b/README.md index 848fb80..1697b33 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,284 @@ -# 算能盒子开发 +# Sophon Chakcy 插件管理系统使用文档 -[TOC] +## 系统概述 -## 盒子环境搭建 +Sophon Chakcy 是一个基于 Sophon SAIL 的插件化目标检测框架,核心是动态插件管理系统,而非具体的检测算法。YOLOv8 仅作为预置的插件示例,系统支持任意检测算法的插件化扩展。 -### 资源包 -``` -. -│ sdcard.tar # 刷机包 -│ uv-aarch64-unknown-linux-gnu.tar.gz # uv python 项目管理工具 +### 核心特性 + +- **动态插件加载**:运行时根据名称动态加载对应检测器 +- **统一配置管理**:集中管理所有插件配置 +- **资源虚拟化**:支持 SQLite VFS 打包模型和配置 +- **模块化设计**:插件间互相独立,易于扩展和维护 + +## 核心架构 + +``text +sophon_chakcy/ +├── get_detector.py # 核心插件管理器 +├── __init__.py # 工具函数 +└── build.py # 插件打包工具 ``` -### 网络 +## 关键组件解析 -1. 将盒子LAN口与计算机连接,WAN口与交换机/路由器连接 +### 1. 插件管理器 (get_detector.py) -2. 通过ssh协议与连接连接 192.168.150.1 地址操作盒子 - -3. 若无交换机/路由器条件可使用电脑网络共享 - -### python环境配置 - -在计算机上输入以下命令将 uv-aarch64-unknown-linux-gnu.tar.gz 上传到盒子的 /data 路径(linaro用户的密码为linaro) - -```sh -scp uv-aarch64-unknown-linux-gnu.tar.gz linaro@192.168.150.1:/data +```python +def get_detector(name: str, is_vfs: bool = False): + """核心插件加载函数 + + Args: + name: 插件名称(在config.json中定义) + is_vfs: 是否从VFS加载资源 + + Returns: + tuple: (检测器类, 配置字典) + """ ``` -解压 uv-aarch64-unkown-linux-gnu.tar.gz 并配置环境 +**工作原理:** -```sh -tar -xzvf uv-aarch64-unknown-linux-gnu.tar.gz +1. 根据插件名称查找 `config.json` 中的配置 +2. 动态导入对应的 Python 模块 +3. 加载插件配置文件 +4. 返回检测器类和配置对象 -# 将 uv 和 uvx 移动到 /usr/local/bin/(需要 sudo 权限) -sudo mv uv-aarch64-unknown-linux-gnu/uv /usr/local/bin/ -sudo mv uv-aarch64-unknown-linux-gnu/uvx /usr/local/bin/ +### 2. 配置文件结构 -# 确保文件有可执行权限 -sudo chmod +x /usr/local/bin/uv -sudo chmod +x /usr/local/bin/uvx - -# 验证是否能够执行uv命令 -uv --version # uv 0.9.3 +```json +{ + "model_map": { + "yolov8": { + "name": "yolov8", + "module": "YOLOv8.yolov8_detector", # 模块导入路径 + "config": "configs/yolov8_config.json" # 插件配置文件 + } + } +} ``` -### 运行示例 +## 插件接口开发指南 -```sh -# 克隆示例项目 -git clone http://124.71.68.6:3000/chakcy/sophon_ai_project.git -# 进入项目 -cd sophon_ai_project -# 初始化依赖 -uv sync -# 配置 sophon sdk 环境 -soucre .venv/bin/activate -python -m dfss --install sail -# 运行代码 -python3 main.py --input resources/datasets/test --bmodel resources/models/BM1688/yolov8s_int8_1b.bmodel --dev_id 0 --conf_thresh 0.25 --nms_thresh 0.7 +### 插件接口规范 + +每个插件必须提供以下接口: + +#### 1. 配置类(必需) + +```python +from dataclasses import dataclass +from typing import Dict, Any + +@dataclass +class PluginConfig: + """插件配置基类""" + bmodel_path: str + classes: list + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "PluginConfig": + """从字典创建配置对象""" + return cls(**data) +``` + +#### 2. 检测器类(必需) + +```python +class Detector: + """插件检测器基类""" + + def __init__(self, config_dict: Dict[str, Any], is_vfs: bool = False, + vfs_path: str = "./application.svfs", dev_id: int = 0, + conf_thresh: float = 0.25, nms_thresh: float = 0.7): + """ + 初始化检测器 + + Args: + config_dict: 配置字典 + is_vfs: 是否使用VFS + vfs_path: VFS文件路径 + dev_id: 设备ID + conf_thresh: 置信度阈值 + nms_thresh: NMS阈值 + """ + self.config = PluginConfig.from_dict(config_dict) + # 其他初始化逻辑... + + def detect_single_image(self, image_path: str, output_dir: str = "./results") -> list: + """单张图像检测接口""" + pass + + def detect_images_in_directory(self, input_dir: str, output_dir: str = "./results"): + """批量图像检测接口""" + pass +``` + +### 创建新插件的完整流程 + +#### 步骤1:创建插件目录结构 + +```text +my_detector/ +├── __init__.py +├── my_detector.py # 主检测器文件 +├── preprocess.py # 预处理模块(可选) +├── postprocess.py # 后处理模块(可选) +└── utils.py # 工具函数(可选) +``` + +#### 步骤2:实现检测器类 + +```python +# my_detector/my_detector.py +import os +import numpy as np +from dataclasses import dataclass +from typing import List, Dict, Any + +import sophon_chakcy.sail as sail +from .preprocess import Preprocessor +from .postprocess import Postprocessor + +@dataclass +class MyDetectorConfig: + """自定义检测器配置""" + bmodel_path: str + classes: List[str] + input_size: tuple = (640, 640) + mean: List[float] = None + std: List[float] = None + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "MyDetectorConfig": + return cls(**data) + +class Detector: + """自定义检测器实现""" + + def __init__(self, config_dict: Dict[str, Any], is_vfs: bool = False, + vfs_path: str = "./application.svfs", dev_id: int = 0, + conf_thresh: float = 0.25, nms_thresh: float = 0.7): + + # 解析配置 + self.config = MyDetectorConfig.from_dict(config_dict) + + # 加载模型 + if is_vfs: + from sqlite_vfs.core import SQLiteVFS + vfs = SQLiteVFS(vfs_path) + bmodel_bytes = vfs.read_file(self.config.bmodel_path) + bmodel_size = vfs.get_file_info(self.config.bmodel_path)["file_size"] + self.net = sail.Engine(bmodel_bytes, bmodel_size, dev_id, sail.IOMode.SYSO) + else: + self.net = sail.Engine(self.config.bmodel_path, dev_id, sail.IOMode.SYSO) + + # 初始化组件 + self.preprocessor = Preprocessor(self.config) + self.postprocessor = Postprocessor( + conf_thresh=conf_thresh, + nms_thresh=nms_thresh, + classes=self.config.classes + ) + + # 其他初始化... + print(f"插件 '{self.__class__.__name__}' 初始化完成") + + def detect_single_image(self, image_path: str, output_dir: str = "./results"): + """实现单图检测逻辑""" + # 1. 读取图像 + # 2. 预处理 + # 3. 推理 + # 4. 后处理 + # 5. 返回结果 + pass + + def detect_images_in_directory(self, input_dir: str, output_dir: str = "./results"): + """实现批量检测逻辑""" + for img_file in os.listdir(input_dir): + img_path = os.path.join(input_dir, img_file) + self.detect_single_image(img_path, output_dir) +``` + +#### 步骤3:创建插件配置文件 +```json +// configs/my_detector_config.json +{ + "bmodel_path": "models/my_model.bmodel", + "classes": ["cat", "dog", "person"], + "input_size": [640, 640], + "mean": [0.485, 0.456, 0.406], + "std": [0.229, 0.224, 0.225] +} +``` + +#### 步骤4:注册插件 + +修改 `config.json` 添加新插件: + +```json +{ + "model_map": { + "yolov8": { + "module": "YOLOv8.yolov8_detector", + "config": "configs/yolov8_config.json" + }, + "my_detector": { + "module": "my_detector.my_detector", + "config": "configs/my_detector_config.json" + }, + "faster_rcnn": { + "module": "faster_rcnn.detector", + "config": "configs/faster_rcnn_config.json" + } + } +} +``` + +#### 步骤5:测试插件 + +```bash +# 使用新插件 +python main.py --name my_detector --input ./test.jpg +``` + +### 插件打包与部署 + +#### 1. 打包工具详解 (build.py) + +构建工具执行以下任务: + +1. **读取配置**:解析 `config.json` 中的所有插件配置 +2. **打包模块**:将插件模块打包到 SQLite 模块库 +3. **打包资源**:将模型和配置文件打包到 VFS +4. **生成部署包**:创建完整的可部署包 + +#### 2. 打包命令 + +```bash +# 基本打包 +python -m sophon_chakcy.build + +# 自定义输出路径 +python -m sophon_chakcy.build --vfs_path my_app.svfs --mbank_path my_plugins.mbank + +# 详细日志 +python -m sophon_chakcy.build --verbose +``` + +#### 3. 部署结构 + +```text +部署目录/ +├── main.py # 主程序(使用VFS和模块库) +├── application.svfs # 虚拟文件系统 +│ ├── config.json +│ ├── configs/yolov8_config.json +│ ├── configs/my_detector_config.json +│ ├── models/yolov8n.bmodel +│ └── models/my_model.bmodel +└── plugins.mbank # Python模块库 + ├── YOLOv8 + ├── my_detector + └── faster_rcnn ``` diff --git a/src/sophon_ai_project/__init__.py b/YOLOv8/__init__.py similarity index 100% rename from src/sophon_ai_project/__init__.py rename to YOLOv8/__init__.py diff --git a/src/sophon_ai_project/postprocess_numpy.py b/YOLOv8/postprocess_numpy.py similarity index 100% rename from src/sophon_ai_project/postprocess_numpy.py rename to YOLOv8/postprocess_numpy.py diff --git a/YOLOv8/yolov8_detector.py b/YOLOv8/yolov8_detector.py new file mode 100644 index 0000000..fd5e318 --- /dev/null +++ b/YOLOv8/yolov8_detector.py @@ -0,0 +1,320 @@ +# yolov8_inference_with_colors.py +import os + +import numpy as np +import sophon_chakcy.sail as sail +from .postprocess_numpy import PostProcess +from sqlite_vfs.core import SQLiteVFS +from dataclasses import dataclass, field + +@dataclass +class YOLOv8Config: + bmodel_path: str = field( + metadata={"description": "模型路径"} + ) + + classes: list = field( + metadata={"description": "检测类别"} + ) + + colors: list = field( + metadata={"description": "边框颜色"} + ) + + @classmethod + def from_dict(cls, data: dict) -> "YOLOv8Config": + return cls(**data) + + +class Detector: + """完整的YOLOv8检测器,包含可视化""" + + def __init__(self, config_dict: dict, is_vfs=False, vfs_path: str="./application.svfs", dev_id=0, conf_thresh = 0.25, nms_thresh = 0.7): + self.dev_id = dev_id + yolov8_config = YOLOv8Config.from_dict(config_dict) + # 加载bmodel + if is_vfs: + vfs = SQLiteVFS(vfs_path) + bmodel_bytes = vfs.read_file(yolov8_config.bmodel_path) + bmodel_size = vfs.get_file_info(yolov8_config.bmodel_path)["file_size"] + self.net = sail.Engine(bmodel_bytes, bmodel_size, dev_id, sail.IOMode.SYSO) + else: + self.net = sail.Engine(yolov8_config.bmodel_path, dev_id, sail.IOMode.SYSO) + print(f"加载模型: {yolov8_config.bmodel_path}") + + self.handle = sail.Handle(dev_id) + self.bmcv = sail.Bmcv(self.handle) + self.graph_name = self.net.get_graph_names()[0] + + # 获取输入信息 + self.input_name = self.net.get_input_names(self.graph_name)[0] + self.input_shape = self.net.get_input_shape(self.graph_name, self.input_name) + self.input_dtype = self.net.get_input_dtype(self.graph_name, self.input_name) + self.input_scale = self.net.get_input_scale(self.graph_name, self.input_name) + + # 获取img_dtype + self.img_dtype = self.bmcv.get_bm_image_data_format(self.input_dtype) + + # 获取输出信息 + self.output_names = self.net.get_output_names(self.graph_name) + self.output_tensors = {} + for output_name in self.output_names: + output_shape = self.net.get_output_shape(self.graph_name, output_name) + output_dtype = self.net.get_output_dtype(self.graph_name, output_name) + output = sail.Tensor(self.handle, output_shape, output_dtype, True, True) + self.output_tensors[output_name] = output + + self.batch_size = self.input_shape[0] + self.net_h = self.input_shape[2] + self.net_w = self.input_shape[3] + + # 预处理参数 + self.ab = [x * self.input_scale / 255. for x in [1, 0, 1, 0, 1, 0]] + + # 后处理参数 + self.conf_thresh = conf_thresh + self.nms_thresh = nms_thresh + self.postprocess = PostProcess( + conf_thresh=self.conf_thresh, + nms_thresh=self.nms_thresh, + agnostic=False, + multi_label=False, + max_det=300 + ) + + self.colors = yolov8_config.colors + self.classes = yolov8_config.classes + + print(f"模型信息:") + print(f" 输入形状: {self.input_shape}") + print(f" 输入类型: {self.input_dtype}") + print(f" colors数量: {len(self.colors)}") + print(f" classes类别数: {len(self.classes)}") + + def draw_detections(self, image, detections, save_path=None): + """ + 绘制检测结果到图像 + + Args: + image: sail.BMImage 对象 + detections: 检测结果列表,每个元素为 [x1, y1, x2, y2, confidence, class_id] + save_path: 保存路径,如果不为None则保存图像 + + Returns: + 绘制后的图像 + """ + if len(detections) == 0: + print("没有检测到任何物体") + return image + + # 转换为BGR planar格式用于绘制 + img_bgr_planar = self.bmcv.convert_format(image) + + thickness = 2 + + print(f"\n绘制 {len(detections)} 个检测结果:") + print("-" * 80) + + for i, det in enumerate(detections): + if len(det) >= 6: + x1, y1, x2, y2, conf, cls_id = det[:6] + + # 转换为整数坐标 + x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) + + # 使用COLORS为不同类别分配颜色 + # 注意:class_id是0-79,但COLORS列表有160个颜色 + # 我们使用 (class_id + 1) % len(COLORS) 来确保不越界 + color_idx = (int(cls_id) + 1) % len(self.colors) + color = self.colors[color_idx] + + # 获取类别名称 + class_name = self.classes[int(cls_id) + 1] if int(cls_id) + 1 < len(self.classes) else f"未知类别{int(cls_id)}" + + # 打印检测信息 + print(f"检测 {i+1:2d}: {class_name:15s} | 置信度: {conf:.4f} | 位置: [{x1:4d}, {y1:4d}, {x2:4d}, {y2:4d}] | 大小: {x2-x1:4d}x{y2-y1:4d} | 颜色: {color}") + + # 绘制边界框 + if (x2 - x1) > thickness * 2 and (y2 - y1) > thickness * 2: + self.bmcv.rectangle(img_bgr_planar, x1, y1, + (x2 - x1), (y2 - y1), + color, thickness) + + print("-" * 80) + + # 保存图像 + if save_path: + self.bmcv.imwrite(save_path, img_bgr_planar) + print(f"\n检测结果已保存到: {save_path}") + + return img_bgr_planar + + def detect_single_image(self, image_path, output_dir="./detection_results"): + """ + 检测单张图像 + + Args: + image_path: 图像路径 + output_dir: 输出目录 + + Returns: + 检测结果列表 + """ + # 创建输出目录 + os.makedirs(output_dir, exist_ok=True) + + print(f"\n处理图像: {image_path}") + + # 1. 解码图像 + decoder = sail.Decoder(image_path, True, self.dev_id) + bmimg = sail.BMImage() + ret = decoder.read(self.handle, bmimg) + + if ret != 0: + print(f"错误: 无法解码图像 {image_path}") + return [] + + orig_width = bmimg.width() + orig_height = bmimg.height() + print(f"图像大小: {orig_width}x{orig_height}") + + # 2. 预处理 + # 转换为RGB格式 + rgb_img = sail.BMImage(self.handle, bmimg.height(), bmimg.width(), + sail.Format.FORMAT_RGB_PLANAR, sail.DATA_TYPE_EXT_1N_BYTE) + self.bmcv.convert_format(bmimg, rgb_img) + + # 调整大小并填充 + img_w = rgb_img.width() + img_h = rgb_img.height() + r = min(self.net_w / img_w, self.net_h / img_h) + tw = int(round(r * img_w)) + th = int(round(r * img_h)) + tx1 = int(round((self.net_w - tw) / 2)) + ty1 = int(round((self.net_h - th) / 2)) + + # 创建Padding属性 + attr = sail.PaddingAtrr() + attr.set_stx(tx1) + attr.set_sty(ty1) + attr.set_w(tw) + attr.set_h(th) + attr.set_r(114) + attr.set_g(114) + attr.set_b(114) + + # 调整大小 + resized_img = self.bmcv.crop_and_resize_padding(rgb_img, 0, 0, img_w, img_h, + self.net_w, self.net_h, attr) + + # 归一化 + preprocessed_img = sail.BMImage(self.handle, self.net_h, self.net_w, + sail.Format.FORMAT_RGB_PLANAR, self.img_dtype) + + # 转换并归一化 + self.bmcv.convert_to(resized_img, preprocessed_img, + ((self.ab[0], self.ab[1]), + (self.ab[2], self.ab[3]), + (self.ab[4], self.ab[5]))) + + # 3. 准备输入张量 + input_tensor = sail.Tensor(self.handle, self.input_shape, self.input_dtype, False, False) + self.bmcv.bm_image_to_tensor(preprocessed_img, input_tensor) + + # 4. 执行推理 + input_tensors = {self.input_name: input_tensor} + input_shapes = {self.input_name: self.input_shape} + self.net.process(self.graph_name, input_tensors, input_shapes, self.output_tensors) + + # 5. 获取输出 + outputs = {} + for name in self.output_names: + outputs[name] = self.output_tensors[name].asnumpy()[0] + + # 6. 后处理 + output_key = list(outputs.keys())[0] + pred = outputs[output_key] + + # 添加batch维度 + pred_with_batch = pred[np.newaxis, :, :] # (1, 8400, 84) + + # 准备后处理参数 + org_size_list = [(orig_width, orig_height)] + ratios_batch = [(r, r)] + txy_batch = [(tx1, ty1)] + + # 执行后处理 + detections = self.postprocess([pred_with_batch], org_size_list, ratios_batch, txy_batch) + + if len(detections) > 0: + detections = detections[0] # 取第一个batch的结果 + + # 7. 过滤低置信度的检测 + conf_threshold = 0.25 + filtered_detections = [] + + for det in detections: + if len(det) >= 6: + x1, y1, x2, y2, conf, cls_id = det[:6] + if conf > conf_threshold: + filtered_detections.append([x1, y1, x2, y2, conf, cls_id]) + + print(f"原始检测数量: {len(detections)}") + print(f"过滤后数量 (置信度 > {conf_threshold}): {len(filtered_detections)}") + + # 8. 绘制检测结果 + if len(filtered_detections) > 0: + # 准备输出文件名 + base_name = os.path.basename(image_path) + name_without_ext = os.path.splitext(base_name)[0] + output_path = os.path.join(output_dir, f"detected_{base_name}") + + # 绘制检测框 + self.draw_detections(bmimg, filtered_detections, output_path) + + return filtered_detections + else: + print("没有检测到任何物体") + return [] + + def detect_images_in_directory(self, input_dir, output_dir="./detection_results"): + """ + 检测目录中的所有图像 + + Args: + input_dir: 输入目录 + output_dir: 输出目录 + """ + if not os.path.exists(input_dir): + print(f"错误: 目录不存在 {input_dir}") + return + + # 创建输出目录 + os.makedirs(output_dir, exist_ok=True) + + print(f"开始检测目录: {input_dir}") + print(f"结果保存到: {output_dir}") + + # 统计信息 + total_images = 0 + total_detections = 0 + + # 遍历目录 + for root, dirs, files in os.walk(input_dir): + for file in files: + + image_path = os.path.join(root, file) + total_images += 1 + + print(f"\n{'='*80}") + print(f"处理图像 {total_images}: {file}") + + # 检测单张图像 + detections = self.detect_single_image(image_path, output_dir) + total_detections += len(detections) + + print(f"\n{'='*80}") + print(f"检测完成!") + print(f"总处理图像数: {total_images}") + print(f"总检测物体数: {total_detections}") + print(f"平均每张图像检测数: {total_detections/max(total_images, 1):.2f}") diff --git a/config.json b/config.json new file mode 100644 index 0000000..582c56d --- /dev/null +++ b/config.json @@ -0,0 +1,15 @@ +{ + "file_system": { + "type": "vfs" + }, + "vfs": { + "file_path": "./application.svfs" + }, + "model_map": { + "yolo_example": { + "name": "yolo_example", + "module": "YOLOv8.yolov8_detector", + "config": "resources/yolov8_config.json" + } + } +} \ No newline at end of file diff --git a/docs/sail_api/1.基础函数.md b/docs/sail_api/1.基础函数.md deleted file mode 100644 index 9c11a74..0000000 --- a/docs/sail_api/1.基础函数.md +++ /dev/null @@ -1,75 +0,0 @@ -# sail 基础函数 - -## get_available_tpu_num - -获取当前设备中可用的TPU数量 - -**接口形式:** -```python -def get_available_tpu_num() -> int -``` - -**返回值说明**: - -返回当前设备中可用 TPU的数量 - -## set_print_flag - -设置是否打印程序的计算耗时信息 - -**接口形式:** - -```python -def set_print_flag(print_flag: bool) -> None -``` - -**参数说明** - -- print_flag:bool - -print_flag 为 True 时,打印程序的计算主要的耗时信息,否则不打印 - -## set_dump_io_flag - -设置是否存储输入时间和输出时间。 - -**接口形式:** - -```python -def set_dump_io_flag(dump_io_flag: bool) -> None -``` - -**参数说明** - -- dump_io_flag: bool - -dump_io_flag为True时,存储输入数据和输出数据,否则不存储。 - -## set_decoder_env - -设置Decoder的环境变量,必须在Decoder构造前设置,否则使用默认值。 - -**接口形式:** - -```python -def set_decoder_env(env_name: str, env_value: str) -> None -``` - -**参数说明:** - -- env_name: str - - 选择设置Decoder的属性名称,可选的属性名称有: - - - ‘refcounted_frames’ 设置为1时,解码出来的图像需要程序手动释放,为0时由Decoder自动释放。 - - ‘extra_frame_buffer_num’ 设置Decoder的最大缓存帧数 - - ‘rtsp_transport’ 设置RTSP采用的传输协议 - - ‘stimeout’ 设置阻塞超时时间 - - ‘rtsp_flags’ 设置RTSP是否自定义IO - - ‘buffer_size’ 设置缓存大小 - - ‘max_delay’ 设置最大时延 - - ‘probesize’ 解析文件时读取的最大字节数 - - ‘analyzeduration’ 解析文件时读取的最大时长 - -- env_value: str - diff --git a/docs/sail_api/2.sail数据类型.md b/docs/sail_api/2.sail数据类型.md deleted file mode 100644 index 6f30f4f..0000000 --- a/docs/sail_api/2.sail数据类型.md +++ /dev/null @@ -1,21 +0,0 @@ -# sail 数据类型 - -定义sophon环境中常用的数据类型 - -**接口形式** - -```python -sail.Dtype.BM_FLOAT32 -sail.Dtype.BM_INT8 -sail.Dtype.BM_UINT8 -sail.Dtype.BM_INT32 -sail.Dtype.BM_UINT32 -``` - -**参数说明** - -- sail.Dtype.BM_FLOAT32 数据类型为float32 -- sail.Dtype.BM_INT8 数据类型为int8 -- sail.Dtype.BM_UINT8 数据类型为uint8 -- sail.Dtype.BM_INT32 数据类型为int32 -- sail.Dtype.BM_UINT32 数据类型为uint32 diff --git a/docs/sail_api/3.填充属性.md b/docs/sail_api/3.填充属性.md deleted file mode 100644 index 0335750..0000000 --- a/docs/sail_api/3.填充属性.md +++ /dev/null @@ -1,156 +0,0 @@ -# 填充属性 - -PaddingAtrr中存储了数据padding的各项属性,可通过配置PaddingAtrr进行数据填充 - -## \_\_init\_\_ - -初始化 PaddingAtrr - -**接口形式:** - -```python -def __init__(self) -def __init__(self, stx: int, sty: int, width: int, height: int, r: int, g: int, b: int) -``` - -**参数说明:** - -- stx: int - -原图像相对于目标图像在x方向上的偏移量 - -- sty: int - -原图像相对于目标图像在y方向上的偏移量 - -- width: int - -在 padding 的同时可对原图像进行 resize,width 为原图像 resize 后的宽,若不进行 resize,则 width 为原图像的宽 - -- height: int - -在 padding 的同时对原图像进行 resize,height 为原图像 resize 后的高,若不进行 resize,则 height 为原图像的高 - -- r: int - -padding 时在 R 通道上填充的像素值 - -- g: int - -padding 时在 G 通道上填充的像素值 - -- b: int - -padding 时在B通道上填充的像素值 - -## set_stx - -设置原图像相对于目标图像在 x 方向上的偏移量 - -**接口形式** - -```python -def set_stx(self, stx: int) -> None -``` - -**参数说明** - -- stx: int - -原图像相对于目标图像在x方向上的偏移量 - -## set_sty - -设置原图像相对于目标图像在y方向上的偏移量 - -**接口形式:** - -```python -def set_sty(self, sty: int) -> None -``` - -**参数说明:** - -- sty: int - -原图像相对于目标图像在y方向上的偏移量 - -## set_w - -设置原图像resize后的width - -**接口形式:** - -```python -def set_w(self, width: int) -> None -``` - -**参数说明:** - -- width: int - -在padding的同时可对原图像进行resize,width为原图像resize后的宽,若不进行resize,则width为原图像的宽 - -## set_h - -设置原图像resize后的height - -**接口形式:** - -```python -def set_h(self, height: int) -> None -``` - -**参数说明:** - -- height: int - -在padding的同时可对原图像进行resize,height为原图像resize后的高,若不进行resize,则height为原图像的高 - -## set_r - -设置R通道上的padding值 - -**接口形式:** - -```python -def set_r(self, r: int) -> None -``` - -**参数说明** - -- r: int - -R通道上的padding值 - -## set_g - -设置G通道上的padding值 - -**接口形式:** - -```python -def set_g(self, g: int) -> None -``` - -**参数说明** - -- g: int - -G通道上的padding值 - -## set_b - -设置B通道上的padding值 - -**接口形式:** - -```python -def set_b(self, b: int) -> None -``` - -**参数说明** - -- b: int - -B通道上的padding值 diff --git a/docs/sail_api/4.设备句柄.md b/docs/sail_api/4.设备句柄.md deleted file mode 100644 index d869765..0000000 --- a/docs/sail_api/4.设备句柄.md +++ /dev/null @@ -1,51 +0,0 @@ -# 设备句柄 - -Handle是设备句柄的包装类,在程序中用于设备的标识。 - -## \_\_init\_\_ - -初始化 Handle - -**接口形式:** - -```python -def __init__(self, tpu_id: int) -``` - -**参数说明:** - -- tpu_id: int - -创建 Handle 使用的TPU的id号 - -## get_device_id - -获取 Handle 中 TPU的id - -**接口形式:** - -```python -def get_device_id(self) -> int -``` - -**返回值说明:** - -- tpu_id: int - -Handle 中的 TPU 的 id 号 - -## get_sn - -获取 Handle 中标识设备的序列码 - -**接口形式:** - -```python -def get_sn(self) -> str -``` - -**返回值说明** - -- serial_number: str - -返回 Handle 中设备的序列码 diff --git a/docs/sail_api/5.resize插值策略.md b/docs/sail_api/5.resize插值策略.md deleted file mode 100644 index 5a0a752..0000000 --- a/docs/sail_api/5.resize插值策略.md +++ /dev/null @@ -1,17 +0,0 @@ -# resize 插值策略(sail.bmcv_resize_algorithm) - -定义图像resize中常见的插值策略 - -**接口形式** - -```python -sail.bmcv_resize_algorithm.BMCV_INTER_NEAREST -sail.bmcv_resize_algorithm.BMCV_INTER_LINEAR -sail.bmcv_resize_algorithm.BMCV_INTER_BICUBIC -``` - -**参数说明** - -- sail.bmcv_resize_algorithm.BMCV_INTER_NEAREST 最近邻插值算法 -- sail.bmcv_resize_algorithm.BMCV_INTER_LINEAR 双线性插值算法 -- sail.bmcv_resize_algorithm.BMCV_INTER_BICUBIC 双三次插值算法 \ No newline at end of file diff --git a/docs/sail_api/6.Tensor张量.md b/docs/sail_api/6.Tensor张量.md deleted file mode 100644 index f065c10..0000000 --- a/docs/sail_api/6.Tensor张量.md +++ /dev/null @@ -1,240 +0,0 @@ -# Tensor 张量 - -Tensor 是模型推理的输入输出类型,包含了数据信息,实现内容管理 - -## \_\_init\_\_ - -初始化 Tensor,并为 Tensor 分配内存 - -**接口形式1** - -```python -def __init__(self, handle: Handle, data: np.arrat, own_sys_data=True) -``` - -**参数说明1** - -- handle: sail.Handle - -设备标识 Handle - -- array_data: numpy.array - -利用 numpy.array 类型初始化 Tensor,其数据类型可以是 np.float32,np.int8,np.uint8 - -- own_sys_data:bool - -指示该 Tensor 是否拥有 system memory,如果为 False,则直接将数据复制到 device memory - -**接口形式2** - -```python -def __init__(self, handle: Handle, shape: tuple, dtype: Dtype, own_sys_data: bool, own_dev_data: bool) -``` - -**参数说明2** - -- handle: sail.Handle - -设备标识 Handle - -- shape: tuple - -设置 Tensor 的 shape - -- dtype: sail.Dtype - -Tensor 的数据类型 - -- own_sys_data: bool - -指示 Tensor 是否拥有 system memory - -- own_dev_data: bool - -指示 Tensor 是否拥有 device memory - -## shape - -获取 Tensor 的 shape - -**接口形式:** - -```python -def shape(self) -> list : -``` - -**返回值说明:** - -- tensor_shape : list - -返回Tensor的shape的列表。 - -## asnumpy - -获取Tensor中系统内存的数据,返回numpy.array类型。 - -**接口形式:** -```python -def asnumpy(self) -> numpy.array - -def asnumpy(self, shape: tuple) -> numpy.array -``` - -**参数说明:** - -- shape: tuple - -可对Tensor中的数据reshape,返回形状为shape的numpy.array - -**返回值说明** - -返回Tensor中系统内存的数据,返回类型为numpy.array。 - -## update_data - -更新Tensor中系统内存的数据 - -**接口形式:** - -```python -def update_data(self, data: numpy.array) -> None -``` - -**参数说明:** - -- data: numpy.array - -更新的数据,数据size不能超过Tensor的size,Tensor的shape将保持不变。 - -## scale_from - -先对data按比例缩放,再将数据更新到Tensor的系统内存。 - -**接口形式:** - -```python -def scale_from(self, data: numpy.array, scale: float32)->None -``` - -**参数说明:** - -- data: numpy.array - -对data进行scale,再将数据更新到Tensor的系统内存。 - -- scale: float32 - -等比例缩放时的尺度。 - -## scale_to - -先对Tensor进行等比例缩放,再将数据返回到系统内存。 - -**接口形式:** - -```python -def scale_to(self, scale: float32)->numpy.array - -def scale_to(self, scale: float32, shape: tuple)->numpy.array -``` - -**参数说明:** - -- scale: float32 - -等比例缩放时的尺度。 - -- shape: tuple - -数据返回前可进行reshape,返回shape形状的数据。 - -**返回值说明:** - -- data: numpy.array - -将处理后的数据返回至系统内存,返回numpy.array - -## reshape - -对Tensor进行reshape - -**接口形式:** - -```python -def reshape(self, shape: list)->None -``` - -**参数说明:** - -- shape: list - -设置期望得到的新shape。 - -# own_sys_data - -查询该Tensor是否拥有系统内存的数据指针。 - -**接口形式:** - -```python -def own_sys_data(self)->bool -``` - -**返回值说明:** - -- judge_ret: bool - -如果拥有系统内存的数据指针则返回True,否则False。 - -## own_dev_data - -查询该Tensor是否拥有设备内存的数据 - -**接口形式:** - -```python -def own_dev_data(self)->bool -``` - -**返回值说明:** - -- judge_ret : bool - -如果拥有设备内存中的数据则返回True,否则False。 - -## sync_s2d - -将Tensor中的数据从系统内存拷贝到设备内存。 - -**接口形式:** - -```python -def sync_s2d(self)->None - -def sync_s2d(self, size)->None -``` - -**参数说明:** - -- size: int - -将特定size字节的数据从系统内存拷贝到设备内存。 - -## sync_d2s - -将Tensor中的数据从设备内存拷贝到系统内存。 - -**接口形式:** - -```python -def sync_d2s(self)->None - -def sync_d2s(self, size: int)->None -``` - -**参数说明:** - -- size: int - -将特定size字节的数据从设备内存拷贝到系统内存。 diff --git a/lib/sophon_arm-3.10.7-py3-none-any.whl b/lib/sophon_arm-3.10.7-py3-none-any.whl deleted file mode 100644 index 46e6fc4..0000000 Binary files a/lib/sophon_arm-3.10.7-py3-none-any.whl and /dev/null differ diff --git a/main.py b/main.py index 739dda1..a8a18ff 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,33 @@ -from sophon_ai_project.yolov8_bmcv import main -from sophon_ai_project.yolov8_bmcv import argsparser +import os +import argparse +from sophon_chakcy.get_detector import get_detector +def main(): + parser = argparse.ArgumentParser(description="YOLOv8目标检测") + parser.add_argument('--name', type=str, required=True, help='算法名称') + parser.add_argument('--input', type=str, required=True, help='输入图像或目录路径') + parser.add_argument('--dev_id', type=int, default=0, help='设备ID') + parser.add_argument('--conf_thresh', type=float, default=0.25, help='置信度阈值') + parser.add_argument('--nms_thresh', type=float, default=0.7, help='NMS阈值') + + args = parser.parse_args() + + detector_class, model_config = get_detector(args.name) + + # 初始化检测器 + detector = detector_class(model_config, False, dev_id=args.dev_id, conf_thresh=args.conf_thresh, nms_thresh=args.nms_thresh) + + # 根据输入类型进行处理 + if os.path.isfile(args.input): + # 单张图像 + detector.detect_single_image(args.input) + + elif os.path.isdir(args.input): + # 图像目录 + detector.detect_images_in_directory(args.input) + else: + print(f"错误: {args.input} 既不是文件也不是目录") + if __name__ == "__main__": - args = argsparser() - main(args) - print('all done.') + main() \ No newline at end of file diff --git a/public/main.py b/public/main.py new file mode 100644 index 0000000..9713396 --- /dev/null +++ b/public/main.py @@ -0,0 +1,38 @@ +import os +import argparse +from sophon_chakcy.get_detector import get_detector +from module_bank import PythonToSQLite + +# 安装导入器 +packer = PythonToSQLite("plugins.mbank") +finder = packer.install_importer() + + +def main(): + parser = argparse.ArgumentParser(description="YOLOv8目标检测") + parser.add_argument('--name', type=str, required=True, help='算法名称') + parser.add_argument('--input', type=str, required=True, help='输入图像或目录路径') + parser.add_argument('--dev_id', type=int, default=0, help='设备ID') + parser.add_argument('--conf_thresh', type=float, default=0.25, help='置信度阈值') + parser.add_argument('--nms_thresh', type=float, default=0.7, help='NMS阈值') + + args = parser.parse_args() + + detector_class, model_config = get_detector(args.name, True) + + # 初始化检测器 + detector = detector_class(model_config, True, dev_id=args.dev_id, conf_thresh=args.conf_thresh, nms_thresh=args.nms_thresh) + + # 根据输入类型进行处理 + if os.path.isfile(args.input): + # 单张图像 + detector.detect_single_image(args.input) + + elif os.path.isdir(args.input): + # 图像目录 + detector.detect_images_in_directory(args.input) + else: + print(f"错误: {args.input} 既不是文件也不是目录") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/public/requirements.txt b/public/requirements.txt new file mode 100644 index 0000000..2e90dbe --- /dev/null +++ b/public/requirements.txt @@ -0,0 +1,4 @@ +module-bank==0.1.1 +numpy==2.2.6 +opencv-python-headless==4.12.0.88 +sqlite-vfs==0.1.0 diff --git a/pyproject.toml b/pyproject.toml index 6456f2a..413b1af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,16 @@ +[build-system] +build-backend = "hatchling.build" +requires = ["hatchling"] + [project] dependencies = [ + "module-bank>=0.1.1", "numpy>=1.24.4", "opencv-python-headless>=4.12.0.88", + "sqlite-vfs>=0.1.0", ] description = "Add your description here" -name = "sophon-ai-project" +name = "sophon-chakcy" readme = "README.md" requires-python = ">=3.8" version = "0.1.0" @@ -14,10 +20,13 @@ default = true url = "https://pypi.tuna.tsinghua.edu.cn/simple" [tool.hatch.build.targets.wheel] -packages = ["src/sophon_ai_project"] +packages = ["src/sophon_chakcy"] [dependency-groups] dev = [ "dfss>=1.10.4", "pip>=25.0.1", ] + +[project.scripts] +build = "sophon_chakcy.build:main" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2e90dbe --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +module-bank==0.1.1 +numpy==2.2.6 +opencv-python-headless==4.12.0.88 +sqlite-vfs==0.1.0 diff --git a/scripts/code_content.py b/scripts/code_content.py index e69de29..eea10a7 100644 --- a/scripts/code_content.py +++ b/scripts/code_content.py @@ -0,0 +1,33 @@ +import os +import sys + + +def generate_markdown_from_py_files(directory, output_file): + with open(output_file, "w", encoding="utf-8") as md_file: + for root, dirs, files in os.walk(directory): + # 排除 venv 目录 + dirs[:] = [d for d in dirs if d != ".venv"] + dirs[:] = [d for d in dirs if d != ".vscode"] + dirs[:] = [d for d in dirs if d != "Scripts"] + dirs[:] = [d for d in dirs if d != "build"] + for file in files: + if ( + file.endswith(".py") + or file.endswith(".rs") + or file.endswith(".toml") + ): + file_path = os.path.join(root, file) + md_file.write(f"`{file_path}`\n") + md_file.write("```python\n") + with open(file_path, "r", encoding="utf-8") as py_file: + md_file.write(py_file.read()) + md_file.write("\n```\n\n") + + +if __name__ == "__main__": + # 指定目录和输出文件名 + target_directory = sys.argv[1] # 替换为你的目标目录 + output_markdown_file = "output.md" # 输出的 Markdown 文件名 + + generate_markdown_from_py_files(target_directory, output_markdown_file) + print(f"Markdown 文件已生成:{output_markdown_file}") diff --git a/src/sophon_ai_project/utils.py b/src/sophon_ai_project/utils.py deleted file mode 100644 index 279b7c1..0000000 --- a/src/sophon_ai_project/utils.py +++ /dev/null @@ -1,125 +0,0 @@ -#===----------------------------------------------------------------------===# -# -# Copyright (C) 2022 Sophgo Technologies Inc. All rights reserved. -# -# SOPHON-DEMO is licensed under the 2-Clause BSD License except for the -# third-party components. -# -#===----------------------------------------------------------------------===# -import os -import sys -import numpy as np -import cv2 - -COCO_CLASSES = ('background', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', - 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', - 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', - 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', - 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', - 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', - 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', - 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', - 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', - 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', - 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', - 'scissors', 'teddy bear', 'hair drier', 'toothbrush') - -COLORS = [ - [56, 0, 255], - [226, 255, 0], - [0, 94, 255], - [0, 37, 255], - [0, 255, 94], - [255, 226, 0], - [0, 18, 255], - [255, 151, 0], - [170, 0, 255], - [0, 255, 56], - [255, 0, 75], - [0, 75, 255], - [0, 255, 169], - [255, 0, 207], - [75, 255, 0], - [207, 0, 255], - [37, 0, 255], - [0, 207, 255], - [94, 0, 255], - [0, 255, 113], - [255, 18, 0], - [255, 0, 56], - [18, 0, 255], - [0, 255, 226], - [170, 255, 0], - [255, 0, 245], - [151, 255, 0], - [132, 255, 0], - [75, 0, 255], - [151, 0, 255], - [0, 151, 255], - [132, 0, 255], - [0, 255, 245], - [255, 132, 0], - [226, 0, 255], - [255, 37, 0], - [207, 255, 0], - [0, 255, 207], - [94, 255, 0], - [0, 226, 255], - [56, 255, 0], - [255, 94, 0], - [255, 113, 0], - [0, 132, 255], - [255, 0, 132], - [255, 170, 0], - [255, 0, 188], - [113, 255, 0], - [245, 0, 255], - [113, 0, 255], - [255, 188, 0], - [0, 113, 255], - [255, 0, 0], - [0, 56, 255], - [255, 0, 113], - [0, 255, 188], - [255, 0, 94], - [255, 0, 18], - [18, 255, 0], - [0, 255, 132], - [0, 188, 255], - [0, 245, 255], - [0, 169, 255], - [37, 255, 0], - [255, 0, 151], - [188, 0, 255], - [0, 255, 37], - [0, 255, 0], - [255, 0, 170], - [255, 0, 37], - [255, 75, 0], - [0, 0, 255], - [255, 207, 0], - [255, 0, 226], - [255, 245, 0], - [188, 255, 0], - [0, 255, 18], - [0, 255, 75], - [0, 255, 151], - [255, 56, 0], - [245, 255, 0], - ] - -def is_img(file_name): - """judge the file is available image or not - Args: - file_name (str): input file name - Returns: - (bool) : whether the file is available image - """ - fmt = os.path.splitext(file_name)[-1] - if isinstance(fmt, str) and fmt.lower() in ['.jpg','.png','.jpeg','.bmp','.jpeg','.webp']: - return True - else: - return False - diff --git a/src/sophon_ai_project/yolov8_bmcv.py b/src/sophon_ai_project/yolov8_bmcv.py deleted file mode 100644 index 1fb4558..0000000 --- a/src/sophon_ai_project/yolov8_bmcv.py +++ /dev/null @@ -1,393 +0,0 @@ -#===----------------------------------------------------------------------===# -# -# Copyright (C) 2022 Sophgo Technologies Inc. All rights reserved. -# -# SOPHON-DEMO is licensed under the 2-Clause BSD License except for the -# third-party components. -# -#===----------------------------------------------------------------------===# -import os -import time -import json -import argparse -import numpy as np -import sophon.sail as sail -from .postprocess_numpy import PostProcess -from .utils import COCO_CLASSES, COLORS -import logging -logging.basicConfig(level=logging.INFO) - -class YOLOv8: - def __init__(self, args): - # load bmodel - self.net = sail.Engine(args.bmodel, args.dev_id, sail.IOMode.SYSO) # type: ignore - logging.debug("load {} success!".format(args.bmodel)) - self.handle = sail.Handle(args.dev_id) - self.bmcv = sail.Bmcv(self.handle) - self.graph_name = self.net.get_graph_names()[0] - - # get input - self.input_name = self.net.get_input_names(self.graph_name)[0] - self.input_dtype= self.net.get_input_dtype(self.graph_name, self.input_name) - self.img_dtype = self.bmcv.get_bm_image_data_format(self.input_dtype) - self.input_scale = self.net.get_input_scale(self.graph_name, self.input_name) - self.input_shape = self.net.get_input_shape(self.graph_name, self.input_name) - self.input_shapes = {self.input_name: self.input_shape} - - # get output - self.output_names = self.net.get_output_names(self.graph_name) - self.output_tensors = {} - self.output_scales = {} - for output_name in self.output_names: - output_shape = self.net.get_output_shape(self.graph_name, output_name) - output_dtype = self.net.get_output_dtype(self.graph_name, output_name) - output_scale = self.net.get_output_scale(self.graph_name, output_name) - output = sail.Tensor(self.handle, output_shape, output_dtype, True, True) # type: ignore - self.output_tensors[output_name] = output - self.output_scales[output_name] = output_scale - if(output_shape[1] < output_shape[2]): - raise ValueError('Only support OPT model, please refer to the docs/YOLOv8_Export_Guide.md to export OPT model.') - # check batch size - self.batch_size = self.input_shape[0] - suppoort_batch_size = [1, 2, 3, 4, 8, 16, 32, 64, 128, 256] - if self.batch_size not in suppoort_batch_size: - raise ValueError('batch_size must be {} for bmcv, but got {}'.format(suppoort_batch_size, self.batch_size)) - self.net_h = self.input_shape[2] - self.net_w = self.input_shape[3] - - # init preprocess - self.use_resize_padding = True - self.use_vpp = False - self.ab = [x * self.input_scale / 255. for x in [1, 0, 1, 0, 1, 0]] - - # init postprocess - self.conf_thresh = args.conf_thresh - self.nms_thresh = args.nms_thresh - self.agnostic = False - self.multi_label = False - self.max_det = 300 - - self.postprocess = PostProcess( - conf_thresh=self.conf_thresh, - nms_thresh=self.nms_thresh, - agnostic=self.agnostic, - multi_label=self.multi_label, - max_det=self.max_det, - ) - - # init time - self.preprocess_time = 0.0 - self.inference_time = 0.0 - self.postprocess_time = 0.0 - - def init(self): - self.preprocess_time = 0.0 - self.inference_time = 0.0 - self.postprocess_time = 0.0 - - def preprocess_bmcv(self, input_bmimg): - rgb_planar_img = sail.BMImage(self.handle, input_bmimg.height(), input_bmimg.width(), - sail.Format.FORMAT_RGB_PLANAR, sail.DATA_TYPE_EXT_1N_BYTE) # type: ignore - self.bmcv.convert_format(input_bmimg, rgb_planar_img) # type: ignore - resized_img_rgb, ratio, txy = self.resize_bmcv(rgb_planar_img) - preprocessed_bmimg = sail.BMImage(self.handle, self.net_h, self.net_w, sail.Format.FORMAT_RGB_PLANAR, self.img_dtype) # type: ignore - self.bmcv.convert_to(resized_img_rgb, preprocessed_bmimg, ((self.ab[0], self.ab[1]), \ - (self.ab[2], self.ab[3]), \ - (self.ab[4], self.ab[5]))) # type: ignore - return preprocessed_bmimg, ratio, txy - - def resize_bmcv(self, bmimg): - """ - resize for single sail.BMImage - :param bmimg: - :return: a resize image of sail.BMImage - """ - img_w = bmimg.width() - img_h = bmimg.height() - if self.use_resize_padding: - r_w = self.net_w / img_w - r_h = self.net_h / img_h - r = min(r_w, r_h) - tw = int(round(r * img_w)) - th = int(round(r * img_h)) - tx1, ty1 = self.net_w - tw, self.net_h - th # wh padding - - tx1 /= 2 # divide padding into 2 sides - ty1 /= 2 - - ratio = (r, r) - txy = (tx1, ty1) - attr = sail.PaddingAtrr() # type: ignore - attr.set_stx(int(round(tx1 - 0.1))) - attr.set_sty(int(round(ty1 - 0.1))) - attr.set_w(tw) - attr.set_h(th) - attr.set_r(114) - attr.set_g(114) - attr.set_b(114) - - preprocess_fn = self.bmcv.vpp_crop_and_resize_padding if self.use_vpp else self.bmcv.crop_and_resize_padding - resized_img_rgb = preprocess_fn(bmimg, 0, 0, img_w, img_h, self.net_w, self.net_h, attr, sail.bmcv_resize_algorithm.BMCV_INTER_LINEAR) # type: ignore - else: - r_w = self.net_w / img_w - r_h = self.net_h / img_h - ratio = (r_w, r_h) - txy = (0, 0) - preprocess_fn = self.bmcv.vpp_resize if self.use_vpp else self.bmcv.resize - resized_img_rgb = preprocess_fn(bmimg, self.net_w, self.net_h) - return resized_img_rgb, ratio, txy - - def predict(self, input_tensor, img_num): - """ - ensure output order: loc_data, conf_preds, mask_data, proto_data - Args: - input_tensor: - Returns: - """ - input_tensors = {self.input_name: input_tensor} - self.net.process(self.graph_name, input_tensors, self.input_shapes, self.output_tensors) # type: ignore - outputs_dict = {} - for name in self.output_names: - # outputs_dict[name] = self.output_tensors[name].asnumpy()[:img_num] * self.output_scales[name] - outputs_dict[name] = self.output_tensors[name].asnumpy()[:img_num] - # resort - out_keys = list(outputs_dict.keys()) - ord = [] - for n in self.output_names: - for i, k in enumerate(out_keys): - if n in k: - ord.append(i) - break - out = [outputs_dict[out_keys[i]] for i in ord] - return out - - def __call__(self, bmimg_list): - img_num = len(bmimg_list) - ori_size_list = [] - ratio_list = [] - txy_list = [] - if self.batch_size == 1: - ori_h, ori_w = bmimg_list[0].height(), bmimg_list[0].width() - ori_size_list.append((ori_w, ori_h)) - start_time = time.time() - preprocessed_bmimg, ratio, txy = self.preprocess_bmcv(bmimg_list[0]) - self.preprocess_time += time.time() - start_time - ratio_list.append(ratio) - txy_list.append(txy) - - input_tensor = sail.Tensor(self.handle, self.input_shape, self.input_dtype, False, False) # type: ignore - self.bmcv.bm_image_to_tensor(preprocessed_bmimg, input_tensor) # type: ignore - - else: - BMImageArray = eval('sail.BMImageArray{}D'.format(self.batch_size)) - bmimgs = BMImageArray() - for i in range(img_num): - ori_h, ori_w = bmimg_list[i].height(), bmimg_list[i].width() - ori_size_list.append((ori_w, ori_h)) - start_time = time.time() - preprocessed_bmimg, ratio, txy = self.preprocess_bmcv(bmimg_list[i]) - self.preprocess_time += time.time() - start_time - ratio_list.append(ratio) - txy_list.append(txy) - bmimgs[i] = preprocessed_bmimg.data() - input_tensor = sail.Tensor(self.handle, self.input_shape, self.input_dtype, False, False) # type: ignore - self.bmcv.bm_image_to_tensor(bmimgs, input_tensor) # type: ignore - - start_time = time.time() - outputs = self.predict(input_tensor, img_num) - self.inference_time += time.time() - start_time - - start_time = time.time() - results = self.postprocess(outputs, ori_size_list, ratio_list, txy_list) - self.postprocess_time += time.time() - start_time - - return results - -def draw_bmcv(dev_id, image, boxes, output_img_dir, file_name, cn, masks=None, classes_ids=None, conf_scores=None, isvideo=False): - bmcv = sail.Bmcv(sail.Handle(dev_id)) - img_bgr_planar = bmcv.convert_format(image) - thickness = 2 - for idx in range(len(boxes)): - x1, y1, x2, y2 = boxes[idx, :].astype(np.int32).tolist() - if classes_ids is not None: - color = np.array(COLORS[int(classes_ids[idx]) + 1]).astype(np.uint8).tolist() - else: - color = (0, 0, 255) - if (x2 - x1) <= thickness * 2 or (y2 - y1) <= thickness * 2: - logging.info("width or height too small, this rect will not be drawed: (x1={},y1={},w={},h={})".format(x1, y1, x2-x1, y2-y1)) - else: - bmcv.rectangle(img_bgr_planar, x1, y1, (x2 - x1), (y2 - y1), color, thickness) # type: ignore - # bmcv.putText(image, COCO_CLASSES[int(classes_ids[idx] + 1)], x1, y1, tuple(color),1.0,1) - logging.debug("class id={}, score={}, (x1={},y1={},w={},h={})".format(int(classes_ids[idx]), conf_scores[idx], x1, y1, x2-x1, y2-y1)) # type: ignore - if isvideo: - return img_bgr_planar - else: - bmcv.imwrite(os.path.join(output_img_dir, file_name), img_bgr_planar) # type: ignore - -def main(args): - # check params - if not os.path.exists(args.input): - raise FileNotFoundError('{} is not existed.'.format(args.input)) - if not os.path.exists(args.bmodel): - raise FileNotFoundError('{} is not existed.'.format(args.bmodel)) - - # creat save path - output_dir = "./results" - if not os.path.exists(output_dir): - os.mkdir(output_dir) - output_img_dir = os.path.join(output_dir, 'images') - if not os.path.exists(output_img_dir): - os.mkdir(output_img_dir) - - yolov8 = YOLOv8(args) - batch_size = yolov8.batch_size - - # warm up - # bmimg = sail.BMImage(yolov8.handle, 1080, 1920, sail.Format.FORMAT_YUV420P, sail.DATA_TYPE_EXT_1N_BYTE) - # for i in range(10): - # results = yolov8([bmimg]) - yolov8.init() - - decode_time = 0.0 - # test images - if os.path.isdir(args.input): - bmimg_list = [] - filename_list = [] - results_list = [] - cn = 0 - yolov8_handle = sail.Handle(args.dev_id) - for root, dirs, filenames in os.walk(args.input): - for filename in filenames: - if os.path.splitext(filename)[-1].lower() not in ['.jpg','.png','.jpeg','.bmp','.webp']: - continue - img_file = os.path.join(root, filename) - cn += 1 - logging.info("{}, img_file: {}".format(cn, img_file)) - # decode - start_time = time.time() - decoder = sail.Decoder(img_file, True, args.dev_id) - bmimg = sail.BMImage() # type: ignore - ret = decoder.read(yolov8_handle, bmimg) # type: ignore - if ret != 0: - logging.error("{} decode failure.".format(img_file)) - continue - decode_time += time.time() - start_time - bmimg_list.append(bmimg) - filename_list.append(filename) - if (len(bmimg_list) == batch_size or cn == len(filenames)) and len(bmimg_list): - # predict - results = yolov8(bmimg_list) - - for i, filename in enumerate(filename_list): - det = results[i] - # save image - det_draw = det[det[:, -2] > 0.1] - draw_bmcv(args.dev_id, - bmimg_list[i], - det_draw[:,:4], - output_img_dir, - filename, - cn, - masks=None, - classes_ids=det_draw[:, -1], - conf_scores=det_draw[:, -2]) - - # save result - res_dict = dict() - res_dict['image_name'] = filename - res_dict['bboxes'] = [] - for idx in range(det.shape[0]): - bbox_dict = dict() - x1, y1, x2, y2, score, category_id = det[idx] - bbox_dict['bbox'] = [float(round(x1, 3)), float(round(y1, 3)), float(round(x2 - x1,3)), float(round(y2 -y1, 3))] - bbox_dict['category_id'] = int(category_id) - bbox_dict['score'] = float(round(score,5)) - res_dict['bboxes'].append(bbox_dict) - results_list.append(res_dict) - - bmimg_list.clear() - filename_list.clear() - - # save results - if args.input[-1] == '/': - args.input = args.input[:-1] - json_name = os.path.split(args.bmodel)[-1] + "_" + os.path.split(args.input)[-1] + "_bmcv" + "_python_result.json" - with open(os.path.join(output_dir, json_name), 'w') as jf: - # json.dump(results_list, jf) - json.dump(results_list, jf, indent=4, ensure_ascii=False) - logging.info("result saved in {}".format(os.path.join(output_dir, json_name))) - - # test videos - else: - decoder = sail.Decoder(args.input, True, args.dev_id) - if not decoder.is_opened(): - raise Exception("can not open the video") - enc_params = f"width=1920:height=1080:bitrate=2000:gop=32:gop_preset=2:framerate=25" - encoder = sail.Encoder("results/output.mp4", args.dev_id, 'h264_bm', 'NV12', enc_params, 10) - - video_name = os.path.splitext(os.path.split(args.input)[1])[0] - cn = 0 - frame_list = [] - yolov8_handle = sail.Handle(args.dev_id) - end_flag = False - while not end_flag: - frame = sail.BMImage() # type: ignore - start_time = time.time() - ret = decoder.read(yolov8_handle, frame) # type: ignore - decode_time += time.time() - start_time - if ret: #differ from cv. - end_flag = True - else: - frame_list.append(frame) - if (len(frame_list) == batch_size or end_flag) and len(frame_list): - results = yolov8(frame_list) - for i, frame in enumerate(frame_list): - det = results[i] - cn += 1 - logging.info("{}, det nums: {}".format(cn, det.shape[0])) - det_draw = det[det[:, -2] > 0.1] - drawed_bmimg = draw_bmcv(args.dev_id, - frame_list[i], - det_draw[:,:4], - output_img_dir, - video_name, - cn, - masks=None, - classes_ids=det_draw[:, -1], - conf_scores=det_draw[:, -2], - isvideo=True) - encoder.video_write(drawed_bmimg) # type: ignore - frame_list.clear() - decoder.release() - encoder.release() - logging.info("result saved in {}".format(output_img_dir)) - - - # calculate speed - logging.info("------------------ Predict Time Info ----------------------") - decode_time = decode_time / cn - preprocess_time = yolov8.preprocess_time / cn - inference_time = yolov8.inference_time / cn - postprocess_time = yolov8.postprocess_time / cn - logging.info("decode_time(ms): {:.2f}".format(decode_time * 1000)) - logging.info("preprocess_time(ms): {:.2f}".format(preprocess_time * 1000)) - logging.info("inference_time(ms): {:.2f}".format(inference_time * 1000)) - logging.info("postprocess_time(ms): {:.2f}".format(postprocess_time * 1000)) - -def argsparser(): - parser = argparse.ArgumentParser(prog=__file__) - parser.add_argument('--input', type=str, default='../datasets/test', help='path of input') - parser.add_argument('--bmodel', type=str, default='../models/BM1684X/yolov8s_fp32_1b.bmodel', help='path of bmodel') - parser.add_argument('--dev_id', type=int, default=0, help='dev id') - parser.add_argument('--conf_thresh', type=float, default=0.25, help='confidence threshold') - parser.add_argument('--nms_thresh', type=float, default=0.7, help='nms threshold') - args = parser.parse_args() - return args - -if __name__ == "__main__": - args = argsparser() - main(args) - print('all done.') - - - diff --git a/src/sophon_chakcy/__init__.py b/src/sophon_chakcy/__init__.py new file mode 100644 index 0000000..9e00bbb --- /dev/null +++ b/src/sophon_chakcy/__init__.py @@ -0,0 +1,40 @@ +"""sophon python module +""" +__all__ = [] + +try: + import numpy +except ImportError: + print('SAIL bindings requires "numpy" package.') + print('Install it via command:') + print(' pip3 install numpy') + raise + +import os +from sqlite_vfs.core import SQLiteVFS +import json + + +def get_config(json_path: str, is_vfs: bool = False, vfs_path: str="./application.svfs"): + if is_vfs: + vfs = SQLiteVFS(vfs_path) + data = json.loads(vfs.read_file(json_path)) + else: + with open(json_path, 'r') as file: + data = json.load(file) + return data + + +def is_img(file_name): + """judge the file is available image or not + Args: + file_name (str): input file name + Returns: + (bool) : whether the file is available image + """ + fmt = os.path.splitext(file_name)[-1] + if isinstance(fmt, str) and fmt.lower() in ['.jpg','.png','.jpeg','.bmp','.jpeg','.webp']: + return True + else: + return False + diff --git a/src/sophon_chakcy/build.py b/src/sophon_chakcy/build.py new file mode 100644 index 0000000..ac7e3c3 --- /dev/null +++ b/src/sophon_chakcy/build.py @@ -0,0 +1,183 @@ +from sqlite_vfs.folder_packer import FolderPacker +from sqlite_vfs.core import SQLiteVFS +import json +from module_bank import PythonToSQLite +import os +import shutil +from pathlib import Path +import traceback +import sys + + +def main(vfs_path: str = "application.svfs", mbank_path: str = "plugins.mbank"): + """ + 构建应用程序资源包和虚拟文件系统 + + Args: + vfs_path: 输出的VFS文件路径 + mbank_path: 输出的模块库文件路径 + """ + build_dir = r"build" + + try: + # 清理旧的构建目录 + if os.path.exists(build_dir): + print(f"清理旧的构建目录: {build_dir}") + shutil.rmtree(build_dir, ignore_errors=True) + + # 创建构建目录 + build_dir_path = Path(build_dir) + if not build_dir_path.exists(): + build_dir_path.mkdir(parents=True, exist_ok=True) + + print("开始构建...") + + # 读取配置文件 + try: + with open("config.json", 'r') as file: + config_data = json.load(file) + model_map = config_data["model_map"] + print("配置文件加载成功") + except FileNotFoundError: + print("错误: 找不到配置文件 config.json") + return + except json.JSONDecodeError as e: + print(f"错误: 配置文件格式错误 - {e}") + return + except KeyError: + print("错误: 配置文件中缺少 'model_map' 字段") + return + + # 初始化VFS + try: + vfs = SQLiteVFS(vfs_path) + folder_packer = FolderPacker(vfs) + print(f"VFS初始化成功: {vfs_path}") + except Exception as e: + print(f"错误: 初始化VFS失败 - {e}") + return + + # 初始化Python模块打包器 + try: + packer = PythonToSQLite(mbank_path) + print(f"模块打包器初始化成功: {mbank_path}") + except Exception as e: + print(f"错误: 初始化模块打包器失败 - {e}") + return + + # 添加配置文件到VFS + try: + folder_packer.add_file("config.json", "config.json") + print("配置文件已添加到VFS") + except Exception as e: + print(f"错误: 添加配置文件到VFS失败 - {e}") + return + + # 处理每个模型配置 + processed_models = 0 + for model_name, model_value in model_map.items(): + try: + config_file_path = model_value["config"] + module: str = model_value["module"] + + # 打包Python模块 + print(f"打包模块: {module}") + packer.pack_directory(module.split(".")[0]) + + # 添加模型配置文件到VFS + folder_packer.add_file(config_file_path, config_file_path) + + # 读取模型配置文件获取bmodel路径 + with open(config_file_path, "r") as file: + model_config = json.load(file) + bmodel_path = model_config["bmodel_path"] + + # 添加bmodel文件到VFS + if os.path.exists(bmodel_path): + folder_packer.add_file(bmodel_path, bmodel_path) + print(f" 添加模型文件: {bmodel_path}") + else: + print(f" 警告: 模型文件不存在 {bmodel_path}") + + processed_models += 1 + + except KeyError as e: + print(f"错误: 模型 '{model_name}' 配置缺少必要字段 - {e}") + continue + except FileNotFoundError as e: + print(f"错误: 找不到模型 '{model_name}' 的文件 - {e}") + continue + except json.JSONDecodeError as e: + print(f"错误: 模型 '{model_name}' 的配置文件格式错误 - {e}") + continue + except Exception as e: + print(f"错误: 处理模型 '{model_name}' 时发生未知错误 - {e}") + continue + + if processed_models == 0: + print("警告: 没有成功处理任何模型") + + # 显示VFS内容 + print("\nVFS内容:") + try: + items = vfs.list_directory("/") + for item in items: + file_type = "DIR" if item["is_directory"] else "FILE" + size_info = f" ({item['file_size']} bytes)" if not item["is_directory"] else "" + print(f" {file_type}: {item['path']}{size_info}") + except Exception as e: + print(f"警告: 无法列出VFS内容 - {e}") + + # 复制文件到构建目录 + try: + print("\n复制文件到构建目录...") + + # 复制主程序 + main_py_source = "public/main.py" + if os.path.exists(main_py_source): + shutil.copy(main_py_source, build_dir) + print(f" 复制: {main_py_source}") + else: + print(f" 警告: 主程序文件不存在 {main_py_source}") + + # 复制VFS文件 + if os.path.exists(vfs_path): + shutil.copy(vfs_path, build_dir) + print(f" 复制: {vfs_path}") + else: + print(f" 警告: VFS文件不存在 {vfs_path}") + + # 复制模块库文件 + if os.path.exists(mbank_path): + shutil.copy(mbank_path, build_dir) + print(f" 复制: {mbank_path}") + else: + print(f" 警告: 模块库文件不存在 {mbank_path}") + + except Exception as e: + print(f"错误: 复制文件失败 - {e}") + return + + print(f"\n构建成功完成! 输出目录: {build_dir}") + print(f" 主程序: {os.path.join(build_dir, 'main.py')}") + print(f" VFS文件: {os.path.join(build_dir, os.path.basename(vfs_path))}") + print(f" 模块库: {os.path.join(build_dir, os.path.basename(mbank_path))}") + + except Exception as e: + print(f"\n构建过程中发生严重错误: {e}") + print("错误详情:") + traceback.print_exc() + + # 清理不完整的构建目录 + if os.path.exists(build_dir): + print(f"\n清理不完整的构建目录: {build_dir}") + try: + shutil.rmtree(build_dir, ignore_errors=True) + except Exception as cleanup_error: + print(f"警告: 清理构建目录失败 - {cleanup_error}") + + sys.exit(1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/sophon_chakcy/get_detector.py b/src/sophon_chakcy/get_detector.py new file mode 100644 index 0000000..87e6927 --- /dev/null +++ b/src/sophon_chakcy/get_detector.py @@ -0,0 +1,11 @@ +from . import get_config +import importlib + + +def get_detector(name: str, is_vfs: bool=False): + config = get_config(r"config.json", is_vfs) + model_map = config["model_map"] + model = importlib.import_module(model_map[name]["module"]) + model_config = get_config(model_map[name]["config"], is_vfs) + detector_class = getattr(model, "Detector") + return detector_class, model_config diff --git a/src/sophon_chakcy/sail.cpython-311-aarch64-linux-gnu.so b/src/sophon_chakcy/sail.cpython-311-aarch64-linux-gnu.so new file mode 100755 index 0000000..4e3d0a9 Binary files /dev/null and b/src/sophon_chakcy/sail.cpython-311-aarch64-linux-gnu.so differ diff --git a/src/sophon_chakcy/sail.pyi b/src/sophon_chakcy/sail.pyi new file mode 100644 index 0000000..ee34dee --- /dev/null +++ b/src/sophon_chakcy/sail.pyi @@ -0,0 +1,3757 @@ +import enum +from typing import Any,Tuple +import numpy +from typing import Any +""" +SAIL basic +=============== + +Provides + 1. Basic data types, mainly including Handle and Tensor + 2. Some common basic interfaces that do not rely on sophon multimedia + +""" + + +class Dtype(enum.Enum): + BM_FLOAT32 = 0 + BM_FLOAT16 = 1 + BM_INT8 = 2 + BM_UINT8 = 3 + BM_INT16 = 4 + BM_UINT16 = 5 + BM_INT32 = 6 + BM_UINT32 = 7 + BM_BFLOAT16 = 8 + +class IOMode(enum.Enum): + SYSI = 0 + SYSO = 1 + SYSIO = 2 + DEVIO = 3 + +class LogLevel(enum.Enum): + """ + The Enumeration class of log level, including TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL, OFF. + """ + TRACE = 0 + DEBUG = 1 + INFO = 2 + WARN = 3 + ERROR = 4 + CRITICAL = 5 + OFF = 6 + +class Handle: + def __init__(self, dev_id: int) -> Handle: + """ + Constructor with device id. + + Parameters: + ---------- + dev_id: int + ID of TPU. + """ + pass + + def get_device_id(self) -> int: + """ Get device id of this handle. """ + pass + + def get_sn(self) -> str: + """ Get Serial Number. """ + pass + + def get_target(self) -> str: + """ Get TPU chip type of this handle. """ + pass + +class Tensor: + def __init__(self, handle: Handle, shape: list[int], + dtype: Dtype = Dtype.BM_FLOAT32, + own_sys_data: bool = False, + own_dev_data: bool = False) -> Tensor: pass + + def __init__(self, handle: Handle, data: numpy.ndarray[Any,numpy.dtype[Any]], own_sys_data: bool = True, own_dev_data: bool = True) -> Tensor: + """ + Constructor allocates device memory of the tensor use numpy.ndarray, \n + Input numpy must be C_CONTIGUOUS True + + Parameters: + ---------- + handle: Handle + data: numpy.ndarray + dtype is float_ | uint8 | int32 | int_, C_CONTIGUOUS flag must be True. + own_sys_data: bool, default is True. + Indicator of whether own system memory, If false, the memory will be copied to device directly + own_dev_data: bool, default is True. + """ + pass + + def __init__(self, other: Tensor, ranges: list[Tuple[int,int]] | list[tuple[int,int],tuple[int,int]], d2d_flag = True): + """ + Create a tensor from specific range of another tensor. + like the slice function in numpy. + Only supports tensor with at most 2D. + + Parameters: + ---------- + other: Tensor + other 2D or 1D tensor. + ranges: list(tuple()) + a list of tuple + if you want to slice a tensor like tensor[20:40, 50:60] in numpy + you can give the para ranges = [(20,40), (50,60)] + + d2d_flag: bool + true for d2d + false for c2c + + """ + pass + + def __init__(self, src: Tensor, shape: list[int], offset: int, no_copy: bool = True): + """ + Create a Tensor from another existing Tensor. + The created Tensor can reuse src's memory without copy. + + Parameters: + ---------- + shape: list[int] + The created Tensor's shape. + offset: int + Start reading src Tensor's momery from this offset (in element, not byte). + no_copy: bool + If no_copy flag is set to True, the created tensor will reuse + the src's memory, instead of allocating new memory. + + """ + pass + + def shape(self) -> list[int]: pass + + def dtype(self) -> int: pass + + def reshape(self, shape: list[int]) -> None: pass + + def own_sys_data(self) -> bool: pass + + def own_dev_data(self) -> bool: pass + + def size(self) -> int: + """ Returns the number of elements in this tensor. """ + pass + + def element_size(self) -> int: + """ Returns the size in bytes of an individual element. """ + pass + + def nbytes(self) -> int: + """ Return the total number of bytes occupied by all elements of Tensor. """ + pass + + def asnumpy(self, shape: list[int] = None) -> numpy.ndarray[Any,numpy.dtype[Any]] : + """ + Get ndarray in system memory of the tensor. + + Parameters: + ---------- + shape: list[int], optional + If provided, Shape of output data. + """ + pass + + def update_data(self, data: numpy.ndarray[Any, numpy.dtype[numpy.any]]) -> None: + """ + If own_sys_data, Update system data of the tensor. \n + Else if own_dev_data Update device data of the tensor. + + Parameters: + ---------- + data: numpy.ndarray + dtype is float_ | uint8 | int32 | int_. + """ + pass + + def scale_from(self, data: numpy.ndarray[Any, numpy.dtype[numpy.any]], scale: float) -> None: + """ + Scale data to tensor in system memory + + Parameters: + ---------- + data : ndarray + Data of type float32 to be scaled from. + scale : float + Scale value. + """ + pass + + def scale_to(self, scale: float, shape: list[int] = None) -> numpy.ndarray[Any, numpy.dtype[Any]] : + """ + Scale tensor to data in system memory. + + Parameters: + ---------- + scale : float + Scale value. + shape : list[int], optional + If provided, Shape of output data to scale to. + + """ + pass + + def sync_s2d(self, size: int = None) -> None: + """ + move size data from system to device + + Parameters: + ---------- + size : int, optional + If provided, byte size to be copied. + else, move all data from system to device. + """ + pass + + def sync_s2d(self, src: Tensor, offset_src: int, offset_dst: int, len: int): + """ + Copy data from system memory to device memory with specified size. + + Parameters: + ---------- + src: Tensor, Specifies the Tensor to be copied from. + offset_src: int, Specifies the number of elements to offset in the source Tensor from where to start copying. + offset_dst: int, Specifies the number of elements to offset in the destination Tensor from where to start copying. + len: int, Specifies the length of the copy, i.e., the number of elements to copy. + """ + pass + + def sync_d2s(self, size: int = None) : + """ + move size data from device to system + + Parameters: + ---------- + size : int, optional + If provided, byte size to be copied. + else, move size data from device to system + """ + pass + + def sync_d2s(self, src: Tensor, offset_src: int, offset_dst: int, len: int): + """ + Copy data from device memory to system memory with specified size. + + Parameters: + ---------- + src: Tensor, Specifies the Tensor to be copied from. + offset_src: int, Specifies the number of elements to offset in the source Tensor from where to start copying. + offset_dst: int, Specifies the number of elements to offset in the destination Tensor from where to start copying. + len: int, Specifies the length of the copy, i.e., the number of elements to copy. + """ + pass + + def sync_d2d(self, src: Tensor, offset_src: int, offset_dst: int, len: int): + """ + Copy data from device memory to device memory with specified size. + + Parameters: + ---------- + src: Tensor, Specifies the Tensor to be copied from. + offset_src: int, Specifies the number of elements to offset in the source Tensor from where to start copying. + offset_dst: int, Specifies the number of elements to offset in the destination Tensor from where to start copying. + len: int, Specifies the length of the copy, i.e., the number of elements to copy. + """ + pass + + def pysys_data(self) -> numpy.ndarray[Any, numpy.dtype[numpy.int32]] : pass + + def memory_set(self, c: any) -> None : + """ + Fill memory with a scalar, it will be automatically converted to tensor's dtype. + + Parameters: + ---------- + c: int + """ + pass + + def zeros(self) -> None: + """ + Fill memory with zeros + """ + + def ones(self) -> None: + """ + Fill memory with ones + """ + + def is_dev_data_valid(self) -> bool: + """ + Check whether device data is valid + """ + + def is_sys_data_valid(self) -> bool: + """ + Check whether system data is valid + """ + + def device_id(self) -> int: + """ + Get device id. + """ + + def dump_data(self, file_name: str, bin:bool = False) -> None: + """ + Dump Tensor data to file. + + Parameters: + ---------- + file_name: str + file path to dump tensor + + bin: bool + binary format, default False. + """ + pass + +class TensorPTRWithName: + def get_name(self) -> str: + """ Get the name of the Tensor. + + pass + """ + + def get_data(self) -> Tensor: + """ Get the Tensor. + + pass + """ + +def ReleaseTensorPtr(tensor_with_name: TensorPTRWithName) -> None: + """ Release TensorPTRWithName data. + + pass + """ + +def CreateTensorPTRWithName(name: str, handle: Handle, data: numpy.ndarray[Any,numpy.dtype[Any]], own_sys_data: bool = False, own_dev_data:bool = True) -> TensorPTRWithName: + """ Create TensorPTRWithName use name and numpy array. + + Parameters: + ---------- + name: input numpy array name + handle: Handle with result + data: input numpy array + own_sys_data: bool, default is False. + Indicator of whether own system memory, If false, the memory will be copied to device directly + own_dev_data: bool, default is True. + Returns + ------- + TensorPTRWithName + """ + +def get_available_tpu_num() -> int: + """ + Get the number of available TPUs. + + Returns + ------- + Number of available TPUs. + """ + pass + +def set_print_flag(print_flag: bool) -> None: + """ Print main process time use """ + pass + +def set_dump_io_flag(dump_io_flag: bool) -> None: + """ Dump io data""" + pass + +def argmax(tensor:Tensor) -> int: + """ + Get the indices of the maximum value + + Parameters: + ---------- + tensor : Tensor, input tensor. + + Returns + ------- + int, the indices of the maximum value. + """ + pass + + +def argmin(tensor:Tensor) -> int: + """ + Get the indices of the minimum value + + Parameters: + ---------- + tensor : Tensor, input tensor. + + Returns + ------- + int, the indices of the minimum value. + """ + +def set_loglevel(loglevel: LogLevel) -> int: + """ + Set the level of output log. + + Parameters: + ---------- + loglevel: LogLevel + The optional level is TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL, OFF. The default level is INFO. + + Returns: + ---------- + int, 0 for success and -1 for failure. + """ + pass + + +class Engine: + def __init__(self, dev_id: int) : pass + def __init__(self, handle: Handle) : pass + def __init__(self, bmodel_path: str, dev_id: int, mode:IOMode) : pass + def __init__(self, bmodel_bytes: bytes, bmodel_size: int, dev_id: int, mode:IOMode) : pass + + def load(self, bmodel_path: str) -> bool: + """ Load bmodel from file """ + pass + + def load(self, bmodel_bytes: bytes, bmodel_size: int) -> bool: + """ load bmodel from system memory """ + pass + + def get_handle(self) -> Handle: + """Get Handle instance """ + pass + + def get_device_id(self) -> int: + """Get device id of this engine """ + pass + + def get_graph_names(self) -> list[str]: + """Get all graph names in the loaded bomodels """ + pass + + def set_io_mode(self, graph_name: str, mode: IOMode) -> bool: + """Set IOMode for a graph """ + pass + + def get_input_names(self, graph_name: str) -> list[str]: + """Get all input tensor names of the specified graph """ + pass + + def get_output_names(self, graph_name: str) -> list[str]: + """Get all output tensor names of the specified graph """ + pass + + def get_max_input_shapes(self, graph_name: str) -> dict[str, list[int]]: + """Get max shapes of input tensors in a graph """ + pass + + def get_input_shape(self, graph_name: str, tensor_name: str) -> list[int]: + """Get the shape of an input tensor in a graph """ + pass + + def get_max_output_shapes(self, graph_name: str) -> dict[str, list[int]]: + """Get max shapes of output tensors in a graph """ + pass + + def get_output_shape(self, graph_name: str, tensor_name: str) -> list[int]: + """Get the shape of an output tensor in a graph """ + pass + + def get_input_dtype(self, graph_name: str, tensor_name: str) -> Dtype: + """Get data type of an input tensor""" + pass + + def get_output_dtype(self, graph_name: str, tensor_name: str) -> Dtype: + """Get data type of an output tensor""" + pass + + def get_input_scale(self, graph_name: str, tensor_name: str) -> float: + """Get scale of an input tensor""" + pass + + def get_output_scale(self, graph_name: str, tensor_name: str) -> float: + """Get scale of an output tensor""" + pass + + def process(self, graph_name: str, + input: dict[str, Tensor], + output: dict[str, Tensor], + core_list: list[int] = []) -> None: + """ + Inference with provided input and output tensors + + Parameters: + ---------- + graph_name: str + The specified graph name. + input : dict[str, Tensor] + Input tensors. + output : dict[str, Tensor] + Output tensors. + core_list : list[int] + Cores used to inference, default is []. + """ + pass + + def process(self, graph_name: str, + input: dict[str, Tensor], + input_shapes: dict[str, list[int]], + output: dict[str, Tensor], + core_list: list[int] = []) -> None: + """ + Inference with provided input and output tensors and input shapes. + + Parameters: + ---------- + graph_name: str + The specified graph name. + input : dict[str, Tensor] + Input tensors. + input_shapes : dict[str, list[int]] + Real input tensor shapes. + output : dict[str, Tensor] + Output tensors. + core_list : list[int] + Cores used to inference, default is []. + """ + pass + def process(self, graph_name: str, + input_tensors: dict[str, numpy.ndarray[Any, numpy.dtype[numpy.float_]]], + core_list: list[int] = []) -> dict[str, numpy.ndarray[Any, numpy.dtype[numpy.float_]]] : + """ + Inference with provided input. + + Parameters: + ---------- + graph_name : str + The specified graph name. + input_tensors: dict[str,ndarray] + Input tensors. + core_list : list[int] + Cores used to inference, default is []. + + Returns + ------- + dict[str,ndarray] + """ + pass + + def create_input_tensors_map(self, graph_name: str, create_mode: int = -1) -> dict[str,Tensor]: + """ + Create input tensors map, according to and bmodel. + + Parameters: + ---------- + graph_name : str + The specified graph name. + create_mode: Tensor Create mode + case 0: only allocate system memory + case 1: only allocate device memory + case other: according to engine IOMode + + Returns + ------- + dict[str,Tensor] + """ + pass + + def create_output_tensors_map(self, graph_name: str, create_mode: int = -1) -> dict[str,Tensor]: + """ + Create output tensors map, according to and bmodel. + + Parameters: + ---------- + graph_name : str + The specified graph name. + create_mode: Tensor Create mode + case 0: only allocate system memory + case 1: only allocate device memory + case other: according to engine IOMode + + Returns + ------- + dict[str,Tensor] + """ + pass + + +class MultiEngine: + def __init__(self, bmodel_path: str, dev_ids: list[int], sys_out: bool = True, graph_idx: int = 0) : pass + + def set_print_flag(self, flag:bool) -> None :pass + + def set_print_time(self, flag:bool) -> None :pass + + def get_device_ids(self) -> list[int]: + """Get device ids of this MultiEngine """ + pass + + def get_graph_names(self) -> list[str]: + """Get all graph names in the loaded bomodels """ + pass + + def get_input_names(self, graph_name: str) -> list[str]: + """Get all input tensor names of the specified graph """ + pass + + def get_output_names(self, graph_name: str) -> list[str]: + """Get all output tensor names of the specified graph """ + pass + + def get_input_shape(self, graph_name: str, tensor_name: str) -> list[int]: + """Get the shape of an input tensor in a graph """ + pass + + def get_output_shape(self, graph_name: str, tensor_name: str) -> list[int]: + """Get the shape of an output tensor in a graph """ + pass + + def process(self, + input_tensors: dict[str, numpy.ndarray[Any, numpy.dtype[numpy.float_]]]) -> dict[str, numpy.ndarray[Any, numpy.dtype[numpy.float_]]] : + """ + Inference with provided input. + + Parameters: + ---------- + input_tensors: dict[str,ndarray] + Input tensors. + + Returns + ------- + dict[str,ndarray] + """ + pass + + +""" +SAIL Kernel API +=============== + +Provides + 1. Based on tpu kernel + +""" + + +class tpu_kernel_api_yolov5_detect_out: + + def __init__(self, device_id: int, shapes: list[list[int]], network_w:int = 640, network_h:int = 640, + module_file: str='/opt/sophon/libsophon-current/lib/tpu_module/libbm1684x_kernel_module.so'): + + """ tpu_kernel_api_yolov5_detect_out Constructor. + + Parameters: + ---------- + device_id: int, Device id + shapes: list[list[int]],Input Data shape + network_w: int, Network input width + network_h: int, Network input height + module_file: str, TPU Kernel module file,default is '/opt/sophon/libsophon-current/lib/tpu_module/libbm1684x_kernel_module.so' + """ + pass + + + def process(self,input:list[TensorPTRWithName], dete_threshold: float, nms_threshold: float, release_input: bool = False) -> list[list[tuple[int, int, int, int, int, float]]]: + """ Process + + Parameters: + ---------- + input: list[TensorPTRWithName], Input Data + dete_threshold: float, Detection threshold + nms_threshold: float, NMS threshold + release_input: bool, Release input memory + + Returns + ------- + list[list[tuple[left, top, right, bottom, class_id, score]]] + + """ + + def process(self,input:dict[str, Tensor], dete_threshold: float, nms_threshold: float, release_input: bool = False) -> list[list[tuple[int, int, int, int, int, float]]]: + """ Process + + Parameters: + ---------- + input: dict[str, Tensor], Input Data + dete_threshold: float, Detection threshold + nms_threshold: float, NMS threshold + release_input: bool, Release input memory + + Returns + ------- + list[list[tuple[left, top, right, bottom, class_id, score]]] + + """ + + def reset_anchors(self, anchors_new: list[list[list[int]]]): + + """ Reset Anchors + + Parameters: + ---------- + anchors_new: list[list[list[int]]] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class tpu_kernel_api_openpose_part_nms: + + def __init__(self, device_id: int, network_c: int, + module_file: str='/opt/sophon/libsophon-current/lib/tpu_module/libbm1684x_kernel_module.so'): + + """ tpu_kernel_api_openpose_part_nms Constructor. + + Parameters: + ---------- + device_id: int, Device id + network_c: int, Pose input channel + module_file: str, TPU Kernel module file,default is '/opt/sophon/libsophon-current/lib/tpu_module/libbm1684x_kernel_module.so' + """ + pass + + + def process(self, input_data: TensorPTRWithName, shape: list[int], threshold: list[float], max_peak_num: list[int]) -> tuple[list[list[int]], list[list[float]], list[list[int]]]: + """ Process + + Parameters: + ---------- + input_data: TensorPTRWithName, Input Data + shape: list[int], Input Data width and height + threshold: list[float], Detection threshold + max_peak_num: list[int], Peak Detection maxium num + + Returns + ------- + tuple[list[list[int]], list[list[float]], list[list[int]]] + + """ + + def process(self, input: dict[str, Tensor], shape: list[int], threshold: list[float], max_peak_num: list[int]) -> tuple[list[list[int]], list[list[float]], list[list[int]]]: + """ Process + + Parameters: + ---------- + input: dict[str, Tensor], Input Data + shape: list[int], Input Data width and height + threshold: list[float], Detection threshold + max_peak_num: list[int], Peak Detection maxium num + + Returns + ------- + tuple[list[list[int]], list[list[float]], list[list[int]]] + + """ + + def reset_network_c(self, network_c_new: int): + + """ Reset channel_num + + Parameters: + ---------- + network_c_new: int + + Returns + ------- + return 0 for success and other for failure + """ + pass + + +class algo_yolov5_post_1output: + + def __init__(self, shape: list[int], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, input_use_multiclass_nms: bool=True, agnostic: bool=False): + """ algo_yolov5_post_1output Constructor. + + Parameters: + ---------- + shape: list[int] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + input_use_multiclass_nms: bool, default True + agnostic: bool, default False + """ + pass + + def push_npy(self, + channel_idx : int, + image_idx : int, + data : numpy.ndarray[Any, numpy.dtype[numpy.float_]], + dete_threshold : float, + nms_threshold : float, + ost_w : int, + ost_h : int, + padding_left : int, + padding_top : int, + padding_width : int, + padding_height : int) -> int: + """ algo_yolov5_post_1output push data. + + Parameters: + ---------- + + channel_idx : Channel index number of the image. + image_idx : Image index number of the image. + data : Input Data + dete_threshold : Detection threshold + nms_threshold : NMS threshold + ost_w : Original image width + ost_h : Original image height + padding_left : Padding left + padding_top : Padding top + padding_width : Padding width + padding_height : Padding height + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : TensorPTRWithName, + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov5_post_1output push data. + + Parameters: + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + + +class bytetrack_tracker_controller: + def __init__(self, frame_rate:int = 30, track_buffer:int = 30): + + """bytetrack Constructor + + Parameters: + ---------- + frame_rate: int, max_lost_time = int(frame_rate / 30.0 * track_buffer) + track_buffer: int, max_lost_time = int(frame_rate / 30.0 * track_buffer) + + """ + + def process(detected_objects:list[tuple[int, int, int, int, int, float]])-> list[tuple[int, int, int, int, int, float, int]]: + + """process interface + + Parameters: + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)), detected box list + + + Returns: + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)), tracked box list output + + + """ + +class deepsort_tracker_controller: + def __init__(self, max_cosine_distance:float, nn_budget:int, k_feature_dim:int, max_iou_distance:float=0.7, max_age:int=30, n_init:int=3): + + """deepsort Constructor + + Parameters: + ---------- + max_cosine_distance:float, + nn_budget:int, + k_feature_dim:int, + max_iou_distance:float=0.7, + max_age:int=30, + n_init:int=3, + + + """ + + def process(self, detected_objects:list[tuple[int, int, int, int, int, float]], features:list[Tensor])-> list[tuple[int, int, int, int, int, float, int]]: + + """process interface + + Parameters: + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)), detected box list + + features: list[sail.Tensor], features extracted by extractor + + Returns: + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)), tracked box list output + + + """ + + def process(self, detected_objects:list[tuple[int, int, int, int, int, float]], features:numpy.array)-> list[tuple[int, int, int, int, int, float, int]]: + + """process interface + + Parameters: + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)), detected box list + + features: numpy.array, features extracted by extractor + + Returns: + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)), tracked box list output + + + """ + +class sort_tracker_controller: + def __init__(self,max_iou_distance:float=0.7, max_age:int=30, n_init:int=3): + + """sort Constructor + + Parameters: + ---------- + max_iou_distance:float=0.7, + max_age:int=30, + n_init:int=3, + + + """ + + def process(self, detected_objects:list[tuple[int, int, int, int, int, float]])-> list[tuple[int, int, int, int, int, float, int]]: + + """process interface + + Parameters: + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)), detected box list + + Returns: + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)), tracked box list output + + + """ + +def nms_rotated(boxes: numpy.ndarray[Any, numpy.dtype[numpy.float32]], + scores: numpy.ndarray[Any, numpy.dtype[numpy.float32]], + threshold: float)-> list[int]: + + """nms with rotated boxes + + Parameters: + ---------- + boxes: numpy array (float), [x,y,w,h,theta] + scores: numpy array (float), score of each box + threshold: float, IOU threshold + + Returns: + keep_id: list (int), the id of original boxes that kept after filtering + + + """ + + +class EngineLLM: + def __init__(self, bmodel_path: str, dev_ids: list[int]) : + """ Constructor, which loads bmodel from file. + + Parameters: + ----------- + bmodel_path: str + The path of bmodel to be load. + dev_ids : list[int] + A list of int, representing device indexes used to inference. + + """ + pass + + def __init__(self, bmodel_path: str, flags: int, dev_ids: list[int]) : + """ Constructor, which loads bmodel from file, with specific bmrt flags. + Old SDK versions may not support this interface. + + Parameters: + ----------- + bmodel_path: str + The path of bmodel to be load. + flags: int + flags for bmruntime. + Value should be set by enum BmrtFlag, like BM_RUNTIME_SHARE_MEM. + Refer to Bmruntime doc for more details + dev_ids : list[int] + A list of int, representing device indexes used to inference. + + """ + pass + + def __init__(self, bmodel_bytes: bytes, bmodel_size: int, dev_ids: list[int]) : + """ Constructor, which loads bmodel from bytes. + + Parameters: + ----------- + bmodel_bytes: bytes + A bytes data representing the bmodel to be load. + bmodel_size: int + The size of the binary model in bytes. + This is typically the length of the `bmodel_bytes`. + dev_ids : list[int] + A list of int, representing device indexes used to inference. + + """ + pass + + def get_device_ids(self) -> list[int]: + """Get device id list of this engine """ + pass + + def get_graph_names(self) -> list[str]: + """Get all graph names in the loaded bmodels """ + pass + + def get_addr_mode(self, graph_name: str) -> int: + """Get address assign mode of a graph + + Parameters: + ----------- + graph_name: str + The specified graph name. + + Returns: + ----------- + addr_mode: int + addr_mode 1 means bmodel will allocate device mem internally, and 0 means not. + + """ + pass + + def get_stage_num(self, graph_name: str) -> int: + """Get stage num of a graph + + Parameters: + ----------- + graph_name: str + The specified graph name. + + Returns: + ----------- + stage_num: int + + """ + pass + + def get_input_num(self, graph_name: str) -> int: + """Get the number of a graph's input """ + pass + + def get_output_num(self, graph_name: str) -> int: + """Get the number of a graph's output """ + pass + + def get_is_dynamic(self, graph_name: str) -> bool: + """Get whether the graph is dynamic """ + pass + + + def process(self, graph_name: str, + input: dict[int, Tensor], + output: dict[int, Tensor], + core_list: list[int] = [0]) -> int: + # output: dict[int, Tensor], + # core_list: list[int] = []) -> int: + """ + Inference with provided input and output tensors + + Parameters: + ---------- + graph_name: str + The specified graph to inference. + input : dict[int, Tensor] + Input index and tensor. + output : dict[int, Tensor] + Output index and tensor. + + Returns: + ---------- + return: int + 0 means success and else for failure. + """ + pass + + + def get_input_name(self, graph_name: str, index: int) -> str: + """Get input tensor name of a specified index in a graph """ + pass + + def get_input_tensor_devid(self, graph_name: str, index: int) -> int: + """Get device id of a input tensor in a graph """ + pass + + def get_output_name(self, graph_name: str, index: int) -> str: + """Get output tensor name of a specified index in a graph """ + pass + + def get_output_tensor_devid(self, graph_name: str, index: int) -> int: + """Get device id of a output tensor in a graph """ + pass + + def get_input_shape(self, graph_name: str, index: int, stage: int = 0) -> list[int]: + """Get the shape of an input tensor in a graph """ + pass + + def get_input_max_shape(self, graph_name: str, index: int) -> list[int]: + """Get the max shape of a graph's index-th input """ + pass + + def get_output_shape(self, graph_name: str, index: int, stage: int = 0) -> list[int]: + """Get the shape of an output tensor in a graph """ + pass + + def get_output_max_shape(self, graph_name: str, index: int) -> list[int]: + """Get the max shape of a graph's index-th output """ + pass + + def get_input_dtype(self, graph_name: str, index: int) -> Dtype: + """Get data type of an input tensor""" + pass + + def get_output_dtype(self, graph_name: str, index: int) -> Dtype: + """Get data type of an output tensor""" + pass + + def get_input_scale(self, graph_name: str, index: int) -> float: + """Get scale of an input tensor""" + pass + + def get_output_scale(self, graph_name: str, index: int) -> float: + """Get scale of an output tensor""" + pass + + def get_input_tensors(self, graph_name: str, tensor_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all input Tensors and input index, only for address assign mode is 1 """ + pass + + def get_input_tensors(self, graph_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all input Tensors and input index, only for address assign mode is 1 """ + pass + + def get_input_tensor(self, graph_name: str, index: int, stage: int = 0) -> Tensor: + """Get one input Tensor, only for address assign mode is 1 """ + pass + + def create_max_input_tensors(self, graph_name: str) -> dict[int,Tensor]: + """Create input Tensors according to max input shape, only for address assign mode 0 """ + pass + + def get_output_tensors(self, graph_name: str, tensor_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all output Tensors and output index, only for address assign mode is 1 """ + pass + + def get_output_tensors(self, graph_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all output Tensors and output index, only for address assign mode is 1 """ + pass + + def get_output_tensor(self, graph_name: str, index: int, stage: int = 0) -> Tensor: + """Get one output Tensor, only for address assign mode is 1 """ + pass + + def create_max_output_tensors(self, graph_name: str) -> dict[int,Tensor]: + """Create output Tensors according to max output shape, only for address assign mode 0 """ + pass + + def get_input_tensors_addrmode0(self, graph_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all input Tensors and input index, even when addr_mode is 0 """ + pass + + def get_output_tensors_addrmode0(self, graph_name: str, stage: int = 0) -> dict[int,Tensor]: + """Get all output Tensors and output index, even when addr_mode is 0 """ + pass + +""" +SAIL multimedia +=============== + +Provides + 1. Codec + 2. Bmcv + +""" + + +class Format(enum.Enum): + FORMAT_YUV420P = 0 + FORMAT_YUV422P = 1 + FORMAT_YUV444P = 2 + FORMAT_NV12 = 3 + FORMAT_NV21 = 4 + FORMAT_NV16 = 5 + FORMAT_NV61 = 6 + FORMAT_NV24 = 7 + FORMAT_RGB_PLANAR = 8 + FORMAT_BGR_PLANAR = 9 + FORMAT_RGB_PACKED = 10 + FORMAT_BGR_PACKED = 11 + FORMAT_RGBP_SEPARATE = 12 + FORMAT_BGRP_SEPARATE = 13 + FORMAT_GRAY = 14 + FORMAT_COMPRESSED = 15 + FORMAT_ARGB_PACKED = 16 + +class ImgDtype(enum.Enum): + DATA_TYPE_EXT_FLOAT32 = 0 + DATA_TYPE_EXT_1N_BYTE = 1 + DATA_TYPE_EXT_4N_BYTE = 2 + DATA_TYPE_EXT_1N_BYTE_SIGNED = 3 + DATA_TYPE_EXT_4N_BYTE_SIGNED = 4 + +class bmcv_resize_algorithm(enum.Enum): + BMCV_INTER_NEAREST = 0 + BMCV_INTER_LINEAR = 1 + BMCV_INTER_BICUBIC = 2 + +class DecoderStatus(enum.Enum): + NONE = -1 + OPENED = 0 + CLOSED = 1 + STATUS_MAX = 2 + +def set_decoder_env(env_name: str, env_value: str) -> None: + """ Set Decoder environment, must set befor Decoder Constructor, else use default values + + refcounted_frames, extra_frame_buffer_num, rtsp_transport, stimeout, rtsp_flags, buffer_size, max_delay, probesize, analyzeduration + """ + pass + +def base64_encode(handle: Handle, input_bytes: bytes) -> bytes: + """ Encode a base64 string """ + pass + +def base64_decode(handle: Handle, encode_bytes: bytes) -> bytes: + """ Decoder a base64 string """ + pass + +def base64_encode_array(handle: Handle, input_arr: numpy.ndarray) -> bytes: + """ Encode a base64 string """ + pass + +def base64_decode_asarray(handle: Handle, encode_arr_bytes: bytes, array_type:str = "uint8") -> numpy.ndarray: + """ Decoder a base64 string """ + pass + +class bm_image: + def width(self) -> int: pass + def height(self) -> int: pass + def format(self) -> Format: pass + def dtype(self) -> ImgDtype: pass + +class BMImage: + def __init__(self) -> BMImage: pass + + def __init__(self, handle: Handle, + h: int, w: int, + format: Format, + dtype: ImgDtype) -> BMImage: pass + + def __init__(self, handle: Handle, + buffer: bytes | numpy.ndarray, + h: int, w: int, + format: Format, + dtype: ImgDtype = ImgDtype.DATA_TYPE_EXT_1N_BYTE, + strides: list = [], + offset: int = 0 + ) -> BMImage: pass + + def width(self) -> int: pass + + def height(self) -> int: pass + + def format(self) -> int: pass + + def dtype(self) -> int: pass + + def data(self) -> bm_image: + """ Get inner bm_image """ + pass + + def get_plane_num(self) -> int: pass + + def need_to_free(self) -> bool: pass + + def empty_check(self) -> int: pass + + def get_device_id(self) -> int: pass + + def get_handle(self) -> Handle: + """ Get Handle of BMImage """ + pass + + def asmat(self) -> numpy.ndarray[numpy.uint8]: pass + + def asnumpy(self) -> numpy.ndarray: + """ + Convert BMImage to numpy.ndarray containing raw data, without color + space convert. + """ + pass + + +class Decoder: + def __init__(self, file_path: str, compressed: bool = True, dev_id: int = 0) -> Decoder: + """ + Decoder by VPU + + Parameters: + ---------- + file_path : str + Path or rtsp url to the video/image file. + compressed : bool, optional + Whether the format of decoded output is compressed NV12. + Defaults is True. + dev_id : int, optional + ID of TPU. + Defaults to 0. + """ + pass + + def is_opened(self) -> bool: + """ Judge if the source is opened successfully. """ + pass + + def get_frame_shape(self) -> list[int]: + """ Get frame shape in the Decoder. + + Returns + ------- + list[int], [1, C, H, W] + """ + pass + + def read(self, handle: Handle) -> BMImage: pass + # def read(self, handle: Handle, image: BMImage) -> int: pass + def read_(self, handle: Handle, image: bm_image) -> None: pass + def get_fps(self) -> float: pass + def release(self) -> None: pass + def reconnect(self) -> int: pass + + def enable_dump(self, dump_max_seconds: int) -> None: pass + def disable_dump(self) -> None: pass + def dump(self, dump_pre_seconds: int, dump_post_seconds: int, file_path: str) -> int: + """ dump input video without encode. + + Parameters: + ---------- + dump_pre_seconds : int + dump video length(seconds) before dump moment + dump_post_seconds : int + dump video length(seconds) after dump moment + file_path : str + output path + + Returns + ------- + int, 0 for success + """ + pass + + def get_pts_dts(self) -> list: + """ Get the pts and dts + + Returns + ------- + lists, pts and dts + """ + pass + +class Decoder_RawStream: + def __init__(self, tpu_id: int = 0 , decformat: str = None ) -> Decoder_RawStream: + pass + + def read_(self, data_bytes: bytes, image: bm_image, continue_frame: bool = False) -> int: + """ + Read from the decoder. + Parameters: + - data_bytes: Input h264 or h265 data as bytes. + - image: Output bm_image. + - continue_frame: Flag to indicate if it's a continuous frame. + Returns: + - int: 0 for success, other values for failure. + """ + pass + + def read(self, data: bytes, image: BMImage, continue_frame: bool = False) -> int: + pass + + def release(self) -> None: pass + + def read_single_frame(self, data: bytes, image: BMImage, continue_frame: bool = False, need_flush: bool = False) -> int: + pass + + +class PaddingAtrr: + def __init__(self): pass + def __init__(self,stx: int, sty: int, w: int, h: int, \ + r: int, g: int, b: int): pass + def set_stx(self, stx: int) -> None : pass + def set_sty(self, sty: int) -> None : pass + def set_w(self, w: int) -> None : pass + def set_h(self, h: int) -> None : pass + def set_r(self, r: int) -> None : pass + def set_g(self, g: int) -> None : pass + def set_b(self, b: int) -> None : pass + + +class Bmcv: + def __init__(self, handle: Handle) -> None: pass + + def bm_image_to_tensor(self, img: BMImage|BMImageArray, tensor: Tensor) -> None: + """ + Convert BMImage|BMImageArray to tensor + + Parameters: + ---------- + img : BMImage|BMImageArray(Input image) + + Returns + ------- + tensor: Tensor(Output tensor) + """ + pass + + def bm_image_to_tensor(self, img: BMImage|BMImageArray) -> Tensor: + """ + Convert BMImage|BMImageArray to tensor + + Parameters: + ---------- + img : BMImage|BMImageArray(Input image) + + Returns + ------- + tensor: Tensor(Output tensor) + """ + pass + + def tensor_to_bm_image(self, tensor: Tensor, img: BMImage|BMImageArray, bgr2rgb: bool = False, layout: str = 'nchw') -> None: + """ + Convert tensor to BMImage|BMImageArray + + Parameters: + ---------- + tensor : Tensor + Input tensor. + bgr2rgb : bool, optional + Swap color channel, default is False. + layout : str, optional + Layout of the input tensor: 'nchw' or 'nhwc', default is 'nchw'. + + Returns + ------- + img: BMImage|BMImageArray + Output image + """ + pass + + def tensor_to_bm_image(self, tensor: Tensor, img: BMImage|BMImageArray, format: Format) -> None: + """ + Convert tensor to BMImage|BMImageArray + + Parameters: + ---------- + tensor : Tensor + Input tensor. + format : Format + Format of the BMImage. + + Returns + ------- + img: BMImage|BMImageArray + Output image + """ + pass + + def tensor_to_bm_image(self, tensor: Tensor, bgr2rgb: bool = False, layout: str = 'nchw') -> BMImage: + """ + Convert tensor to BMImage + + Parameters: + ---------- + tensor : Tensor + Input tensor. + bgr2rgb : bool, optional + Swap color channel, default is False. + layout : str, optional + Layout of the input tensor: 'nchw' or 'nhwc', default is 'nchw'. + + Returns + ------- + img: BMImage + Output image + """ + pass + + def tensor_to_bm_image(self, tensor: Tensor, format: Format) -> BMImage: + """ + Convert tensor to BMImage + + Parameters: + ---------- + tensor : Tensor + Input tensor. + format : Format + Format of the BMImage. + + Returns + ------- + img: BMImage + Output image + """ + pass + + def mat_to_bm_image(self, mat: numpy.ndarray[numpy.uint8]) -> BMImage: + """ + Convert cv mat to BMImage + + Parameters: + ---------- + mat: input cv mat, rgb_packed. + + Returns + ------- + img: BMImage + Output image + """ + pass + + def mat_to_bm_image(self, mat: numpy.ndarray[numpy.uint8], img: BMImage) -> int: + """ + Convert cv mat to BMImage + + Parameters: + ---------- + mat: input cv mat, rgb_packed. + img: output BMImage + """ + pass + + def crop_and_resize(self, input: BMImage|BMImageArray, + crop_x0: int, crop_y0: int, crop_w: int, crop_h: int, resize_w: int, resize_h: int, + resize_alg: bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Crop then resize an image. """ + pass + + def crop(self, input: BMImage|BMImageArray, crop_x0: int, crop_y0: int, crop_w: int, crop_h: int) -> BMImage|BMImageArray: + """Crop an image with given window. """ + pass + + def resize(self, input: BMImage|BMImageArray, resize_w: int, resize_h: int, + resize_alg: bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Resize an image with interpolation of INTER_NEAREST. """ + pass + + def vpp_crop_and_resize(self, input: BMImage|BMImageArray, + crop_x0: int, crop_y0: int, crop_w: int, crop_h: int, resize_w: int, resize_h: int, + bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Crop then resize an image using vpp. """ + pass + + def vpp_crop(self, input: BMImage|BMImageArray, crop_x0: int, crop_y0: int, crop_w: int, crop_h: int) -> BMImage|BMImageArray: + """Crop an image with given window using vpp. """ + pass + + def vpp_resize(self, input: BMImage|BMImageArray, output: BMImage|BMImageArray, resize_w: int, resize_h: int, + bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> None: + """Resize an image with interpolation of INTER_NEAREST using vpp. """ + pass + + def vpp_resize(self, input: BMImage|BMImageArray, resize_w: int, resize_h: int, + bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Resize an image with interpolation of INTER_NEAREST using vpp. """ + pass + + def vpp_crop_and_resize_padding(self, input: BMImage|BMImageArray, crop_x0: int, crop_y0: int, crop_w: int, crop_h: int, + resize_w: int, resize_h: int, padding_in: PaddingAtrr, + resize_alg: bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Crop then resize an image using vpp. """ + pass + + def crop_and_resize_padding(self, input: BMImage, crop_x0: int, crop_y0: int, crop_w: int, crop_h: int, + resize_w: int, resize_h: int, padding_in: PaddingAtrr) -> BMImage: + """Crop then resize an image. """ + pass + + def vpp_crop_padding(self, input: BMImage|BMImageArray, resize_w: int, resize_h: int, padding_in: PaddingAtrr) -> BMImage|BMImageArray: + """Crop an image with given window using vpp. """ + pass + + def vpp_resize_padding(self, input: BMImage|BMImageArray, resize_w: int, resize_h: int, padding_in: PaddingAtrr, + bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_NEAREST) -> BMImage|BMImageArray: + """Resize an image with interpolation of INTER_NEAREST using vpp. """ + pass + + def yuv2bgr(self, input: BMImage|BMImageArray) -> BMImage|BMImageArray: + """Convert an image from YUV to BGR.""" + pass + + def warp(self, input: BMImage|BMImageArray, matrix, use_bilinear: int = 0, similar_to_opencv: bool = False) -> BMImage|BMImageArray: + """ + Applies an affine transformation to an image. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + matrix: 2x3 transformation matrix + use_bilinear: Bilinear use flag, 0 for nearest interpolation and 1 for bilinear interpolation + similar_to_opencv: Whether to use the interface aligning the affine transformation interface of OpenCV + + Returns: + ------- + Output image + """ + pass + def warp(self, input: BMImage|BMImageArray, output: BMImage|BMImageArray, matrix, use_bilinear: int = 0, similar_to_opencv: bool = False) -> int: + """ + Applies an affine transformation to an image. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + output: BMImage|BMImageArray(Output image) + matrix: 2x3 transformation matrix + use_bilinear: Bilinear use flag, 0 for nearest interpolation and 1 for bilinear interpolation + similar_to_opencv: Whether to use the interface aligning the affine transformation interface of OpenCV + + Returns: + ------- + int, 0 for success + """ + pass + + def warp_perspective(self, input: BMImage, coordinate, output_width: int, output_height: int, \ + format: Format = Format.FORMAT_BGR_PLANAR, dtype: ImgDtype = ImgDtype.DATA_TYPE_EXT_1N_BYTE, \ + use_bilinear: int = 0 ) -> BMImage: + """ + Applies a perspective transformation to an image. + + Parameters: + ---------- + input: BMImage + coordinate: Original coordinate, like(left_top.x, left_top.y), (right_top.x, right_top.y), \ + (left_bottom.x, left_bottom.y), (right_bottom.x, right_bottom.y) + output_width: Output width + output_height: Output height + Format: Output image format, Only FORMAT_BGR_PLANAR,FORMAT_RGB_PLANAR + dtype: Output image dtype, Only DATA_TYPE_EXT_1N_BYTE,DATA_TYPE_EXT_4N_BYTE + use_bilinear: Bilinear use flag. + + Returns: + ------- + Output image + """ + pass + + def convert_to(self, input: BMImage|BMImageArray, output: BMImage|BMImageArray, alpha_beta) -> None: + """ + Applies a linear transformation to an image. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + alpha_beta:like (a0, b0), (a1, b1), (a2, b2) factors + + Returns: + output: BMImage|BMImageArray(Output image) + """ + pass + + def convert_to(self, input: BMImage|BMImageArray, alpha_beta) -> BMImage|BMImageArray: + """ + Applies a linear transformation to an image. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + alpha_beta: (a0, b0), (a1, b1), (a2, b2) factors + + Returns: + output: BMImage|BMImageArray(Output image) + """ + pass + + def rectangle(self, image: BMImage, x: int, y: int, w: int, h: int, color, thickness: int = 1) -> None: + """ + Draw a rectangle on input image. + + Parameters: + ---------- + image: BMImage, Input image + x: int, Start point x of rectangle + y: int, Start point y of rectangle + w: int, Width of rectangle + h: int, Height of rectangle + color: Color of rectangle, like (0, 0, 255) + thickness: int, optional, default is 1 + """ + pass + + def rectangle(self, image: bm_image, x: int, y: int, w: int, h: int, color, thickness: int = 1) -> None: + """ + Draw a rectangle on input image. + + Parameters: + ---------- + image: bm_image, Input image + x: int, Start point x of rectangle + y: int, Start point y of rectangle + w: int, Width of rectangle + h: int, Height of rectangle + color: Color of rectangle, like (0, 0, 255) + thickness: int, optional, default is 1 + """ + pass + def fillRectangle(self, image: BMImage, x: int, y: int, w: int, h: int, color) -> None: + """ + Fill a rectangle on input image. + + Parameters: + ---------- + image: BMImage, Input image + x: int, Start point x of rectangle + y: int, Start point y of rectangle + w: int, Width of rectangle + h: int, Height of rectangle + color: Color of rectangle, like (0, 0, 255) + """ + pass + def fillRectangle(self, image: bm_image, x: int, y: int, w: int, h: int, color) -> None: + """ + Fill a rectangle on input image. + + Parameters: + ---------- + image: bm_image, Input image + x: int, Start point x of rectangle + y: int, Start point y of rectangle + w: int, Width of rectangle + h: int, Height of rectangle + color: Color of rectangle, like (0, 0, 255) + """ + pass + def putText(self, image: BMImage, text: str, x: int, y: int, color, fontScale: float, thickness: int=1) -> None: + """ + Draw Text on input image. + + Parameters: + ---------- + image: BMImage, Input image + text: str, Text string to be drawn + x: int, Start point x + y: int, Start point y + color: color of text, like(0, 0, 255) + fontScale: float, Font scale factor that is multiplied by the font-specific base size + thickness: int, optional, default is 1 + """ + pass + + def putText(self, image: bm_image, text: str, x: int, y: int, color, fontScale: float, thickness: int=1) -> None: + """ + Draw Text on input image. + + Parameters: + ---------- + image: bm_image, Input image + text: str, Text string to be drawn + x: int, Start point x + y: int, Start point y + color: color of text, like(0, 0, 255) + fontScale: float, Font scale factor that is multiplied by the font-specific base size + thickness: int, optional, default is 1 + """ + pass + + + def imwrite(self, filename: str, image: BMImage) -> None: + """ + Save the image to the specified file. + + Parameters: + ---------- + filename: str + Name of the save file. + image: BMImage + Image to be saved. + """ + pass + + def imwrite(self, filename: str, image: bm_image) -> None: + """ + Save the image to the specified file. + + Parameters: + ---------- + filename: str + Name of the save file. + image: bm_image + Image to be saved. + """ + pass + + def get_handle(self) -> Handle: + """Get Handle instance. """ + pass + + def convert_format(self, input: BMImage, output: BMImage) -> None: + """Convert input to output format. """ + pass + + def convert_format(self, input: BMImage) -> BMImage: + """Convert an image to BGR PLANAR format. """ + pass + + def vpp_convert_format(self, input: BMImage, output: BMImage) -> None: + """Convert input to output format using vpp. """ + pass + + def vpp_convert_format(self, input: BMImage) -> BMImage: + """Convert an image to BGR PLANAR format using vpp. """ + pass + + def get_bm_data_type(self, format: ImgDtype) -> Dtype: pass + + def get_bm_image_data_format(self, dtype: Dtype) -> ImgDtype: pass + + def image_add_weighted(self, input1: BMImage, alpha: float, input2: BMImage, \ + beta: float, gamma: float, output: BMImage) -> int: + """output = input1 * alpha + input2 * beta + gamma.""" + pass + + def image_add_weighted(self, input1: BMImage, alpha: float, input2: BMImage, \ + beta: float, gamma: float) -> BMImage: + """output = input1 * alpha + input2 * beta + gamma.""" + pass + + def image_copy_to(self, input: BMImage|BMImageArray, output: BMImage|BMImageArray, \ + start_x: int, start_y: int) -> None: + """ + Copy the input to the output. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + output: BMImage|BMImageArray(Output image) + start_x: point start x + start_y: point start y + """ + pass + + def image_copy_to_padding(self, input: BMImage|BMImageArray, output: BMImage|BMImageArray, \ + padding_r: numpy.uint8, padding_g: numpy.uint8, padding_b: numpy.uint8, start_x: int, start_y: int) -> None: + """ + Copy the input to the output width padding. + + Parameters: + ---------- + input: BMImage|BMImageArray(Input image) + output: BMImage|BMImageArray(Output image) + padding_r: r value for padding + padding_g: g value for padding + padding_b: b value for padding + start_x: point start x + start_y: point start y + """ + pass + + def convert_yuv420p_to_gray(self, input:BMImage, output:BMImage) -> int: + """ + Convert YUV420P to gray image. + + Parameters: + ---------- + input: BMImage(Input image) + output: BMImage(Output image) + """ + pass + + def convert_yuv420p_to_gray(self, input:bm_image, output:bm_image) -> int: + """ + Convert YUV420P to gray image. + + Parameters: + ---------- + input: bm_image(Input image) + output: bm_image(Output image) + """ + pass + + def nms(self, input: numpy.ndarray[Any, numpy.dtype[numpy.float32]], threshold: float) -> numpy.ndarray[Any, numpy.dtype[numpy.float32]]: + """ + Do nms use tpu. + + Parameters: + ---------- + input: input proposal array + shape must be (n,5) n<56000, proposal:[left,top,right,bottom,score] + threshold: nms threshold + + Returns: + ---------- + return nms result, numpy.ndarray[Any, numpy.dtype[numpy.float32]] + """ + pass + + def drawPoint(self, image: BMImage, center: tuple[int, int], color: tuple[int, int, int], radius: int) -> int: + """ + Draw Point on input image. + + Parameters: + ---------- + image: BMImage, Input image + center: Tuple[int, int], center of point, (point_x, point_y) + color: Tuple[int, int, int], color of drawn, (b,g,r) + radius: Radius of drawn + """ + pass + + def drawPoint(self, image: bm_image, center: tuple[int, int], color: tuple[int, int, int], radius: int) -> int: + """ + Draw Point on input image. + + Parameters: + ---------- + image: bm_image, Input image + center: Tuple[int, int], center of point, (point_x, point_y) + color: Tuple[int, int, int], color of drawn, (b,g,r) + radius: Radius of drawn + """ + pass + + def polylines(self, image: BMImage, pts: list[list[tuple[int, int]]], isClosed: bool, color: tuple[int, int, int], thickness: int = 1, shift: int = 0) -> int: + """ + Draw one or more line segments on an image and polygonal curves. + + Parameters: + ---------- + image: input image + pts: The starting point and end point coordinates of the line segment, multiple coordinate points can be entered. + The upper left corner of the image is the origin, + extending to the right in the x direction and extending down in the y direction. + isClosed: Whether the graph is closed. + color: The color of the line is the value of the three RGB channels. + thickness: The width of the lines is recommended to be even for YUV format images. + shift: Polygon scaling multiple. Default is not scaling. The scaling factor is(1/2)^shift。 + + Returns: + ---------- + returns 0 if success. + """ + pass + + def mosaic(self, mosaic_num: int, img: BMImage, rects: list[list[int,int,int,int]], is_expand:int) -> int: + """ + Print one or more mosaics on an image. + + Parameters: + ---------- + mosaic_num: Number of mosaics, length of list in rects. + img: Input BMImage. + rects: Multiple Mosaic positions, the parameters in each element in the list are + [Mosaic at X-axis start point, Mosaic at Y-axis start point, Mosaic width, Mosaic height]. + is_expand:A value of 0 means that the column is not expanded, + and a value of 1 means that a macro block (8 pixels) + + Returns: + ---------- + returns 0 if success. + """ + pass + + def transpose(self, src: BMImage, dst: BMImage) -> int: + """ + Transpose of image width and height. + + Parameters: + ---------- + src: Input BMImage + dst: Output BMImage + + Returns: + ---------- + returns 0 if success. + """ + pass + + def transpose(self, src: BMImage) -> BMImage: + """ + Transpose of image width and height. + + Parameters: + ---------- + src: Input BMImage + + Returns: + ---------- + Output BMImage + """ + pass + + def gaussian_blur(self, input: BMImage, kw: int, kh : int, sigmaX : float, sigmaY : float = 0.0) -> BMImage: + """ + Gaussian blur + + Parameters: + ---------- + input: BMImage + kw: int, size of kernel in the width direction. + kh: int, size of kernel in the height direction. + sigmaX : float, gaussian kernel standard deviation in the X direction. + sigmaY : float, gaussian kernel standard deviation in the Y direction.Default is 0.0, + which means that it is the same standard deviation as the Gaussian kernel in the X direction. + + Returns: + ---------- + return gaussian blur image + """ + pass + + def Sobel(self, input: BMImage, output: BMImage, dx: int, dy: int, ksize: int = 3, scale: float = 1, delta: float = 0) -> int: + """ + Edge detection Sobel Operator. + + Parameters: + ---------- + input Input BMImage + output Output BMImage + dx Order of the derivative x. + dy Order of the derivative y + ksize ize of the extended Sobel kernel; it must be -1, 1, 3, 5, or 7. + scale Optional scale factor for the computed derivative values; by default, no scaling is applied + delta Optional delta value that is added to the results prior to storing them in dst. + + Returns: + ---------- + return 0 if success + """ + pass + + def Sobel(self, input: BMImage, dx: int, dy: int, ksize: int = 3, scale: float = 1, delta: float = 0) -> BMImage: + """ + Edge detection Sobel Operator. + + Parameters: + ---------- + input Input BMImage + dx Order of the derivative x. + dy Order of the derivative y + ksize ize of the extended Sobel kernel; it must be -1, 1, 3, 5, or 7. + scale Optional scale factor for the computed derivative values; by default, no scaling is applied + delta Optional delta value that is added to the results prior to storing them in dst. + + Returns: + ---------- + return processed BMImage + """ + pass + + def imdecode(self, data_bytes: bytes) -> BMImage: + """ + Load Jpeg image from system memory. + + Parameters: + ---------- + data_bytes: image data bytes in system memory + + + Returns: + ---------- + return decoded image + """ + pass + + def imencode(self, ext: str, img: BMImage) -> numpy.ndarray: + """ + Compresses the BMImage and stores it in the memory + + Parameters: + ---------- + ext: File extension that defines the output format. + img: BMImage to be written + buf: Output buffer resized to fit the compressed BMImage + + Returns: + ---------- + return encoded array + """ + pass + + def imread(self, filename: str) -> BMImage: + """ + Read a jpeg image from file. Only support jpeg baseline image. The returned BMImage keeps YUV color space. + + Parameters: + ---------- + filename: Name of file to be read. + + Returns: + ---------- + Return decoded BMImage, whose pixel format is in YUV color space. + """ + pass + + def stft(self, input_real: numpy.ndarray, input_imag: numpy.ndarray, real_input: bool, normalize: bool, n_fft: int, hop_len: int, + pad_mode: int, win_mode: int) -> tuple[numpy.ndarray, numpy.ndarray]: + """ + Short-Time Fourier Transform (STFT) for NumPy arrays. + + Parameters: + ---------- + input_real: numpy.ndarray + The real part of the input signal as a 1D array. + input_imag: numpy.ndarray + The imaginary part of the input signal as a 1D array. + real_input: bool + Indicates whether the input is purely real. If true, the imaginary part is ignored. + normalize: bool + Indicates whether to normalize the output. + n_fft: int + The number of points in the FFT. This defines the resolution of the frequency bins. + hop_len: int + The number of samples to hop between successive frames. This controls the overlap. + pad_mode: int + An integer indicating the padding mode to use when the input signal is shorter than the expected length: + - 0: Constant padding (pads with zeros). + - 1: Reflective padding (pads by reflecting the signal). + win_mode: int + An integer specifying the window function to apply to each segment: + - 0: Hann window. + - 1: Hamming window. + + Returns: + ---------- + tuple[numpy.ndarray, numpy.ndarray] + A tuple containing two NumPy arrays representing the STFT output: + - The first array is the real part of the STFT. + - The second array is the imaginary part of the STFT. + """ + pass + + def stft(self, input_real: Tensor, input_imag: Tensor, real_input: bool, normalize: bool, n_fft: int, hop_len: int, + pad_mode: int, win_mode: int) -> tuple[Tensor, Tensor]: + pass + + def istft(self, input_real: numpy.ndarray, input_imag: numpy.ndarray, real_input: bool, normalize: bool, L: int, hop_len: int, + pad_mode: int, win_mode: int) -> tuple[numpy.ndarray, numpy.ndarray]: + """ + Inverse Short-Time Fourier Transform (ISTFT) for NumPy arrays. + + Parameters: + ---------- + input_real: numpy.ndarray + The real part of the STFT output as a 1D array. + input_imag: numpy.ndarray + The imaginary part of the STFT output as a 1D array. + real_input: bool + Indicates whether the input STFT is purely real. If true, the imaginary part is ignored. + normalize: bool + Indicates whether to normalize the output. + L: int + The length of the original time-domain signal to reconstruct. + hop_len: int + The number of samples to hop between successive frames. This controls the overlap. + pad_mode: int + An integer indicating the padding mode to use when the input signal is shorter than the expected length: + - 0: Constant padding (pads with zeros). + - 1: Reflective padding (pads by reflecting the signal). + win_mode: int + An integer specifying the window function to apply to each segment when reconstructing the signal: + - 0: Hann window. + - 1: Hamming window. + + Returns: + ---------- + tuple[numpy.ndarray, numpy.ndarray] + A tuple containing two NumPy arrays representing the reconstructed time-domain signal: + - The first array is the reconstructed signal. + - The second array is the corresponding phase information (if applicable). + """ + pass + + def istft(self, input_real: Tensor, input_imag: Tensor, real_input: bool, normalize: bool, L: int, hop_len: int, + pad_mode: int, win_mode: int) -> tuple[Tensor, Tensor]: + pass + + def fft(self, forward: bool, input_real: Tensor) -> list[Tensor]: + """ + 1d or 2d fft (only real part) + + Parameters: + ---------- + forward: bool, positive transfer + input_real: Tensor, input tensor + + + Returns: + ---------- + return list[Tensor], The real and imaginary part of output + """ + pass + + def fft(self, forward: bool, input_real: Tensor, input_imag: Tensor) -> list[Tensor]: + """ + 1d or 2d fft (real part and imaginary part) + + Parameters: + ---------- + forward: bool, positive transfer + input_real: Tensor, input tensor real part + input_imag: Tensor, input tensor imaginary part + + + Returns: + ---------- + return list[Tensor], The real and imaginary part of output + """ + pass + + def bmcv_overlay(self, image: BMImage, overlay_info: list[list[int]], overlay_image: list[BMImage]) -> int: + """ + Add a watermark with a transparent channel to the image + + Parameters: + ----------- + image: BMImage, the base image + overlay_info: a list of rect (x,y,w,h) + overlay_image: a list of watermark image with a transparent channel + + Returns: + return ret, 0 for success and others for failed + """ +class BMImageArray(): + def __init__(self) -> None: ... + + def __init__(self, handle: Handle, h: int, w: int, format: Format, dtype: ImgDtype ) -> None: ... + + def __len__(self) -> int: pass + + def __getitem__(self, i: int) -> bm_image: pass + + def __setitem__(self, i: int, data: bm_image) -> None: + """ + Copy the image to the specified index. + + Parameters: + ---------- + i: int + Index of the specified location. + data: bm_image + Input image. + """ + pass + + def copy_from(self, i: int, data:BMImage) -> None: + """ + Copy the image to the specified index. + + Parameters: + ---------- + i: int + Index of the specified location. + data: bm_image + Input image. + """ + pass + + def attach_from(self, i: int, data: BMImage) -> None: + """ + Attach the image to the specified index.(Because there is no memory copy, the original data needs to be cached) + + Parameters: + ---------- + i: int + Index of the specified location. + data: BMImage + Input image. + """ + pass + + def watermark_superpose(self, + image: BMImage, + water_name:str, + bitmap_type: int, + pitch: int, + rects: list[list[int]], + color: tuple + ) -> int: + """ + Add a watermark_superpose to BMImage. + + Parameters: + ---------- + image: BMImage + input BMImage + water_name:str + input watermark_superpose + bitmap_type: int + bitmap_type of input watermark_superpose,0/1,0 8byte,1 1byte + pitch: int + the width of input watermark_superpose + rects: list[list[int]] + the rects of input watermark_superpose + color: tuple + the color of input watermark_superpose + """ + pass + + def get_device_id(self) -> int: pass + + +class BMImageArray2D(BMImageArray): pass +class BMImageArray3D(BMImageArray): pass +class BMImageArray4D(BMImageArray): pass +class BMImageArray8D(BMImageArray): pass +class BMImageArray16D(BMImageArray): pass +class BMImageArray32D(BMImageArray): pass +class BMImageArray64D(BMImageArray): pass +class BMImageArray128D(BMImageArray): pass +class BMImageArray256D(BMImageArray): pass + +class MultiDecoder: + + def __init__(self, queue_size: int = 10, tpu_id: int = 0, discard_mode: int = 0): + """ MultiDecoder Constructor. + + Parameters: + ---------- + queue_size: int + Max queue size,default is 10. + tpu_id: int + ID of TPU, default is 0. + discard_mode: int + Data discard policy when the queue is full. Default is 0. + If 0, do not push the data to queue, else pop the data from queue and push new data to queue. + """ + pass + + + def set_read_timeout(self, timeout: int) -> None : + + """ Set read frame timeout waiting time + + Parameters: + ---------- + timeout: int + Set read frame timeout waiting time in seconds. + """ + pass + + + def add_channel(self, file_path: str, frame_skip_num: int = 0) -> int: + + """ Add a channel to decode + + Parameters: + ---------- + file_path : str + file path + frame_skip_num : int + frame skip number, default is 0 + + Returns: + ---------- + return channel index number, int + """ + pass + + def add_channel(self, file_path: str, frame_skip_num: int, loop_num: int) -> int: + + """ Add a channel to decode + + Parameters: + ---------- + file_path : str + file path + frame_skip_num : int + frame skip number + loop_num : int + loop number + + Returns: + ---------- + return channel index number, int + """ + pass + + def del_channel(self, channel_idx: int) -> int : + """ Delete channel + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + 0 for success and other for failure. + """ + pass + + def get_channel_fps(self, channel_idx: int) -> float: + """ Get the fps of the video stream in a specified channel + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + Returns the fps of the video stream in the specified channel + """ + pass + + def clear_queue(self, channel_idx: int) -> int : + """ Clear data cache queue + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + 0 for success and other for failure. + """ + pass + + def read(self, channel_idx: int, image: BMImage, read_mode: int = 0) -> int : + """ Read a BMImage from the MultiDecoder with a given channel. + + Parameters: + ---------- + channel_idx : int + channel index number + image: BMImage + BMImage instance to be read to + read_mode: int + Read data mode, 0 for not waiting data and other waiting data. + + Returns: + ------- + 0 for successed get data. + """ + pass + + def read(self,channel_idx: int) -> BMImage : + """ Read a BMImage from the MultiDecoder with a given channel. + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + BMImage instance to be read to + """ + pass + + + def read_(self, channel_idx: int, image: bm_image, read_mode: int=0) -> int : + """ Read a bm_image from the MultiDecoder with a given channel. + + Parameters: + ---------- + channel_idx : int + channel index number + image: bm_image + bm_image instance to be read to + read_mode: int + read data mode, default 0, if 0, not waiting data, else waiting data. + + Returns: + ------- + return 0 if get data. + """ + pass + + def read_(self,channel_idx: int) -> int : + """ Read a bm_image from the MultiDecoder with a given channel. + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + bm_image instance to be read to + """ + pass + + + def reconnect(self, channel_idx: int) -> int : + """ Reconnect Decoder for instance channel + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns: + ------- + 0 for success and other for failure. + + """ + pass + + + def get_frame_shape(self, channel_idx: int) -> list[int]: + """ Get frame for instance channel + + Parameters: + ---------- + channel_idx : int + channel index number + + Returns + ------- + list[int], [1, C, H, W] + """ + pass + + def set_local_flag(self, flag: bool) -> None: + """ Set local video flag + + Parameters: + ---------- + flag : bool + If flag is True, Decode up to 25 frames per second + + """ + pass + + def exhausted(self) -> None: + """ Set a flag. + just a status flag. Always uesd when image dataset has been traversed. + + """ + pass + + def get_exhausted_flag(self) -> bool: + """ get exhausted flag + + """ + pass + + def get_channel_status(self, channel_idx: int) -> DecoderStatus: + """ Get the status of the specific channel. + + Parameters: + ---------- + channel_idx : int + channel index + + Returns: + ------- + Returns the status of the the specified channel + """ + pass + + def is_channel_eof(self, channel_idx: int) -> bool: + """ + Get whether end of file is reached in the specific channel. + + Parameters + ---------- + channel_idx : int + channel index + + Returns + ------- + out : bool + Return True if EOF is reached else False + """ + +class sail_resize_type(enum.Enum): + BM_RESIZE_VPP_NEAREST = 0 + BM_RESIZE_TPU_NEAREST = 1 + BM_RESIZE_TPU_LINEAR = 2 + BM_RESIZE_TPU_BICUBIC = 3 + BM_PADDING_VPP_NEAREST = 4 + BM_PADDING_TPU_NEAREST = 5 + BM_PADDING_TPU_LINEAR = 6 + BM_PADDING_TPU_BICUBIC = 7 + + +class Encoder: + + def __init__(self): + """ + encoder constructor for pic + """ + pass + + def __init__(self, output_path: str, handle: Handle, enc_fmt: str, pix_fmt: str, enc_params: str, cache_buffer_length: int=5, abort_policy: int=0): + """ + encoder constructor for video + + Parameters: + ---------- + output_path: local file path or stream url + handle: sail.Handle + enc_fmt: encoder name, support h264_bm and h265_bm + pix_fmt: encoder pixel format, support I420 and NV12 + enc_params: encoder params, width=1920:height=1080:bitrate=2000:gop=32:gop_preset=2:framerate=25 + cache_buffer_length: The internal cache queue length defaults to 6. + abort_policy:The reject policy for video_write. 0 for returns -1 immediately. 1 for pop queue header. 2 for clear the queue. 3 for blocking. + """ + pass + + def __init__(self, output_path: str, device_id: int, enc_fmt: str, pix_fmt: str, enc_params: str, cache_buffer_length: int=5, abort_policy: int=0): + """ + encoder constructor for video + + Parameters: + ---------- + output_path: local file path or stream url + device_id: device id + enc_fmt: encoder name, support h264_bm and h265_bm + pix_fmt: encoder pixel format, support I420 and NV12 + enc_params: encoder params, width=1920:height=1080:bitrate=2000:gop=32:gop_preset=2:framerate=25 + cache_buffer_length: The internal cache queue length defaults to 6. + abort_policy:The reject policy for video_write. 0 for returns -1 immediately. 1 for pop queue header. 2 for clear the queue. 3 for blocking. + """ + pass + + def is_opened(self) -> bool: + + pass + + def pic_encode(self, ext: str, image: BMImage) -> numpy.ndarray[Any, numpy.dtype[Any]]: + """ + pic encode + + Parameters: + ---------- + ext: encode format, .jpg .png ... + image: input image + + Returns: + ---------- + return pic data numpy.ndarray[Any, numpy.dtype[numpy.uint8_t]] + """ + pass + + def pic_encode(self, ext: str, image: bm_image) -> numpy.ndarray[Any, numpy.dtype[Any]]: + + pass + + def video_write(self, image: BMImage) -> int: + """ + On BM1684, it is required that the image shape be consistent with the width and height specified by the encoder, \ + video_write use bmcv_image_storage_convert to perform format conversion. + On BM1684X, video_write use bmcv_image_vpp_convert to resize and format conversion. + + Parameters: + ---------- + image: BMImage + + Returns: + ---------- + Successfully returned 0, internal cache queue full returned -1. encode failed returns -2. push stream failed returns -3. unknown abort policy returns -4. + """ + pass + + def video_write(self, image: bm_image) -> int: + + pass + + def release(self) -> None: + """ + release resources + only invoked when video encode finished + """ + pass + + +class EngineImagePreProcess: + + def __init__(self, bmodel_path: str, tpu_id: int, use_mat_output: bool = False, core_list:list = []): + """ EngineImagePreProcess Constructor. + + Parameters + ---------- + bmodel_path: str + tpu_id: int + ID of TPU, there may be more than one TPU for PCIE mode,default is 0. + core_list: list + CORE of choosed TPU,default is None. + use_mat_output : bool + Use opencv Mat for output images + """ + pass + + def InitImagePreProcess(self, resize_mode: sail_resize_type, bgr2rgb: bool = False, + queue_in_size: int = 20, queue_out_size: int = 20) -> int: + """ initialize ImagePreProcess. + + Parameters + ---------- + resize_mode: sail_resize_type + Resize Methods + bgr2rgb: bool + The flag of convert BGR image to RGB, default is False. + queue_in_size: int + Max input image data queue size, default is 20. + queue_out_size: int + Max output tensor data queue size, default is 20. + + Returns + ------- + 0 for success and other for failure + """ + pass + + + def SetPaddingAtrr(self,padding_b:int=114,padding_g:int=114,padding_r:int=114,align:int=0) -> int : + """ Set the padding attribute object. + + Parameters + ---------- + padding_b: int + padding value of b channel, dafault 114 + padding_g: int + padding value of g channel, dafault 114 + padding_r: int + padding value of r channel, dafault 114 + align: int + padding position, default 0: start left top, 1 for center + + Returns + ------- + 0 for success and other for failure + """ + + def SetConvertAtrr(self,alpha_beta) -> int : + """ Set the linear transformation attribute + + Parameters + ---------- + alpha_beta:like (a0, b0), (a1, b1), (a2, b2) factors + + Returns + ------- + 0 for success and other for failure + """ + pass + + def PushImage(self, channel_idx : int, image_idx : int, image: BMImage) -> int: + """ Push Image + Parameters + ---------- + channel_idx : int + Channel index number of the image + image_idx: int + Image index number of the image + image: BMImage + Input image + + Returns + ------- + 0 for success and other for failure + """ + pass + + + def GetBatchData_Npy(self) -> tuple: + """ Get the Batch Data object + + Returns + ------- + [dict[str, ndarray], list[BMImage],list[int],list[int],list[list[int]]] + Output ndarray map, Original Images, Original Channel index, Original Indexm, Padding Atrr(start_x, start_y, width, height) + """ + pass + + def GetBatchData_Npy2(self) -> tuple: + """ Get the Batch Data object + + Returns + ------- + [dict[str, ndarray], list[numpy.ndarray[numpy.uint8]],list[int],list[int],list[list[int]]] + Output ndarray map, Original Images, Original Channel index, Original Indexm, Padding Atrr(start_x, start_y, width, height) + """ + pass + + def GetBatchData(self, need_d2s: bool = True) -> tuple: + """ Get the Batch Data object + + Parameters + ------------ + need_d2s : bool + Need copy data to system memory. + + Returns + ------- + [list[TensorPTRWithName], list[BMImage],list[int],list[int],list[list[int]]] + Output ndarray map, Original Images, Original Channel index, Original Indexm, Padding Atrr(start_x, start_y, width, height) + """ + pass + + def get_graph_name(self) -> str: + """ Get first graph name in the loaded bomodel + + Returns + ------- + First graph name + """ + pass + + def get_input_width(self) -> int: + """ Get model input width + + Returns + ------- + Model input width + """ + pass + + def get_input_height(self) -> int: + """ Get model input height + + Returns + ------- + Model input height + """ + pass + + def get_output_names(self) -> list[str]: + """ Get all output tensor names of the first graph + + Returns + ------- + All the output tensor names of the graph + """ + pass + + def get_output_shape(self, tensor_name: str) -> list[int]: + """ Get the shape of an output tensor in frist graph + + Parameters + ---------- + tensor_name : str + The specified tensor name + + Returns + ------- + The shape of the tensor + """ + pass + +class ImagePreProcess: + + def __init__(self, batch_size: int, resize_mode:sail_resize_type, tpu_id: int=0, + queue_in_size: int=20, queue_out_size: int=20): + """ ImagePreProcess Constructor. + + Parameters + ---------- + batch_size: int + Output batch size. + resize_mode: sail_resize_type + Resize Methods + tpu_id: int + ID of TPU, there may be more than one TPU for PCIE mode,default is 0. + queue_in_size: int + Max input image data queue size, default is 20. + queue_out_size: int + Max output tensor data queue size, default is 20. + """ + pass + + + def SetResizeImageAtrr(self, output_width: int, output_height: int ,bgr2rgb : bool, dtype: ImgDtype) -> None : + + """ Set the Resize Image attribute + + Parameters + ---------- + output_width: int + The width of resized image. + output_height: int + The height of resized image. + bgr2rgb: bool + The flag of convert BGR image to RGB. + dtype: ImgDtype + The data type of resized image,Only supported BM_FLOAT32,BM_INT8,BM_UINT8 + """ + pass + + + def SetPaddingAtrr(self,padding_b:int=114,padding_g:int=114,padding_r:int=114,align:int=0) -> None : + """ Set the padding attribute object. + + Parameters + ---------- + padding_b: int + padding value of b channel, dafault 114 + padding_g: int + padding value of g channel, dafault 114 + padding_r: int + padding value of r channel, dafault 114 + align: int + padding position, default 0: start left top, 1 for center + + """ + pass + + + def SetConvertAtrr(self,alpha_beta) -> int : + """ Set the linear transformation attribute + + Parameters + ---------- + alpha_beta:like (a0, b0), (a1, b1), (a2, b2) factors + + Returns + ------- + 0 for success and other for failure + """ + pass + + + def PushImage(self, channel_idx : int, image_idx : int, image: BMImage) -> int: + """ Push Image + Parameters + ---------- + channel_idx : int + Channel index number of the image + image_idx: int + Image index number of the image + image: BMImage + Input image + + Returns + ------- + 0 for success and other for failure + """ + pass + + def GetBatchData(self) -> tuple[Tensor, list[BMImage],list[int],list[int],list[list[int]]]: + """ Get the Batch Data object + + Returns + ------- + [Tensor, list[BMImage],list[int],list[int],list[list[int]]] + Output Tensor, Original Images, Original Channel index, Original Index, Padding Atrr(start_x, start_y, width, height) + """ + pass + + def set_print_flag(self, flag : bool) -> None: + """ Set the print flag + + Parameters + ---------- + flag : int + """ + pass + +class algo_yolov5_post_1output: + + def __init__(self, shape: list[int], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, input_use_multiclass_nms: bool=True, agnostic: bool=False): + + """ algo_yolov5_post_1output Constructor. + + Parameters + ---------- + shape: list[int] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + input_use_multiclass_nms: bool, default True + agnostic: bool, default False + """ + pass + + def push_npy(self, + channel_idx : int, + image_idx : int, + data : numpy.ndarray[Any, numpy.dtype[numpy.float_]], + dete_threshold : float, + nms_threshold : float, + ost_w : int, + ost_h : int, + padding_left : int, + padding_top : int, + padding_width : int, + padding_height : int) -> int: + """ algo_yolov5_post_1output push data. + + Parameters + ---------- + + channel_idx : Channel index number of the image. + image_idx : Image index number of the image. + data : Input Data + dete_threshold : Detection threshold + nms_threshold : NMS threshold + ost_w : Original image width + ost_h : Original image height + padding_left : Padding left + padding_top : Padding top + padding_width : Padding width + padding_height : Padding height + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : TensorPTRWithName, + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov5_post_1output push data. + + Parameters + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov8_post_1output_async: + + def __init__(self, shape: list[int], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, input_use_multiclass_nms: bool=True, agnostic: bool=False): + """ algo_yolov8_post_1output_async Constructor. + + Parameters + ---------- + shape: list[int] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + input_use_multiclass_nms: bool, default True + agnostic: bool, default False + """ + pass + + def push_npy(self, + channel_idx : int, + image_idx : int, + data : numpy.ndarray[Any, numpy.dtype[numpy.float_]], + dete_threshold : float, + nms_threshold : float, + ost_w : int, + ost_h : int, + padding_left : int, + padding_top : int, + padding_width : int, + padding_height : int) -> int: + """ algo_yolov8_post_1output_async push data. + + Parameters + ---------- + + channel_idx : Channel index number of the image. + image_idx : Image index number of the image. + data : Input Data + dete_threshold : Detection threshold + nms_threshold : NMS threshold + ost_w : Original image width + ost_h : Original image height + padding_left : Padding left + padding_top : Padding top + padding_width : Padding width + padding_height : Padding height + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : TensorPTRWithName, + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov8_post_1output_async push data. + + Parameters + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov8_post_cpu_opt_1output_async: + + def __init__(self, shape: list[int], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, input_use_multiclass_nms: bool=True, agnostic: bool=False): + """ algo_yolov8_post_cpu_opt_1output_async Constructor. + + Parameters + ---------- + shape: list[int] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + input_use_multiclass_nms: bool, default True + agnostic: bool, default False + """ + pass + + def push_npy(self, + channel_idx : int, + image_idx : int, + data : numpy.ndarray[Any, numpy.dtype[numpy.float_]], + dete_threshold : float, + nms_threshold : float, + ost_w : int, + ost_h : int, + padding_left : int, + padding_top : int, + padding_width : int, + padding_height : int) -> int: + """ algo_yolov8_post_cpu_opt_1output_async push data. + + Parameters + ---------- + + channel_idx : Channel index number of the image. + image_idx : Image index number of the image. + data : Input Data + dete_threshold : Detection threshold + nms_threshold : NMS threshold + ost_w : Original image width + ost_h : Original image height + padding_left : Padding left + padding_top : Padding top + padding_width : Padding width + padding_height : Padding height + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : TensorPTRWithName, + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov8_post_cpu_opt_1output_async push data. + + Parameters + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov5_post_3output: + + def __init__(self, shape: list[list[int]], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, input_use_multiclass_nms: bool=True, agnostic: bool=False): + """ algo_yolov5_post_1output Constructor. + + Parameters + ---------- + shape: list[list[int]] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + input_use_multiclass_nms: bool, default True + agnostic: bool, default False + """ + pass + + def reset_anchors(self, anchors_new: list[list[list[int]]]): + """ Reset Anchors + + Parameters + ---------- + anchors_new: list[list[list[int]]] + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : list[TensorPTRWithName], + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov5_post_1output push data. + + Parameters + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov5_post_cpu_opt_async: + + def __init__(self, shape: list[list[int]], network_w:int = 640, network_h:int = 640, max_queue_size: int=20, use_multiclass_nms: bool=True): + """ algo_yolov5_post_cpu_opt_async Constructor. + + Parameters + ---------- + shape: list[list[int]] + network_w: int, network input width + network_h: int, network input height + max_queue_size: int, default 20 + use_multiclass_nms: bool, whether to use multi-class NMS, default True + """ + pass + + def reset_anchors(self, anchors_new: list[list[list[int]]]): + """ Reset Anchors + + Parameters + ---------- + anchors_new: list[list[list[int]]] + + Returns + ------- + return 0 for success and other for failure + """ + pass + + def get_result_npy(self) -> tuple[tuple[int, int, int, int, int, float],int, int]: + """ Get the PostProcess result + + Returns + ------- + tuple[tuple[left, top, right, bottom, class_id, score],channel_idx, image_idx] + + """ + pass + + + def push_data( self, + channel_idx : list[int], + image_idx : list[int], + input_data : list[TensorPTRWithName], + dete_threshold : list[float], + nms_threshold : list[float], + ost_w : list[int], + ost_h : list[int], + padding_attr : list[list[int]]) -> int: + """ algo_yolov5_post_cpu_opt_async push data. + + Parameters + ---------- + + channel_idx : Channel index number of the images. + image_idx : Image index number of the images. + input_data : Input Data + dete_threshold : Detection thresholds + nms_threshold : NMS thresholds + ost_w : Original images width + ost_h : Original images height + padding_attr : Padding Attribute[start_x, start_y, width, height] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov5_post_cpu_opt: + + def __init__(self, shapes: list[list[int]], network_w:int = 640, network_h:int = 640): + + """ algo_yolov5_post_cpu_opt Constructor. + + Parameters + ---------- + shapes: list[list[int]],Input Data shape + network_w: int, Network input width + network_h: int, Network input height + """ + pass + + + def process(self,input_data:list[TensorPTRWithName], ost_w: list[int], ost_h: list[int], dete_threshold: list[float], nms_threshold: list[float], input_keep_aspect_ratio: bool, input_use_multiclass_nms: bool) -> list[list[tuple[int, int, int, int, int, float]]]: + """ Process + + Parameters + ---------- + input_data: list[TensorPTRWithName], Input Data + ost_w: list[int], Original image width + ost_h: list[int], Original image height + dete_threshold: list[float], Detection threshold + nms_threshold: list[float], NMS threshold + input_keep_aspect_ratio: bool, Input keeping aspect ratio + input_use_multiclass_nms: bool, Input with multiclass + + Returns + ------- + list[list[tuple[left, top, right, bottom, class_id, score]]] + + """ + pass + + def process(self,input:dict[str, Tensor], ost_w: list[int], ost_h: list[int], dete_threshold: list[float], nms_threshold: list[float], input_keep_aspect_ratio: bool, input_use_multiclass_nms: bool) -> list[list[tuple[int, int, int, int, int, float]]]: + """ Process + + Parameters + ---------- + input: dict[str, Tensor], Input Data + ost_w: list[int], Original image width + ost_h: list[int], Original image height + dete_threshold: list[float], Detection threshold + nms_threshold: list[float], NMS threshold + input_keep_aspect_ratio: bool, Input keeping aspect ratio + input_use_multiclass_nms: bool, Input with multiclass + + Returns + ------- + list[list[tuple[left, top, right, bottom, class_id, score]]] + + """ + pass + + def reset_anchors(self, anchors_new: list[list[list[int]]]): + + """ Reset Anchors + + Parameters + ---------- + anchors_new: list[list[list[int]]] + + Returns + ------- + return 0 for success and other for failure + """ + pass + +class algo_yolov8_seg_post_tpu_opt: + + def __init__(self, bmodel_file: str, dev_id: int, detection_shape: list[int], segmentation_shape: list[int], network_h: int, network_w: int): + + """ algo_yolov8_seg_post_tpu_opt Constructor. + + Parameters + ---------- + bmodel_file: str, The TPU getmask bmodel path + dev_id: int, device id + detection_shape: list[int], The shapes of detection head + segmentation_shape: list[int], The shapes of segmentation head, that is Prototype Mask + network_h: int, The input height of yolov8 network + network_w: int, The input width of yolov8 network + """ + pass + + def process(self, detection_input: TensorPTRWithName, segmentation_input: TensorPTRWithName, ost_h: int, ost_w: int, dete_threshold: float, nms_threshold: float, input_keep_aspect_ratio: bool, input_use_multiclass_nms: bool) -> list[tuple[int, int, int, int, float, int, list[float], numpy.ndarray]]: + """ Process + + Parameters + ---------- + detection_input: TensorPTRWithName, The input data of detection head + segmentation_input: TensorPTRWithName, The input data of segmentation head, that is Prototype Mask + ost_h: int, Original image height + ost_w: int, Original image width + dete_threshold: float, Detection threshold + nms_threshold: float, NMS threshold + input_keep_aspect_ratio: bool, Input keeping aspect ratio + input_use_multiclass_nms: bool, Input with multiclass + + Returns + ------- + list[tuple[left, top, right, bottom, score, class_id, contour, mask]] + + """ + pass + + def process(self, detection_input: dict[str, Tensor], segmentation_input: dict[str, Tensor], ost_h: int, ost_w: int, dete_threshold: float, nms_threshold: float, input_keep_aspect_ratio: bool, input_use_multiclass_nms: bool) -> list[tuple[int, int, int, int, float, int, list[float], numpy.ndarray]]: + """ Process + + Parameters + ---------- + detection_input: dict[str, Tensor], The input data of detection head + segmentation_input: dict[str, Tensor], The input data of segmentation head, that is Prototype Mask + ost_h: int, Original image height + ost_w: int, Original image width + dete_threshold: float, Detection threshold + nms_threshold: float, NMS threshold + input_keep_aspect_ratio: bool, Input keeping aspect ratio + input_use_multiclass_nms: bool, Input with multiclass + + Returns + ------- + list[tuple[left, top, right, bottom, score, class_id, contour, mask]] + + """ + pass + +class deepsort_tracker_controller_async: + def __init__(self, max_cosine_distance:float, nn_budget:int, k_feature_dim:int, max_iou_distance:float=0.7, max_age:int=30, n_init:int=3, queue_size:int=10): + + """asynchronous deepsort Constructor + + Parameters + ---------- + max_cosine_distance:float, + nn_budget:int, + k_feature_dim:int, + max_iou_distance:float=0.7, + max_age:int=30, + n_init:int=3, + queue_size:int=10 + """ + + def push_data(self, detected_objects:list[tuple[int, int, int, int, int, float]], feature:Tensor) -> int: + """ Asynchronous processing interface. Use with get_result_npy()! + Track the objects based on the detected objects and their features + + Parameters + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)) + feature: sail.Tensor, the features of the detected objects + + Returns + ------- + int:Returns 0 on success and others on failure. + """ + + def push_data(self, detected_objects:list[tuple[int, int, int, int, int, float]], feature:list[numpy.array]) -> int: + """ Asynchronous processing interface. Use with get_result_npy()! + Track the objects based on the detected objects and their features + + Parameters + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)) + feature: list[numpy.array], the features of the detected objects + + Returns + ------- + int:Returns 0 on success and others on failure. + """ + + def get_result_npy(self) -> list[tuple[int, int, int, int, int, float, int]]: + """ Asynchronous processing interface. Use with push_data()! + Track the objects based on the detected objects and their features + + Returns + ------- + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)) + """ + def set_processing_timer(flag: bool): + """ set the flag whether printing time cost of each processing + + Parameters + ---------- + flag: bool, if True, print the time cost in each processing + if False, nothing happens + + """ + +class sort_tracker_controller_async: + def __init__(self, max_iou_distance:float=0.7, max_age:int=30, n_init:int=3, input_queue_size:int=10, result_queue_size:int=10): + + """asynchronous sort Constructor + + Parameters + ---------- + max_iou_distance:float=0.7, + max_age:int=30, + n_init:int=3, + input_queue_size:int=10, + result_queue_size:int=10 + """ + + def push_data(self, detected_objects:list[tuple[int, int, int, int, int, float]]) -> int: + """ Asynchronous processing interface. Use with get_result_npy()! + Track the objects based on the detected objects and their features + + Parameters + ---------- + detected_objects: list(tuple(left, top, right, bottom, class_id, score)) + + Returns + ------- + int:Returns 0 on success and others on failure. + """ + + def get_result_npy(self) -> list[tuple[int, int, int, int, int, float, int]]: + """ Asynchronous processing interface. Use with push_data()! + Track the objects based on the detected objects and their features + + Returns + ------- + tracked_objects: list(tuple(left, top, right, bottom, class_id, score, track_id)) + """ + + +class Perf: + def __init__(self, bmodel_path:str, tpu_id:list[int], max_que_size:int, mode:IOMode=IOMode.SYSO, thread_count:int=2, free_input:bool=False): + + """Perf Constructor + + Parameters + ---------- + bmodel_path:float, Path to bmodel.\n + tpu_id:list[int], ID of TPUs, there may be more than one TPU for PCIE mode.\n + max_que_size:int, max queue size.\n + mode:IOMode, Specify the input/output tensors are in system memory or device memory, default SYSO.\n + thread_count:int, thread counts with each tpu.\n + free_input:bool, release memory of input, default false.\n + """ + + def PushTensor(self, tensor_index:int, input_tensors:list[TensorPTRWithName]) -> int: + """ Push Tensors + + Parameters + ---------- + tensor_index: int, index number of the Tensors. + input_tensors: list[TensorPTRWithName], Input tensors with name + + Returns + ------- + int:Returns 0 on success and others on failure. + """ + + def SetEnd(self) -> int: + """ Stop Push Tensors + + Returns + ------- + int:Returns 0 on success and others on failure. + """ + + def GetResult(self) -> tuple[int, list[TensorPTRWithName]]: + """ Get the Result Data object + + Returns + ------- + tensor_index: int, Original input data index + output_data: list(TensorPTRWithName), Output result + """ + + def get_input_dtype(self, graph_name: str, tensor_name: str) -> Dtype: + """Get data type of an input tensor""" + pass + + def get_input_scale(self, graph_name: str, tensor_name: str) -> float: + """Get scale of an input tensor""" + pass + + def get_input_shape(self, graph_name: str, tensor_name: str) -> list[int]: + """Get the shape of an input tensor in a graph """ + pass + + def get_output_names(self, graph_name: str) -> list[str]: + """Get all output tensor names of the specified graph """ + pass + + def get_input_names(self, graph_name: str) -> list[str]: + """Get all input tensor names of the specified graph """ + pass + + def get_graph_names(self) -> list[str]: + """Get all graph names in the loaded bomodels """ + pass + +class DecoderImages: + def __init__(self, image_list:list[str], tpu_id:int, queue_size:int): + """ DecoderImages Constructor + + Parameters + ----------- + image_list:list[str], image name list\n + tpu_id:int,TPU ID. You can use bm-smi to see available IDs.\n + queue_size:int, max queue size\n + """ + pass + + def setResizeAttr(self, width:int, height:int, resize_alg:bmcv_resize_algorithm = bmcv_resize_algorithm.BMCV_INTER_LINEAR) -> int: + """ Set the Resize Attr object + Parameters + ----------- + width:int,output width\n + height:int,output height\n + resize_alg:bmcv_resize_algorithm, Resize algorithm, defalut BMCV_INTER_LINEAR + + Returns + ----------- + int:Returns 0 on success, other for failed. + """ + pass + + def start(self) -> int: + """ Start read images + + Returns + ----------- + int:Returns 0 on success, other for failed. + """ + pass + + + def read(self, image: BMImage) -> int: + """ read + + Parameters + ----------- + image: Output BMImage. + + Returns + ------- + int:Returns 0 on success, 1 for queue empty, -1 for end or thread stoped. + """ + pass + + def stop(self) -> None: + """ stop + """ + pass + + def get_schedule(self) -> int: + """ Get the schedule object + + Returns + --------- + The number of decoded images. + """ + pass + + diff --git a/uv.lock b/uv.lock index e518e53..2e6ac6b 100644 --- a/uv.lock +++ b/uv.lock @@ -16,6 +16,15 @@ wheels = [ { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ed/66/388cee1df022233ef157347a7275f0e80cf297bfb344e7680001e5ae2acd/dfss-1.10.4-py2.py3-none-any.whl", hash = "sha256:37bf171350dac531c7185ea5789a6d4b0e63a7cc1852c909cd333e6a2efb0ef5", size = 8556566, upload-time = "2025-07-29T03:11:34.678Z" }, ] +[[package]] +name = "module-bank" +version = "0.1.1" +source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } +sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/73/52/1aeb99df074e827dce1337a9cf89d97ee88b636b1fe5d2db3366acf86dc3/module_bank-0.1.1.tar.gz", hash = "sha256:a168e600166d51bf38a3ee26247a878d65c16ed44109a919cc61ecfa4fe8b79e", size = 58296, upload-time = "2026-01-31T06:37:08.99Z" } +wheels = [ + { url = "https://pypi.tuna.tsinghua.edu.cn/packages/3e/ef/7bc3912ae9c8489b147e0392bc284ec66a0fb79974b76ff65145cf235ada/module_bank-0.1.1-py3-none-any.whl", hash = "sha256:dc4312b93f6c1cbecaf5e3b96d56f2af26326ebeb31bf148007556043846a106", size = 10867, upload-time = "2026-01-31T06:37:06.497Z" }, +] + [[package]] name = "numpy" version = "1.24.4" @@ -219,14 +228,16 @@ wheels = [ ] [[package]] -name = "sophon-ai-project" +name = "sophon-chakcy" version = "0.1.0" -source = { virtual = "." } +source = { editable = "." } dependencies = [ + { name = "module-bank" }, { name = "numpy", version = "1.24.4", source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }, marker = "python_full_version < '3.9'" }, { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }, marker = "python_full_version >= '3.10'" }, { name = "opencv-python-headless" }, + { name = "sqlite-vfs" }, ] [package.dev-dependencies] @@ -238,8 +249,10 @@ dev = [ [package.metadata] requires-dist = [ + { name = "module-bank", specifier = ">=0.1.1" }, { name = "numpy", specifier = ">=1.24.4" }, { name = "opencv-python-headless", specifier = ">=4.12.0.88" }, + { name = "sqlite-vfs", specifier = ">=0.1.0" }, ] [package.metadata.requires-dev] @@ -247,3 +260,12 @@ dev = [ { name = "dfss", specifier = ">=1.10.4" }, { name = "pip", specifier = ">=25.0.1" }, ] + +[[package]] +name = "sqlite-vfs" +version = "0.1.0" +source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } +sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/70/ff/9cbb7f704d59f88ae048bb84a3de19b5d6dd0c1ae21af53396723af18d14/sqlite_vfs-0.1.0.tar.gz", hash = "sha256:cd6cf5cb7d60c1983d9befdc6c4cce8ab050fc4fd215e5e63ece1d2d28f4f9bb", size = 57435, upload-time = "2025-11-08T08:16:01.715Z" } +wheels = [ + { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ef/26/a3f51ea9d10efe2c4f85cac78dcbd898b437d2331cf25d470f804e4498b7/sqlite_vfs-0.1.0-py3-none-any.whl", hash = "sha256:c6e27a35e504bb6360fb0d9083d79572367a903788b3b14aea5f1188130e9314", size = 10768, upload-time = "2025-11-08T08:15:18.588Z" }, +]