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);}
相关文章:
DepthAnything(2): 基于ONNXRuntime在ARM(aarch64)平台部署DepthAnything
DepthAnything(1): 先跑一跑Depth Anything_depth anything离线怎么跑-CSDN博客 目录 1. 写在前面 2. 安装推理组件 3. 生成ONNX 4. 准备ONNXRuntime库 5. API介绍 6. 例程 1. 写在前面 DepthAnything是一种能在任何情况下处理任何图像的简单却又强大的深度估计模型。 …...
JAVA简单封装UserUtil
目录 思路 一、TokenFilterConfiguration 二、FilterConfig 三、TokenContextHolder 四、TokenUtil 五、UserUtil 思路 配置Token过滤器(TokenFilterConfiguration):实现一个Token过滤器配置,用于拦截HTTP请求,从请求头中提取Token&…...
【TOOLS】Chrome扩展开发
Chrome Extension Development 1. 入门教程 入门案例,可以访问【 谷歌插件官网官方文档 】查看官方入门教程,这里主要讲解大概步骤 Chrome Extenson 没有固定的脚手架,所以项目的搭建需要根据开发者自己根据需求搭建项目(例如通过…...
分享WPF的UI开源库
文章目录 前言一、HandyControl二、AduSkin三、Adonis UI四、Panuon.WPF.UI五、LayUI-WPF六、MahApps.Metro七、MaterialDesignInXamlToolkit八、FluentWPF九、DMSkin总结 前言 分享WPF的UI开源库。 一、HandyControl HandyControl是一套WPF控件库,它几乎重写了所…...
[ACM独立出版]2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024)
最新消息ICVISP 2024-已通过ACM出版申请投稿免费参会,口头汇报或海报展示(可获得相应证明证书) ————————————————————————————————————————— [ACM独立出版]2024年虚拟现实、图像和信号处理国际学术会议(ICVI…...
JVM:类加载器
文章目录 一、什么是类加载器二、类加载器的应用场景三、类加载器的分类1、分类2、启动类加载器3、Java中的默认类加载器(1)扩展类加载器(2)应用程序类加载器(3)arthas中类加载器相关的功能 四、双亲委派机…...
支持向量机 (support vector machine,SVM)
支持向量机 (support vector machine,SVM) flyfish 支持向量机是一种用于分类和回归的机器学习模型。在分类任务中,SVM试图找到一个最佳的分隔超平面,使得不同类别的数据点在空间中被尽可能宽的间隔分开。 超平面方…...
宝塔面板以www用户运行composer
方式一 执行命令时指定www用户 sudo -u www composer update方式二 在网站配置中的composer选项卡中选择配置运行...
昇思25天打卡营-mindspore-ML- Day24-基于 MindSpore 实现 BERT 对话情绪识别
学习笔记:基于MindSpore实现BERT对话情绪识别 算法原理 BERT(Bidirectional Encoder Representations from Transformers)是由Google于2018年开发的一种预训练语言表示模型。BERT的核心原理是通过在大量文本上预训练深度双向表示࿰…...
【精品资料】模块化数据中心解决方案(33页PPT)
引言:模块化数据中心解决方案是一种创新的数据中心设计和部署策略,旨在提高数据中心的灵活性、可扩展性和效率。这种方案通过将数据中心的基础设施、计算、存储和网络资源封装到标准化的模块中,实现了快速部署、易于管理和高效运维的目标 方案…...
N6 word2vec文本分类
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊# 前言 前言 上周学习了训练word2vec模型,这周进行相关实战 1. 导入所需库和设备配置 import torch import torch.nn as nn import torchvision …...
excel、word、ppt 下载安装步骤整理
请按照我的步骤开始操作,注意以下截图红框标记处(往往都是需要点击的地方) 第一步:下载 首先进入office下载网址: otp.landian.vip 然后点击下载 拉到下方 下载站点(这里根据自己的需要选择下载&#x…...
【python学习】标准库之日期和时间库定义、功能、使用场景和示例
引言 datetime模块最初是由 Alex Martelli 在 Python 2.3 版本引入的,目的是为了解决之前版本中处理日期和时间时存在的限制和不便 在datetime模块出现之前,Python 主要使用time模块来处理时间相关的功能,但 time模块主要基于 Unix 纪元时间&…...
Android --- Kotlin学习之路:基础语法学习笔记
------>可读可写变量 var name: String "Hello World";------>只读变量 val name: String "Hello World"------>类型推断 val name: String "Hello World" 可以写成 val name "Hello World"------>基本数据类型 1…...
嵌入式智能手表项目实现分享
简介 这是一个基于STM32F411CUE6和FreeRTOS和LVGL的低成本的超多功能的STM32智能手表~ 推荐 如果觉得这个手表的硬件难做,又想学习相关的东西,可以试下这个新出的开发板,功能和例程demo更多!FriPi炸鸡派STM32F411开发板: 【STM32开发板】 FryPi炸鸡派 - 嘉立创EDA开源硬件平…...
`nmap`模块是一个用于与Nmap安全扫描器交互的库
在Python中,nmap模块是一个用于与Nmap安全扫描器交互的库。Nmap(Network Mapper)是一个开源工具,用于发现网络上的设备和服务。虽然Python的nmap模块可能不是官方的Nmap库(因为Nmap本身是用C/C编写的)&…...
JVM系列 | 对象的创建与存储
JVM系列 | 对象的生命周期1 对象的创建与存储 文章目录 前言对象的创建过程内存空间的分配方式方式1 | 指针碰撞方式2 | 空闲列表 线程安全问题 | 避免空间冲突的方式方式1 | 同步处理(加锁)方式2 | 本地线程分配缓存 对象的内存布局Part1 | 对象头Mark Word类型指针…...
【JavaScript 算法】快速排序:高效的排序算法
🔥 个人主页:空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 快速排序(Quick Sort)是一种高效的排序算法,通过分治法将数组分为较小的子数组,递归地排序子数组。快速排序通常…...
Excel如何才能忽略隐藏行进行复制粘贴?
你有没有遇到这样的情况:数据很多,将一些数据隐藏后,进行复制粘贴,结果发现粘贴后的内容仍然将整个数据都显示出来了!那么,Excel如何才能忽略隐藏行进行复制粘贴? 打开你的Excel表格 Excel如何…...
行人越界检测 越线 越界区域 多边形IOU越界判断
行人越界判断 越界判断方式:(1)bbox中心点越界(或自定义)(2)交并比IoU判断 越界类型:(1)越线 (2)越界区域 1.越线判断 bbox中心点xc、…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
用 FFmpeg 实现 RTMP 推流直播
RTMP(Real-Time Messaging Protocol) 是直播行业中常用的传输协议。 一般来说,直播服务商会给你: ✅ 一个 RTMP 推流地址(你推视频上去) ✅ 一个 HLS 或 FLV 拉流地址(观众观看用)…...
C#最佳实践:为何优先使用as或is而非强制转换
C#最佳实践:为何优先使用as或is而非强制转换 在 C# 的编程世界里,类型转换是我们经常会遇到的操作。就像在现实生活中,我们可能需要把不同形状的物品重新整理归类一样,在代码里,我们也常常需要将一个数据类型转换为另…...
Ray框架:分布式AI训练与调参实践
Ray框架:分布式AI训练与调参实践 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 Ray框架:分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …...
20250609在荣品的PRO-RK3566开发板的Android13下解决串口可以执行命令但是脚本执行命令异常的问题
20250609在荣品的PRO-RK3566开发板的Android13下解决串口可以执行命令但是脚本执行命令异常的问题 2025/6/9 20:54 缘起,为了跨网段推流,千辛万苦配置好了网络参数。 但是命令iptables -t filter -F tetherctrl_FORWARD可以在调试串口/DEBUG口正确执行。…...
