C++ 实现ONNX语义分割(TopFormer)

使用C++部署应用onnx模型 在C++下部署onnx模型的示例程序,包含各个API的解释。 阅读详情

TopFormer是一个比较高效的语义分割模型,
在TopFormer ONNX主页上可以找到python的实现。

用一个小猫的图片测试一下
在这里插入图片描述
瑕疵是有一些,不过它的特点是非常快,视频语义分割能达到实时(本地CPU)。
TopFormer模型的输出Size是64x64,这个是resize后的效果。

用cpp实现看看效果。
cpp版的onnxruntime安装这里就不说了,参考链接
还需要安装cpp版的opencv,我选的是4.5,安装参考

然后你的CmakeLists.txt里面要link这两样

target_link_libraries(${PROJECT_NAME}
        ${OpenCV_LIBS}
        ${ONNXRUNTIME_LIB}
        )

来一波include

#include <iostream>
#include <fstream>
#include <array>
#include <string>

#include <opencv4/opencv2/core/mat.hpp>
#include <opencv4/opencv2/imgcodecs.hpp>
#include <opencv4/opencv2/imgproc.hpp>
#include <core/session/experimental_onnxruntime_cxx_api.h>

using namespace std;
using namespace cv;

onnx模型直接用github下下来的就好,
定义几个onnxruntime变量

const string modelFile = "TopFormer-S_512x512_2x8_160k.onnx";
Ort::Env env;
Ort::SessionOptions sessionOptions;
Ort::Session session(nullptr);

try{
     session = Ort::Session(env, modelFile.data(), sessionOptions);
} catch(Ort::Exception& e) {
     cout << e.what() << endl;
     return 1;
}

TopFormer的输入Size是1x3x512x512,输出Size是1x150x64x64,
所以先定义下形状。

constexpr int64_t numChannels = 3;  //constexpr修饰,表示编译期就可以得到常量值去优化
constexpr int64_t width = 512;
constexpr int64_t height = 512;
constexpr int64_t out_width = 64;
constexpr int64_t out_height = 64;
constexpr int64_t numClasses = 150;  //类别数
constexpr int64_t numInputElements = numChannels * height * width;
constexpr int64_t numOutputElements = numClasses * out_height * out_width;

定义输入输出数组,输入输出Tensor,
有人会说,输入本身就是矩阵了,为什么要转成数组。
用array, vector的话会保存指针,就不需要反复create Tensor,只需要把数据copy到数组。

array<float, numInputElements> input;
array<float, numOutputElements> output;

//输入输出需要转成Tensor
//这个Tensor保存的是输入输出数组的pointer,所以不能删除输入输出数组
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
auto inputTensor = Ort::Value::CreateTensor<float>(memory_info, input.data(),
                                                   input.size(), inputShape.data(),
                                                   inputShape.size());
auto outputTensor = Ort::Value::CreateTensor<float>(memory_info, output.data(),output.size(),
                                                    outputShape.data(), outputShape.size());
//也可以不用转成数组,直接用Tensor,但是array,vector会便利一些
//因为图片如果很多,就需要反复create Tensor,用数组的话只需要copy到数组

读入image,预处理(比如-mean, /std),
注意要把image处理成CxHxW的形式

Mat img = imread(imageFile);
const vector<float> imageVec = loadImage(img); //CxHxW: [ch1:HXW][ch2:HxW][ch3:HxW]
//预处理(resize, normalize)放在loadImage函数里面

预处理中mean和std我们用TopFormer python版本中的数据

//-mean, /std
float img_mean[3] = {0.485, 0.456, 0.406};
float img_std[3] = {0.229, 0.224, 0.225};

注意要把image拉成一维数组,顺序是CxHxW

resize(image, image, Size(512, 512));
image = image.reshape(1, 1);  //图像拉成向量
//HWC -> CHW (transpose(2, 0, 1)
for(size_t ch = 0; ch < 3; ++ch) {
    for(size_t i = ch; i < vec.size(); i+= 3) {
        //保存成CxHxW的顺序
    }
}

copy图像数据到input数组

//把图像copy进input数组
copy(imageVec.begin(), imageVec.end(), input.begin());

定义输入输出的name,要和onnx模型的输入输出name一致,
可以直接定义,也可以从onnx模型中获取。

    //输入输出的name,可以自己定义,也可以从onnx模型中获取
    const array<const char*, 1> inputNames = {"input"};
    const array<const char*, 1> outputNames = {"output"};


//    //从onnx模型中获取输入输出名称
//    vector<const char*> inputNames;
//    vector<const char*> outputNames;
//
//    Ort::AllocatorWithDefaultOptions alloc;
//    for(size_t i = 0; i < session.GetInputCount(); i++) {
//        //push_back是创建元素,然后添加到vector末尾,
//        //emplace_back是直接在vector末尾创建元素,省去了copy或移动元素的过程
//        inputNames.emplace_back(session.GetInputName(i, alloc));
//    }
//    for(size_t i = 0; i < session.GetOutputCount(); i++) {
//        outputNames.emplace_back(session.GetOutputName(i, alloc));
//    }

推理过程,
这里的outputTensor是前面创建的,指向的是output数组,
所以最后的输出数据会在output数组里。

//inference
Ort::RunOptions runOptions;
try{
    session.Run(runOptions, inputNames.data(), &inputTensor, 1,
                outputNames.data(), &outputTensor, 1);
}catch (Ort::Exception& e) {
    cout << e.what() << endl;
    return 1;
}

现在我们得到的输出output是一条向量,并不是1x150x64x64的形状,
而我们想要的是1x150x64x64,然后在64x64的每个像素上,取所有channel的最大值index作为label,
取出label对应的颜色保存到像素上。
很复杂有木有。

先解决每个label对应什么颜色吧,
TopFormer共有150个类别,在ade20k_label_colors.txt(github下载)中有每个类别对应的颜色。
也可以自己定义颜色表。

const int classes = 150;
unsigned char colors[classes][3];
void color_map(int classes) {
   int r = 0, g = 0, b = 0;
   for(int i = 0; i < classes; i++) {  //150类
       int c = i;
       for(int j = 0; j < 8;j ++) {
           r = r | (bitget(c, 0) << 7-j);
           g = g | (bitget(c, 1) << 7-j);
           b = b | (bitget(c, 2) << 7-j);
           c = c >> 3;
       }
       for(int j = 0; j < 3; j++) {
           colors[i][0] = r;
           colors[i][1] = g;
           colors[i][2] = b;
       }
   }
}

把“在64x64的每个像素上,取所有channel的最大值index作为label,
取出label对应的颜色保存到像素上。“放在一起处理。
那么需要一个64x64x3的输出map

Mat output_map(out_height, out_width, CV_MAKETYPE(CV_8UC1, 3));

现在输出是1x150x64x64拉成一条的向量,
保存顺序是这样的,
[ch1: 64x64] [ch2: 64x64] … [ch150: 64x64]
只需要每隔64x64个点取各个channel数值,找到最大值所在的label即可。
注意opencv是以BGR的channel顺序储存的。

看看output_map的结果吧。
这里是64x64大小,没有resize.
可以看到跟python版本效果类似。
在这里插入图片描述
完整代码放在github的semantic

参考资料

使用onnx c++部署pytorch神经网络模型全流程 C++调用ONNXRUNTIME推理pytorch模型 阅读详情

相关推荐

解析ONNX(含C++和Python版本)

主要讲解ONNX在C++和Python代码下的解析

幸福回头的博客 6488

【ONNX】使用 C++ 调用 ONNX 格式的 PyTorch 深度学习模型进行预测(Windows, C++, PyTorch, ONNX, Visual Studio, OpenCV)

使用 C++ 的 OpenCV 接口调用 ONNX 格式的 PyTorch 深度学习模型进行预测(Windows, C++, PyTorch, ONNX, Visual Studio, OpenCV)

AItrust的博客 1万+

VS c++ onnxruntime 环境配置、onnx教程、部署推理模型、sklearn pkl模型转onnx、问题汇总

VS c++ onnxruntime 环境配置、onnx教程、部署推理模型、sklearn pkl模型转onnx、问题汇总

AIcar_lrm的博客 1万+

h2o-3 目标编码(Target Encoding):高基数分类特征的编码参数、transform 方法与 Titanic 实战

本文基于 h2o-3 仓库中的官方文档 [target-encoding.rst](https://link.gitcode.com/i/7b0681162698fc1603b20fba29e20ce5) 展开,系统讲解 H2O 中 Target Encoder 的全部训练参数(含默认值)、`transform` 变换方法,以及如何用 k_fold 防泄漏策略 + blending 正则化对 Ti

gitblog_00544的博客 774

C++ 上用 ONNXruntime 部署自己的模型

利用C++ ONNXruntime部署自己的模型,这里用Keras搭建好的一个网络模型来举例,转换为onnx的文件,在C++上进行部署,另外可以利用tensorRT加速。 目录一、模型的准备二、配置ONNXruntime三、模型的部署1. 模型的初始化设置2. 构建推理构建推理函数computPoseDNN()步骤:函数具体代码:四、应用参考 一、模型的准备 搭建网络模型训练: tensorflow keras 搭建相机位姿估计网络–例 网络的输入输出为: 网络的输入: [image_ref , ima

老邹的博客 2万+

onnxruntime c++ 推理示例(tensorRT/cuda provider)

onnxruntime-gpu:在 nvidia gpu 上跑onnx模型获得与tensorRT相媲美的推理速度

wohenibdxt的博客 8229

Pure Live v3.0.4:Android 可信画面比例解析统一与历史记录容量规则解析

本篇以 [docs/STAGE_UPDATE_3_0_4.md](https://link.gitcode.com/i/8a17bd53c7516d16d0715c5549c24b02) 为骨架,拆解 Pure Live v3.0.4(build 4092)这一版 Android 修复的核心内容:为什么移动端画面比例会失真、"可信比例"如何成为唯一缩放控制源、历史记录保留容量的统一规则如何实现,以

gitblog_00917的博客 384

onnxruntime的c++使用

onnxruntime的c++使用 利用onnx和onnxruntime实现pytorch深度框架使用C++推理进行服务器部署,模型推理的性能是比python快很多的 版本环境 python: pytorch == 1.6.0 onnx == 1.7.0 onnxruntime == 1.3.0 c++: onnxruntime-linux-x64-1.4.0 使用流程 首先,利用pytorch自带的torch.onnx模块导出 .onnx模型文件,具体查看该部分pytorch官方文档,主要流程如下: im

chencision的博客 4万+

ONNX在C++上部署

步骤 1:初始化 ONNX Runtime 环境。(2) 图片与处理preprocess.cpp。步骤 9:后处理(NMS + 解码)步骤 6:创建输入 Tensor。步骤 2:加载 ONNX 模型。步骤 3:获取模型输入输出信息。步骤 12:释放动态分配的内存。步骤 11:显示和保存结果。步骤 10:绘制检测结果。步骤 4:加载测试图像。步骤 8:获取输出数据。(3)预测结果后处理。

qq_35732321的博客 642

ONNX:C++通过onnxruntime使用.onnx模型进行前向计算【下载的onnxruntime是编译好的库文件,可直接使用】

利用onnx和onnxruntime实现深度框架使用C++推理进行服务器部署,模型推理的性能是比python快很多的。

u013250861的博客 1万+

多类别语义分割C++实现(onnx部署)详细教程

Unet多类别语义分割C++实现(onnx部署)详细教程

低调猫熊的博客 4192

利用OnnxRuntime进行torch模型部署(C++版)——以分类网络为例

近年来,ONNX(Open Neural Network Exchange)格式的兴起为解决这一问题提供了有效的途径。ONNX是一种开放标准,旨在使不同深度学习框架之间能够共享模型。通过将模型导出为ONNX格式,我们可以轻松地在不同框架和平台上进行部署和推理。而ONNX Runtime,作为微软开源的高性能推理引擎,更是为模型的部署提供了强大的支持。本文将重点介绍如何利用ONNX Runtime在C++环境中部署PyTorch模型。,而。通过结合这两者的优势,我们可以实现深度学习模型的高效部署和推理。

z240626191s的博客 2625

因果表示学习 (Causal Representation Learning, CRL)

传统的机器学习,尤其是深度学习,非常擅长学习数据中的相关性 (Correlation)。但它常常会走“捷径”,学到一些虚假的、不稳定的“表面联系”。一个AI模型在学习识别“牛”时,如果训练数据里所有的牛都在绿色的草地上,模型很可能会学到一个错误的规则:“牛 = 四条腿的生物 + 绿色背景”。你给它一张牛在海滩上的照片,它就可能不认识了。因果表示学习的目标,就是让模型超越这种表面相关性,去学习数据背后。

Xuxiansir的博客 1184

TopFormer: Token Pyramid Transformer for Mobile Semantic Segmentation论文解读

  本文试图在移动平台上实现低成本的transfomer计算来进行语义分割,并且实现多尺度融合。对于类似语义分割这种密集预测任务来说多尺度交互是很重要的,其他文章的多尺度融合一般是将编码器中的transfomer实现类似CNN的分层结构,然后将不同scale的特征图拿来进行融合。而这篇文章的创新点是通过金字塔结构将token多尺度化,然后将不同尺度的token进行融合。这样做既融合了多尺度的图像又因为H,W减小减小了计算量。再通过原始token与经过transfomer处理后的特征图进行融合,在分割的任务表

qq_42476803的博客 1523

Vmware虚拟机一打开就蓝屏解决方法

Vmware虚拟机一打开就蓝屏解决方法 问题: 一打开Vmware虚拟机就蓝屏,如下图所示: 解决方法1: 启用和关闭windows功能(对话框)——>虚拟机平台(选项打对勾,默认没勾选)——>确定后重启——>再进应该就好了。 解决方法2: ①.查看电脑中的Hyper-V服务是否关闭 1.打开控制面板-程序-程序和功能 2.双击启用或关闭Windows功能 3.把Hyper-V前面的勾去掉 如果后期发下没有反应,或者电脑本身Hyper-V的服务没有打开,可以先打开在关闭,试

m0_55901666的博客 26万+

CCS TMSC6748 报错Error connecting to the target: (Error -600 @ 0x0)

CCS TMSC6748 报错Error connecting to the target:(Error -600@ 0x0)

AS_the_deer1717的博客 6637

【深度学习】【OnnxRuntime】【C++】模型转化、环境搭建以及模型部署的详细教程

【深度学习】【OnnxRuntime】【C++】模型转化、环境搭建以及模型部署的详细教程

yangyu0515的博客 1万+

vue2 - 实现移动端H5网页调用手机相册选取图片或打开摄像头相机拍照上传,如何在h5网站浏览器中打开本机相册或相机选择相片,H5调用本地相册/相机上传图片详细教程(附图片压缩功能及上传服务器示例)

vue2手机H5网页,调起安卓苹果ios手机相册和相机,H5实现调用手机摄像头相册实现图片压缩预览删除,vue项目调用摄像头和相册,H5调用手机摄像头,实时拍照上传,VUE2 H5页面如何唤起手机摄像头拍照上传,H5调起手机端的摄像头,html5调用手机摄像头,实现H5调起手机相机和相册,vue H5拍照上传,手机网站浏览器移动端调取相机或相册,实现拍照上传功能,解决苹果ios手机无法打开相册相机问题,无法唤起摄像头怎么办,调取本机系统的相册,vue h5网页调用相机拍照和相册,实现多张图片上传功能,图片压

✅ 精选推荐文章 1万+

ONNX Runtime 加速深度学习(C++ 、python)详细介绍

ONNX Runtime 加速深度学习(C++ 、python)详细介绍

yohnyang的博客 6037

基于YOLO的印章检测及文字识别

针对印章自动化检测与文字识别需求,提出了一种融合改进YOLO模型与OCR技术的端到端解决方案,旨在解决复杂背景干扰、印章残缺变形及环形文字排列等难题

商务合作 / 项目定制 / 学习交流。个人vx:lovely_wml 8224

板蓝根挥发油微胶囊化技术及其在抗菌织物整理中的应用研究

微胶囊技术是一种通过成膜材料将具有反应活性或挥发性的液体或固体包封成微小颗粒的技术。该技术因其优异的缓释保护和物态改变性能,已在医药、食品、化妆品等多个领域得到广泛应用。本研究采用复凝聚法制备板蓝根挥发油的微胶囊,利用明胶和阿拉伯胶作为壁材,旨在提升其稳定性和抗菌性能。

qq_62634009的博客 585

深度学习模型部署——基于Onnx Runtime的深度学习模型CPU与GPU部署(C++实现)

以上就是在win 10下使用Onnx Runtime用CPU与GPU来对onnx模型进行推理部署的对比,可以明显的看出来,使用GPU之后的推理速度,但在正式的大型项目中,在win下使用GPU部署模型是不建议,一般都会选择Linux,那样对GPU的利用率会高出不少,毕竟蚊腿肉也是肉。

知来者逆的博客 2万+

激光打标轴坐标计算分析

‌:基于坐标差的平方和开方运算,勾股定理将几何关系转化为代数计算,从而实现了从坐标到距离的精确转换‌12。直角三角形的应用从上图可以看到A,B,P三个点连起来就是一个直角三角形了。用勾股定理计算距离 C#有相关的方法直接传参数就可以了。很方便。

StevenChen的博客 312

C++---视觉开发ONNX Runtime(ORT)

ORT(ONNX Runtime)是微软开源的跨平台深度学习推理引擎,可将PyTorch/TensorFlow等框架训练的模型通过ONNX格式高效部署。其核心优势包括:跨框架统一(支持YOLO、SegFormer等模型)、性能优化(推理延迟降低30%-50%)、多硬件适配(CPU/GPU/嵌入式/NPU)和轻量级设计(<10MB)。ORT采用分层架构,提供C++ API接口,包含Env(全局环境)、SessionOptions(会话配置)、Session(模型加载)、Allocator(内存管理)和V

MzKyle的博客 2311

OpenCV-Python实战(10)——详解 OpenCV 轮廓检测

在计算机视觉领域,轮廓通常指图像中对象边界的一系列点。因此,轮廓通常描述了对象边界的关键信息,包含了有关对象形状的主要信息,该信息可用于形状分析与对象检测和识别。在本文中,将首次通过简单示例了解轮廓的基本概念,然后通过实际示例来了解如何检测和压缩轮廓,最后利用介绍如何利用图像矩描述检测到的轮廓属性。

盼小辉丶的博客 3万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

基于c++ onnxruntime部署yolov5模型

最近因业务需要需要使用yolo模型来做目标检测的任务,翻了网上的各种博客没有比较完整的教程,在部署过程踩了不少坑,特别是在装英伟达驱动和cuda\cudnn版本时,甚至把ubuntu系统搞坏。于是想把训练及部署过程记录下来,并留给后来者方便使用。实验的系统是ubuntu20.04。

二爷的博客 4410

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: leetcode 237. Delete Node in a Linked List(链表中删除节点)
下一篇: leetcode 2095. Delete the Middle Node of a Linked List(删除链表的中间节点)
蓝羽飞鸟
博客等级 码龄8年 1万+粉丝 727原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值