在C++上利用onnxruntime (CUDA)和 opencv 部署模型onnx

概述

将得到的模型转化为onnx模型,加载到c++中运行,来完成模型的部署,下载并安装onnxruntime;

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(test)

#使用clang++编译器
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#find the opencv and the qt5
find_package(OpenCV 4.5.1  REQUIRED)
#onnxruntime
set(ONNXRUNTIME_ROOT_PATH /home/zyl/ubuntu/tensorRT/onnxruntime-master)
set(ONNXRUNTIME_INCLUDE_DIRS ${ONNXRUNTIME_ROOT_PATH}/include/onnxruntime
                             ${ONNXRUNTIME_ROOT_PATH}/onnxruntime
                             ${ONNXRUNTIME_ROOT_PATH}/include/onnxruntime/core/session/)
set(ONNXRUNTIME_LIB ${ONNXRUNTIME_ROOT_PATH}/build/Linux/Release/libonnxruntime.so)
include_directories(${ONNXRUNTIME_INCLUDE_DIRS})


add_executable(${PROJECT_NAME} "main.cpp")
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${ONNXRUNTIME_LIB})

C++源码:

#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <chrono>
#include <string>

//onnxruntime
#include <core/session/onnxruntime_cxx_api.h>
#include <core/providers/cuda/cuda_provider_factory.h>
#include <core/session/onnxruntime_c_api.h>
#include <core/providers/tensorrt/tensorrt_provider_factory.h>

using namespace std;

int main(int argc,char ** argv)
{
    //输入网络的维度
    static constexpr const int width = 600;
    static constexpr const int height = 600;
    static constexpr const int channel = 3;
    std::array<int64_t, 4> input_shape_{ 1,height, width,channel};

    //-------------------------------------------------------------onnxruntime-------------------------------------------------
    //图片和模型位置
    string img_path = argv[1];
    string model_path = "model.onnx";
    cv::Mat imgSource = cv::imread(img_path);

    Ort::Env env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, "Detection");
    Ort::SessionOptions session_options;
    //CUDA加速开启
    //OrtSessionOptionsAppendExecutionProvider_Tensorrt(session_options, 0); //tensorRT
    OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0);
    session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);

    Ort::AllocatorWithDefaultOptions allocator;
    //加载ONNX模型
    Ort::Session session(env, model_path.c_str(), session_options);
    //获取输入输出的维度
    std::vector<int64_t> input_dims = session.GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();
    std::vector<int64_t> output_dims = session.GetOutputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();

    /*
    session.GetOutputName(1, allocator);
    session.GetInputName(1, allocator);
    //输出模型输入节点的数量
    size_t num_input_nodes = session.GetInputCount();
    size_t num_output_nodes = session.GetOutputCount();
    */

    std::vector<const char*> input_node_names = {"image_tensor:0"};
    std::vector<const char*> output_node_names = {"detection_boxes:0","detection_scores:0","detection_classes:0","num_detections:0" };
    input_dims[0] = output_dims[0] = 1;//batch size = 1

    std::vector<Ort::Value> input_tensors;
    auto memory_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);

    //将图像存储到uchar数组中,BGR--->RGB
    std::array<uchar, width * height *channel> input_image_{};
    uchar* input =  input_image_.data();
    for (int i = 0; i < imgSource.rows; i++) {
        for (int j = 0; j < imgSource.cols; j++) {
            for (int c = 0; c < 3; c++)
            {
                //NHWC 格式
                if(c==0)
                    input[i*imgSource.cols*3+j*3+c] = imgSource.ptr<uchar>(i)[j*3+2];
                if(c==1)
                    input[i*imgSource.cols*3+j*3+c] = imgSource.ptr<uchar>(i)[j*3+1];
                if(c==2)
                    input[i*imgSource.cols*3+j*3+c] = imgSource.ptr<uchar>(i)[j*3+0];
                //NCHW 格式
//                if (c == 0)
//                     input[c*imgSource.rows*imgSource.cols + i * imgSource.cols + j] = imgSource.ptr<uchar>(i)[j * 3 + 2];
//                if (c == 1)
//                     input[c*imgSource.rows*imgSource.cols + i * imgSource.cols + j] = imgSource.ptr<uchar>(i)[j * 3 + 1];
//                if (c == 2)
//                     input[c*imgSource.rows*imgSource.cols + i * imgSource.cols + j] = imgSource.ptr<uchar>(i)[j * 3 + 0];


            }
        }
    }

    input_tensors.push_back(Ort::Value::CreateTensor<uchar>(
            memory_info, input, input_image_.size(), input_shape_.data(), input_shape_.size()));
    //不知道输入维度时
    //input_tensors.push_back(Ort::Value::CreateTensor<uchar>(
    //        memory_info, input, input_image_.size(), input_dims.data(), input_dims.size()));

    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();

    std::vector<Ort::Value> output_tensors;
    for(int i=0; i<100;i++)
         output_tensors = session.Run(Ort::RunOptions { nullptr },
                                                            input_node_names.data(), //输入节点名
                                                            input_tensors.data(),     //input tensors
                                                            input_tensors.size(),     //1
                                                            output_node_names.data(), //输出节点名
                                                            output_node_names.size()); //4
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();

    chrono::duration<double> delay_time = chrono::duration_cast<chrono::duration<double>>(t2 - t1); //milliseconds 毫秒

    cout<<"前向传播平均耗时:"<<delay_time.count()*1000/100.0<<"ms"<<endl;

    float* boxes_ = output_tensors[0].GetTensorMutableData<float>();
    float* scores_ = output_tensors[1].GetTensorMutableData<float>();
    float* class_ = output_tensors[2].GetTensorMutableData<float>();
    float* num_detection = output_tensors[3].GetTensorMutableData<float>();

    //-------------------------------------------------------------onnxruntime-------------------------------------------------


    //------------------循环遍历显示检测框--------------------------
    cv::Mat frame(imgSource.clone());
        for (int i = 0; i < num_detection[0]; i++)
            {
                float confidence = scores_[i];
                size_t objectClass = (size_t)class_[i];

                if (confidence >= 0.8)
                {
                    int xLeftBottom = static_cast<int>(boxes_[i*4 + 1] * frame.cols);
                    int yLeftBottom = static_cast<int>(boxes_[i*4 + 0] * frame.rows);
                    int xRightTop = static_cast<int>(boxes_[i*4 + 3] * frame.cols);
                    int yRightTop = static_cast<int>(boxes_[i*4 + 2]* frame.rows);

                    //显示检测框
                    cv::Rect object((int)xLeftBottom, (int)yLeftBottom,
                        (int)(xRightTop - xLeftBottom),
                        (int)(yRightTop - yLeftBottom));

                    cv::rectangle(frame, object, cv::Scalar(0,0,255), 2);
                    cv::String label = cv::String("confidence :") +to_string(confidence);
                    int baseLine = 0;
                    cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.3, 1, &baseLine);
                    cv::rectangle(frame, cv::Rect(cv::Point(xLeftBottom, yLeftBottom - labelSize.height),
                        cv::Size(labelSize.width, labelSize.height + baseLine)),
                        cv::Scalar(255, 255, 0), cv::FILLED);
                    cv::putText(frame, label, cv::Point(xLeftBottom, yLeftBottom),
                        cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(0, 0, 0));
                }
            }
    cv::imshow("frame",frame);
    cv::waitKey(0);
    return 0;

}

 
 
参考链接:

  1. https://codechina.csdn.net/mirrors/tenglike1997/onnxruntime-projects/-/blob/master/Ubuntu/onnx_mobilenet
  2. https://blog.csdn.net/mightbxg/article/details/119237326
ONNX Runtime是一个高性能的开源推理引擎,用于在各种硬件上执行机器学习模型。与OpenCV相比,ONNX Runtime具有更高的性能和更广泛的硬件支持。 要使用ONNX Runtime进行分割任务,您可以按照以下步骤操作: 1. 安装ONNX Runtime库:首先,您需要安装ONNX Runtime库。您可以通过在终端中运行适当的安装命令来完成此操作,具体取决于您使用的操作系统和硬件。 2. 加载和解析模型:在使用ONNX Runtime之前,您需要加载和解析分割模型。您可以使用ONNX Runtime的API来加载和解析ONNX模型文件。 3. 准备输入数据:在进行分割之前,您需要准备输入数据。通常,输入数据是图像,您可以使用常见的图像库(如PIL)或将图像读取为NumPy数组。 4. 运行推断:一旦加载模型并准备好输入数据,您可以使用ONNX Runtime的API来运行推断。这将对输入数据进行模型的前向传递,并生成分割结果。 5. 处理输出结果:最后,您可以根据需求处理和可视化分割的输出结果。您可以使用常见的图像处理库(如PIL)或将输出结果转换为NumPy数组进行后续处理和可视化。 总结来说,使用ONNX Runtime进行分割任务不需要使用OpenCV。您只需要加载和解析模型、准备输入数据、运行推断以及处理输出结果。ONNX Runtime提供了高性能和硬件支持,可以有效地执行机器学习模型,包括分割任务。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值