DepthAnything(2): 基于ONNXRuntime在ARM(aarch64)平台部署DepthAnything

DepthAnything(1): 先跑一跑Depth Anything_depth anything离线怎么跑-CSDN博客
 


目录

1. 写在前面

2. 安装推理组件

3. 生成ONNX

4. 准备ONNXRuntime库

5. API介绍

6. 例程


1. 写在前面

        DepthAnything是一种能在任何情况下处理任何图像的简单却又强大的深度估计模型。

2. 安装推理组件

        针对有GPU加持的场景,以NVIDIA显卡为例,首先需要安装GPU驱动。

        然后再安装CUDA、cuDNN和ONNX Runtime,一般情况下,在有显卡的系统中,我们选择GPU版本。

        进入如下链接,可以查看CUDA、cuDNN、ONNX Runtime库的版本对应关系。

        NVIDIA - CUDA | onnxruntime

        如下所示,ONNX Runtime与CUDA、cuDNN的版本需要匹配,否则可能出现我发调用GPU进行推理。

        针对没有GPU的场景,我们使用CPU进行推理。可直接下载相应平台的onnx-runtime库。

3. 生成ONNX

        使用DepthAnything训练工程下的export_onnx.py文件导出ONNX模型。

        注意,导出的时候,需要注意分辨率,DepthAnything到处分辨率必须是14的整数倍。

        另外,如果导出分辨率过小,可能会导致识别的深度图失效,因此一般建议导出时,分辨率选择518*518。

        导出onnx模型参考代码如下。

import argparseimport torchfrom onnx import load_model, save_modelfrom onnxruntime.tools.symbolic_shape_infer import SymbolicShapeInferencefrom depth_anything.dpt import DPT_DINOv2def parse_args() -> argparse.Namespace:parser = argparse.ArgumentParser()parser.add_argument("--model",type=str,choices=["s", "b", "l"],required=True,help="Model size variant. Available options: 's', 'b', 'l'.",)parser.add_argument("--output",type=str,default=None,required=False,help="Path to save the ONNX model.",)return parser.parse_args()def export_onnx(model: str, input: str, output: str = None):# Handle argsif output is None:output = f"weights/depth_anything_vit{model}14_ori.onnx"# Device for tracing (use whichever has enough free memory)device = torch.device("cpu")# Sample image for tracing (dimensions don't matter)image = torch.rand(1, 3, 518, 518).to(device) # [SAI-KEY] 必须是14的倍数# Load model paramsif model == "s":depth_anything = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384])elif model == "b":depth_anything = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768])else:  # model == "l"depth_anything = DPT_DINOv2(encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024])weights = torch.load(input)depth_anything.to(device).load_state_dict(weights)depth_anything.eval()torch.onnx.export(depth_anything,image,output,input_names=["image"], # 列表,如果有多个输入,应按照顺序,依次output_names=["depth"],opset_version=12,)save_model(SymbolicShapeInference.infer_shapes(load_model(output), auto_merge=True),output,)if __name__ == "__main__":export_onnx("l", "/2T/001_AI/8001_DepthAnything/003_Models/checkpoints/depth_anything_vitl14.pth", "/2T/001_AI/8001_DepthAnything/003_Models/checkpoints/depth_anything_vitl14.onnx")

4. 准备ONNXRuntime库

        登录链接https://github.com/microsoft/onnxruntime/releases下载相应的ONNX Runtime推理库。如下所示,可选择linux、windows、osx系统下的库,以及选择x86或aarch64架构的库。需要说明的是,aarch64目前仅支持CPU版本。

        不同系统的库,引入方式也不同。

        例如,下载onnxruntime-linux-aarch64-1.18.1.tgz库,解压后可以将其中lib文件夹下的libonnxruntime.so和libonnxruntime.so.1.18.1复制到/usr/lib路径下。

        include头文件可移动可不移动,也可重命名后,加入到工程中。如果需要添加到工程中,需要注意Makefile中的包含项。

        如果是下载的windows平台的库,一般是include文件和dll链接库,按照不同IDE的引入方式来就可以。

5. API介绍

        本小节简单介绍几个API,具体使用可以参照后续小节的例程加以探索和理解。

(1)Ort::Env(ORT_LOGGING_LEVEL_WARNING, "depthAnything_mono");

        ORT_LOGGING_LEVEL_VERBOSE:最详细的日志信息,包括所有信息。

        ORT_LOGGING_LEVEL_INFO:一般的信息,例如模型加载和推理进度。

        ORT_LOGGING_LEVEL_WARNING:警告级别的日志,例如潜在的问题或性能下降,仅输出警告日志。

        ORT_LOGGING_LEVEL_ERROR:错误级别的日志,例如无法恢复的错误。

        ORT_LOGGING_LEVEL_FATAL:致命错误,通常是程序无法继续执行的错误。

(2)OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0); ///< 相当于指定执行后端,如果不指定,则默认使用CPU

        参数1:

        参数2:设备号

(3)GetInputCount()和GetOutputCount()

        获得输入和输出的数量。

(4)GetInputTypeInfo(i)

        获取第i个输入的信息。

(5)GetShape()

        获取输入或输出的shape信息。

6. 例程

        以下例程以DepthAnything利用ONNXRuntime与OpenCV实现对一张图片的深度估计、并将结果存储到本地。

#include <assert.h>#include <vector>#include <ctime>#include <iostream>#include <chrono>#include <onnxruntime_cxx_api.h>#include <opencv2/core.hpp>#include <opencv2/imgproc.hpp>#include <opencv2/highgui.hpp>#include <opencv2/videoio.hpp>using namespace cv;using namespace std;int input_width = 518;int input_height = 518;class DepthAnything{public:DepthAnything(std::string onnx_model_path);std::vector<float> predict(std::vector<float>& input_data, int batch_size = 1, int index = 0);cv::Mat predict(cv::Mat& input_tensor, int batch_size = 1, int index = 0);private:Ort::Env env;Ort::Session session;Ort::AllocatorWithDefaultOptions allocator;std::vector<const char*>input_node_names = {"image"}; ///< 生成onnx时的输入节点名std::vector<const char*>output_node_names = {"depth"}; ///< 生成onnx时的输出节点名std::vector<int64_t> input_node_dims;std::vector<int64_t> output_node_dims;};DepthAnything::DepthAnything(std::string onnx_model_path) :session(nullptr), env(nullptr){/** 初始化ORT环境. */this->env = Ort::Env(ORT_LOGGING_LEVEL_WARNING, "DepthAnything_ORT");/** 初始化ORT会话选项. */Ort::SessionOptions session_options;// session_options.SetInterOpNumThreads(1);session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_BASIC); ///< ORT_ENABLE_ALL/** 初始化ORT会话. */this->session = Ort::Session(env, onnx_model_path.data(), session_options);/** 输入输出节点数量. */size_t num_input_nodes = session.GetInputCount();size_t num_output_nodes = session.GetOutputCount();for (int i = 0; i < num_input_nodes; i++){Ort::TypeInfo type_info = session.GetInputTypeInfo(i);auto tensor_info = type_info.GetTensorTypeAndShapeInfo();ONNXTensorElementDataType type = tensor_info.GetElementType();this->input_node_dims = tensor_info.GetShape();for(int i=0; i<this->input_node_dims.size(); i++){printf("shape[%d]: %d\n", i, this->input_node_dims[i]);}}for (int i = 0; i < num_output_nodes; i++){Ort::TypeInfo type_info = session.GetOutputTypeInfo(i);auto tensor_info = type_info.GetTensorTypeAndShapeInfo();ONNXTensorElementDataType type = tensor_info.GetElementType();this->output_node_dims = tensor_info.GetShape();}}std::vector<float> DepthAnything::predict(std::vector<float>& input_tensor_values, int batch_size, int index){this->input_node_dims[0] = batch_size;this->output_node_dims[0] = batch_size;float* floatarr = nullptr;std::vector<const char*>output_node_names;if (index != -1){output_node_names = { this->output_node_names[index] };}else{output_node_names = this->output_node_names;}this->input_node_dims[0] = batch_size;auto input_tensor_size = input_tensor_values.size();/** 创建Tensor对象. */auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); ///< 创建CPU内存信息Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_size, input_node_dims.data(), 4); ///< 创建输入张量/** 执行推理. */auto output_tensors = session.Run(Ort::RunOptions{ nullptr }, input_node_names.data(), &input_tensor, 1, output_node_names.data(), 1);assert(output_tensors.size() == 1 && output_tensors.front().IsTensor());floatarr = output_tensors[0].GetTensorMutableData<float>(); ///< 获取输出张量int64_t output_tensor_size = 1;for (auto& it : this->output_node_dims){output_tensor_size *= it;}std::vector<float>results(output_tensor_size);for (unsigned i = 0; i < output_tensor_size; i++){results[i] = floatarr[i];}return results;}cv::Mat DepthAnything::predict(cv::Mat& input_tensor, int batch_size, int index){int input_tensor_size = input_tensor.cols * input_tensor.rows * 3;std::size_t counter = 0;std::vector<float>input_data(input_tensor_size);std::vector<float>output_data;/** 转换RGB Planar, 归一化. */for (unsigned k = 0; k < 3; k++){for (unsigned i = 0; i < input_tensor.rows; i++){for (unsigned j = 0; j < input_tensor.cols; j++){input_data[counter++] = static_cast<float>(input_tensor.at<cv::Vec3b>(i, j)[k]) / 255.0;}}}/** 推理. */output_data = this->predict(input_data);/** 后处理. */cv::Mat output_tensor(output_data);output_tensor =output_tensor.reshape(1, {input_width, input_height});double minVal, maxVal;cv::minMaxLoc(output_tensor, &minVal, &maxVal); ///< 获取最大值、最小值.output_tensor.convertTo(output_tensor, CV_32F); ///< 转换数据类型,float32类型.if (minVal != maxVal) {output_tensor = (output_tensor - minVal) / (maxVal - minVal);}output_tensor *= 255.0;output_tensor.convertTo(output_tensor, CV_8UC1); ///< 转单通道(灰度图).cv::applyColorMap(output_tensor, output_tensor, cv::COLORMAP_HOT); ///< 伪彩映射.return output_tensor;}std::chrono::time_point<std::chrono::high_resolution_clock> tic;std::chrono::time_point<std::chrono::high_resolution_clock> toc;std::chrono::milliseconds elapsed;int main(int argc, char* argv[]){std::string model_path = "/zqpe/8001_DepthAnything_OnnxRuntime/out/bin/depth_anything_vits14.onnx";std::string image_path = "/zqpe/8001_DepthAnything_OnnxRuntime/out/bin/204995.jpg";printf("Construct depth anything inference engine.\n");tic = std::chrono::high_resolution_clock::now();DepthAnything model(model_path);toc = std::chrono::high_resolution_clock::now();elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic);printf("Construct depth anything inference engine, takes %ld ms\n", elapsed.count());printf("Prepare sample.\n");tic = std::chrono::high_resolution_clock::now();cv::Mat image = cv::imread(image_path);auto ori_h = image.cols;auto ori_w = image.rows;// cv::imshow("image", image);cv::cvtColor(image, image, cv::COLOR_BGR2RGB);cv::resize(image, image, {input_width, input_height}, 0.0, 0.0, cv::INTER_CUBIC);toc = std::chrono::high_resolution_clock::now();elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic);printf("Prepare sample, takes %ld ms\n", elapsed.count());cv::Mat result;// while(1){printf("Do inference.\n");tic = std::chrono::high_resolution_clock::now();result = model.predict(image);toc = std::chrono::high_resolution_clock::now();elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic);printf("Do inference, takes %ld ms\n", elapsed.count());// }cv::resize(result, result, {ori_h, ori_w}, 0.0, 0.0, cv::INTER_CUBIC);printf("Save result.\n");int pos = image_path.rfind(".");image_path.insert(pos, "_depth");cv::imwrite(image_path, result);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/46396.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud微服务开发框架

Spring Cloud是基于Spring Boot的微服务开发框架&#xff0c;为构建分布式系统和微服务架构提供了一系列的工具和解决方案。它包含了很多组件&#xff0c;每个组件都有特定的功能&#xff0c;可以解决微服务架构中常见的问题。下面是对Spring Cloud的一些主要组件和功能的详细介…

KingbaseES数据库逻辑备份还原

数据库版本&#xff1a;KingbaseES V008R006C008B0014 简介 介绍2个KingbaseES用于备份还原的工具&#xff1a; sys_dump&#xff1a;逻辑备份sys_restore&#xff1a;逻辑还原 sys_dump 是 KingbaseES 用于逻辑备份的工具&#xff0c;可以将数据备份为不同类型的文件。支持数据…

ARM功耗管理标准接口之SCMI

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理有哪些标准接口&#xff1f;ACPI&PSCI&SCMI&#xff1f; Advanced Configuration and Power Interface Power State Coordination Interface System Control and Management Interface 下图示例说明了实现…

docker部署canal 并监听mysql

1.部署mysql 需要开启mysql的binlong&#xff0c;和创建好用户等 可以参考这个 Docker部署Mysql数据库详解-CSDN博客 2.部署canal 参考这一篇&#xff1a; docker安装Canal&#xff0c;开启MySQL binlog &#xff0c;连接Java&#xff0c;监控MySQL变化_docker canal-CSD…

内网信息收集——MSF信息收集浏览器记录配置文件敏感信息

文章目录 一、配置文件敏感信息收集二、浏览器密码&记录三、MSF信息收集 域控&#xff1a;windows server 2008 域内机器&#xff1a;win7 攻击机&#xff1a;kali 就是红日靶场&#xff08;一&#xff09;的虚拟机。 一、配置文件敏感信息收集 使用searchall64.exe&#…

个人对于“链接”的理解

一、概念&#xff1a; 链接是将各种代码和数据片段收集并组合成为一个单一文件的过程&#xff0c;这个文件可被加载&#xff08;复制&#xff09;到内存并执行。在现代操作系统中&#xff0c;链接是由叫做链接器的程序自动执行的。 链接器在软件开发中扮演着重要的角色&#…

【错题集-编程题】四个选项(DFS + 剪枝 + 哈希表)

牛客对应题目链接&#xff1a;四个选项 (nowcoder.com) 一、分析题目 用递归枚举出所有的情况&#xff0c;注意剪枝&#xff1a; 填写某个数时&#xff0c;要看看还有没有剩余次数。填写某个数时&#xff0c;要看看符不符合若干题的选项必须相同。 二、代码 // 值得学习的代码…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(六)-人工智能控制的自主无人机用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

SparkStreaming--scala

文章目录 第1关&#xff1a;QueueStream代码 第2关&#xff1a;File Streams代码 第1关&#xff1a;QueueStream 任务描述 本关任务&#xff1a;编写一个清洗QueueStream数据的SparkStreaming程序。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.如何使用S…

OrangePi AI Pro 实测:感受 AI 应用的独特魅力与强大性能

OrangePi AiPro介绍和初始化配置 小寒有话说一、OrangePi AiPro介绍1. 主板详情2. 开发配置3. 镜像烧录4. 设备连接5. WiFi连接6. NVMe SSD的安装和挂载7. 更新下载源并下载必要的软件8. 扩展内存 二、Jupyter Lab AI测评应用案例1. 获取Jupyter Lab 网址链接2. 图像提取文字3.…

帕金森病患者应该如何进行日常锻炼以提高生活质量?

帕金森病患者的日常锻炼建议 帕金森病患者进行日常锻炼对于改善症状、维持肌肉功能和延缓疾病进展至关重要。以下是一些具体的锻炼建议&#xff1a; 选择适合的运动类型&#xff1a;帕金森病患者应选择低冲击、有氧的活动&#xff0c;如散步、骑自行车、游泳和太极拳等。这些运…

【qt】考试系统项目

话不多说,先一睹芳颜 咱们的账号,题库和答案都是通过文件获取的. 话不多说,直接开干 目录 一.登录窗口1.界面设计2.邮箱验证3.登录验证 二.题库窗口1.考试计时2.布局管理器3.题库显示4.按钮布局5.计算分数 三.窗口交互四.完整代码五.结语 一.登录窗口 1.界面设计 这里添加背…

【笔记】先求修改没保存的文本文件-在虚拟机中输入 yum makecache报错

所有者: root 日期: Sat Jul 13 03:10:34 2024 文件名: /etc/yum.repos.d/CentOS-Base.repo 修改过: 是 用户名: root 主机名: linuxlocalhost 进程 ID: 78107 正在打开文件 "CentOS-Base.repo" 日期: Sat Jul 13 03:18:24 2024 比交换文件新&#xff01; (1) Anothe…

从信息化、数字化、智能化到企业大模型应用

新时代背景下&#xff0c;数字经济发展速度之快、辐射范围之广、影响程度之深前所未有&#xff0c;5G、大数据、云计算、人工智能、区块链等技术加速创新&#xff0c;全域融入经济社会、民生服务全过程&#xff0c;成为资源要素重组、经济结构重塑、竞争格局重构的关键力量。千…

jar服务注册为windows的服务

依赖工具&#xff1a;nssm.exe 使用NSSM (Non-Sucking Service Manager) NSSM是一个免费的开源工具&#xff0c;用于将任何应用程序注册为Windows服务。以下是如何使用NSSM将Java应用注册为服务的步骤&#xff1a; 步骤 1: 安装 NSSM 首先&#xff0c;你需要从NSSM的官方网站…

Visual Studio 安装程序无法执行修复或更新

一.问题场景 出现问题的场景&#xff1a;当你的VS已经安装但是无法在工具中下载新组件或者卸载了当时一直无法安装。 二.问题原因 如果计算机上的 Visual Studio 实例已损坏&#xff0c;则可能会出现此问题。 三.解决方法 如果之前尝试修复或更新 Visual Studio 失败&…

【Python】 使用 gne 库提取新闻标题的简易指南

我白天是个 搞笑废物 表演不在乎 夜晚变成 忧伤怪物 撕扯着孤独 我曾经是个 感性动物 小心地感触 现在变成 无关人物 &#x1f3b5; 张碧晨/王赫野《何物》 数据科学和网络爬虫领域&#xff0c;提取网页内容是一项常见任务。然而&#xff0c;不同的网站结…

浅谈RLHF---人类反馈强化学习

浅谈RLHF&#xff08;人类反馈强化学习&#xff09; RLHF&#xff08;Reinforcement Learning fromHuman Feedback&#xff09;人类反馈强化学习 RLHF是[Reinforcement Learning from Human Feedback的缩写&#xff0c;即从人类反馈中进行强化学习。这是一种结合了机器学习中…

Gridea + SFTP +Docker + Nginx 配置博客-CSDN

服务器选择 阿里云 ESC 服务器 比较便宜 99 一年开启密码登录配置你的远程服务域名选择自己的域名&#xff0c;当然我可以解析二级域名给大家不要搞我的服务器Remote Path 远程服务配置 配置自己的一个文件夹我是使用的 /gridea/blog &#xff08;绝对路径&#xff09;阿里云安…

探索AI艺术:简单方法训练你的AI画家(思路)

如何训练一个简单的AI画家模型 1. 确定问题和目标 在开始之前&#xff0c;明确你想要的输出类型和风格。例如&#xff0c;你是否想要生成逼真的风景画&#xff0c;还是抽象艺术作品&#xff1f;这将决定你选择的模型和数据集。 2. 准备数据集 收集和准备用于训练的艺术作品…