C++ Qt / VS2019 +opencv + onnxruntime 部署语义分割模型【经验】

本机环境:
OS:WIN11
CUDA: 11.1
CUDNN:8.0.5
显卡:RTX3080 16G
opencv:3.3.0
onnxruntime:1.8.1

目前C++ 调用onnxruntime的示例主要为图像分类网络,与语义分割网络在后处理部分有很大不同。

  1. pytorch模型转为onnx格式

1.1 安装onnx, 参考官网https://onnxruntime.ai/
1.2 pytorch->onnx

import torch
from nets.unet import Unet
import numpy as np


use_cuda = torch.cuda.is_available()

device = torch.device('cuda:0' if use_cuda else 'cpu')

checkpoints = torch.load("latest.pth")
model = Unet().to(device)
model.load_state_dict(checkpoints)

model.eval()

img_scale = [64, 64]
input_shape = (1, 3, img_scale[1], img_scale[0])
rng = np.random.RandomState(0)
dummy_input = torch.rand(1, 3, 64, 64).to(device)
imgs = rng.rand(*input_shape)
output_file = "latest.onnx"

dynamic_axes = {
                'input': {
                    0: 'batch',
                    2: 'height',
                    3: 'width'
                },
                'output': {
                    1: 'batch',
                    2: 'height',
                    3: 'width'
                }
            }

with torch.no_grad():
    torch.onnx.export(
        model, dummy_input,
        output_file,
        input_names=['input'],
        output_names=['output'],
        export_params=True,
        keep_initializers_as_inputs=False,
        opset_version=11,
        dynamic_axes=dynamic_axes)
    print(f'Successfully exported ONNX model: {output_file}')

由于网络中包含upsample上采样层,出现以下问题:

TypeError: 'NoneType' object is not subscriptable 
(Occurred when translating upsample_bilinear2d).

查到有两种解决方案:

  1. 重写上采样层
  2. 【推荐】 修改参数:opset_version=11
    torch.onnx.export(model, input, onnx_path, verbose=True, input_names=input_names, output_names=output_names, opset_version=11)

检查模型是否正确

import onnx
# Load the ONNX model
onnx_model = onnx.load("latest.onnx") 
try: 
    onnx.checker.check_model(onnx_model) 
except Exception: 
    print("Model incorrect") 
else: 
    print("Model correct")

# Print a human readable representation of the graph
print(onnx.helper.printable_graph(model.graph))

python 调用onnxruntime

import onnx
import torch
import cv2
import numpy as np
import onnxruntime as ort
import torch.nn.functional as F
import matplotlib.pyplot as plt



def predict_one_img(img_path):
    img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), 1)
    img = cv2.resize(img, (64, 64))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 把图片BGR变成RGB
    print(img.shape)

    img = np.transpose(img,(2,0,1))
    
    img = img.astype(np.float32)
    img /= 255
    # img = (img - 0.5) / 0.5
    mean = [0.485, 0.456, 0.406]
    std = [0.229, 0.224, 0.225]
    for i in range(3):
        img[i,:,:] = (img[i,:,:] - mean[i]) / std[i]
    print(img.shape)

    img = np.expand_dims(img, 0)

    outputs = ort_session.run(
        None,
        {"input": img.astype(np.float32)},
    )
    print(np.max(outputs[0]))
    # print(np.argmax(outputs[0]))
    

    out = torch.tensor(outputs[0],dtype=torch.float64)
    out = F.softmax(out, dim=1)

    out = torch.squeeze(out).cpu().numpy()

    print(out.shape)
    pr = np.argmax(out, axis=0)
    
    # # out = out.argmax(axis=-1)
    # pr = F.softmax(out[0].permute(1, 2, 0), dim=-1).cpu().numpy()
    
    # pr = pr.argmax(axis=-1)
    # img = img.squeeze(0)
    # new_img = np.transpose(img, (1, 2, 0))
    new_img = pr * 255
    plt.imshow(new_img)
   
    plt.show()

if __name__ == '__main__':

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    img_path = "0007.png"
    model_path = ".latest.onnx"
    ort_session = ort.InferenceSession(model_path, providers=['CUDAExecutionProvider'])
    predict_one_img(img_path)
  1. 下载Onnxruntime

可以直接下载编译好的文件,我选用的是gpu版本
https://github.com/microsoft/onnxruntime/releases/tag/v1.8.1添加链接描述
尝试使用cmake重新编译onnxruntime,感觉是个弯路
3. vs2019 配置onnxruntime
新建空项目
右击选择属性,
VC++目录 ——包含目录——include文件夹
链接器——常规——附加库目录——lib文件夹
链接器——输入——附加依赖项 llib文件
在这里插入图片描述

将onnxruntime.dll 复制到debug目录下

  1. qt配置onnxruntime

在pro文件最后加入

include("opencv.pri")
include("onnx.pri")

DISTFILES += \
    opencv.pri \
    onnx.pri

opencv.pri

INCLUDEPATH += C:/opencv/build/include
INCLUDEPATH += C:/opencv/build/include/opencv2
INCLUDEPATH += C:/opencv/build/include/opencv

LIBS += -L"C:/opencv/build/x64/vc14/lib"\
        -lopencv_world330\
        -lopencv_world330d

onnx.pri

INCLUDEPATH += C:/onnxruntime1.8.1/include


LIBS += -L"C:/onnxruntime1.8.1/lib"\
        -lonnxruntime \

Onnx模型在线查看器:https://netron.app/

Ref
[1] C++/CV/推理部署资料整理

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
【资源说明】 基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip 基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip 基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip基于QT实现的缺陷检测系统c++源码(含图像检测+目标检测支持ONNXRuntime加速).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
下面是一个简单的 C++ OpenCV DNN 推理代码示例,使用 ONNX 格式的 U-Net 模型进行语义分割: ```c++ #include <opencv2/dnn/dnn.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; using namespace cv::dnn; int main(int argc, char** argv) { // 读取模型文件 const string model_file_path = "unet.onnx"; Net net = readNetFromONNX(model_file_path); // 读取输入图像 const string input_file_path = "input.jpg"; Mat input_image = imread(input_file_path); // 预处理输入图像 Mat input_blob = blobFromImage(input_image, 1.0 / 255.0, Size(572, 572), Scalar(0, 0, 0), true, false); // 运行推理 Mat output_blob; net.setInput(input_blob); net.forward(output_blob); // 后处理输出结果 Mat output_image; output_blob = output_blob.reshape(1, 388 * 388); output_blob.convertTo(output_blob, CV_8UC1, 255.0); applyColorMap(output_blob, output_image, COLORMAP_JET); // 显示输出结果 imshow("Output", output_image); waitKey(0); return 0; } ``` 这个示例代码假设已经有了一个 ONNX 格式的 U-Net 模型文件 `unet.onnx` 和一个输入图像文件 `input.jpg`。代码中首先使用 `readNetFromONNX` 函数读取了模型文件,然后使用 `imread` 函数读取了输入图像。 接下来,代码中使用 `blobFromImage` 函数将输入图像转换成网络需要的输入格式,并使用 `setInput` 函数将输入数据设置到网络中,使用 `forward` 函数进行推理,得到输出结果。 最后,代码中使用 `reshape` 函数和 `convertTo` 函数对输出结果进行后处理,然后使用 `applyColorMap` 函数将结果可视化,使用 `imshow` 函数显示输出结果,使用 `waitKey` 函数等待用户按下键盘。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值