The_be 2024-11-23 20:02 采纳率: 25%
浏览 125

c++调用onnx模型

#include <onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
#include <fstream>
#include <vector>
#include <filesystem>
using namespace cv;
using namespace std;


int main(int argc, char** argv)
{
    //step-1:set filepath and modelpath
    cv::Mat frame = cv::imread("F:/Yolov11-onnx_cpp-main/1.jpg");
    std::string onnxpath = "E:/ultralytics-main/ultralytics-main/runs/train/exp9/weights/best.onnx";

    //step2:load labels
    std::vector<std::string> labels;
    std::ifstream inputFile("E:/classes.names");
    if (inputFile.is_open())
    {
        std::string classLine;
        while (std::getline(inputFile, classLine))
            labels.push_back(classLine);
        inputFile.close();
    }

    //step-3:load onnx model
    int ih = frame.rows;
    int iw = frame.cols;

    std::wstring modelPath = std::wstring(onnxpath.begin(), onnxpath.end());
    Ort::SessionOptions session_options;
    Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "yolov11-onnx");

    session_options.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
    //std::cout << "onnxruntime inference try to use GPU Device" << std::endl;
    OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0);
    Ort::Session session_(env, modelPath.c_str(), session_options);

    std::vector<std::string> input_node_names;
    std::vector<std::string> output_node_names;

    size_t numInputNodes = session_.GetInputCount();
    size_t numOutputNodes = session_.GetOutputCount();
    Ort::AllocatorWithDefaultOptions allocator;
    input_node_names.reserve(numInputNodes);

    int input_w = 0;
    int input_h = 0;
    for (int i = 0; i < numInputNodes; i++) {
        //onnx newest version-1.14
        auto input_name = session_.GetInputNameAllocated(i, allocator);
        input_node_names.push_back(input_name.get());

        //onnx old version-1.8
        //input_node_names.push_back(session_.GetInputName(i, allocator));

        Ort::TypeInfo input_type_info = session_.GetInputTypeInfo(i);
        auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
        auto input_dims = input_tensor_info.GetShape();
        input_w = input_dims[3];
        input_h = input_dims[2];
        std::cout << "input format: NxCxHxW = " << input_dims[0] << "x" << input_dims[1] << "x" << input_dims[2] << "x" << input_dims[3] << std::endl;
    }

    //step-4:get output parameter
    int output_h = 0;
    int output_w = 0;
    Ort::TypeInfo output_type_info = session_.GetOutputTypeInfo(0);
    auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
    auto output_dims = output_tensor_info.GetShape();
    output_h = output_dims[1];
    output_w = output_dims[2];
    std::cout << "output format : HxW = " << output_dims[1] << "x" << output_dims[2] << std::endl;
    for (int i = 0; i < numOutputNodes; i++)
    {
        //onnx newest version-1.14
        auto out_name = session_.GetOutputNameAllocated(i, allocator);
        output_node_names.push_back(out_name.get());

        //onnx old version-1.8
        //output_node_names.push_back(session_.GetOutputName(i, allocator));
    }
    std::cout << "input: " << input_node_names[0] << " output: " << output_node_names[0] << std::endl;

    //step-5:get infer result
    int64 start = cv::getTickCount();
    int w = frame.cols;
    int h = frame.rows;
    int _max = std::max(h, w);
    cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);
    cv::Rect roi(0, 0, w, h);
    frame.copyTo(image(roi));

    // fix bug, boxes consistence!
    float x_factor = image.cols / static_cast<float>(input_w);
    float y_factor = image.rows / static_cast<float>(input_h);

    cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(input_w, input_h), cv::Scalar(0, 0, 0), true, false);
    size_t tpixels = input_h * input_w * 3;
    std::array<int64_t, 4> input_shape_info{ 1, 3, input_h, input_w };

    // set input data and inference
    auto allocator_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
    Ort::Value input_tensor_ = Ort::Value::CreateTensor<float>(allocator_info, blob.ptr<float>(), tpixels, input_shape_info.data(), input_shape_info.size());
    const std::array<const char*, 1> inputNames = { input_node_names[0].c_str() };
    const std::array<const char*, 1> outNames = { output_node_names[0].c_str() };
    std::vector<Ort::Value> ort_outputs;
    try {
        ort_outputs = session_.Run(Ort::RunOptions{ nullptr }, inputNames.data(), &input_tensor_, 1, outNames.data(), outNames.size());
    }
    catch (std::exception e) {
        std::cout << e.what() << std::endl;
    }

    // output data
    const float* pdata = ort_outputs[0].GetTensorMutableData<float>();
    cv::Mat dout(output_h, output_w, CV_32F, (float*)pdata);
    cv::Mat det_output = dout.t(); // 8400x84

    // post-process
    std::vector<cv::Rect> boxes;
    std::vector<int> classIds;
    std::vector<float> confidences;
    int returnValue = 0;
    for (int i = 0; i < det_output.rows; i++) {
        cv::Mat classes_scores = det_output.row(i).colRange(4, 9);
        cv::Point classIdPoint;
        double score;
        minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);

        //between 0~1
        if (score > 0.25)
        {
            float cx = det_output.at<float>(i, 0);
            float cy = det_output.at<float>(i, 1);
            float ow = det_output.at<float>(i, 2);
            float oh = det_output.at<float>(i, 3);
            int x = static_cast<int>((cx - 0.5 * ow) * x_factor);
            int y = static_cast<int>((cy - 0.5 * oh) * y_factor);
            int width = static_cast<int>(ow * x_factor);
            int height = static_cast<int>(oh * y_factor);
            cv::Rect box;
            box.x = x;
            box.y = y;
            box.width = width;
            box.height = height;

            // 获取类别ID
            int classId = classIdPoint.x;

            // 根据类别ID设置返回值
            if (classId == 0 || classId == 1) {  // 假设类别0为目标类别
                returnValue = 1; // 设置为1
            }
            else {
                returnValue = 0; // 默认值
            }

            boxes.push_back(box);
            classIds.push_back(classIdPoint.x);
            confidences.push_back(score);
        }
    }
    std::cout << "Detection Result: " << returnValue << std::endl;
    // NMS
    std::vector<int> indexes;
    cv::dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes);
    for (size_t i = 0; i < indexes.size(); i++) {
        int index = indexes[i];
        int idx = classIds[index];
        cv::rectangle(frame, boxes[index], cv::Scalar(0, 0, 255), 2, 8);
        cv::rectangle(frame, cv::Point(boxes[index].tl().x, boxes[index].tl().y - 20),
            cv::Point(boxes[index].br().x, boxes[index].tl().y), cv::Scalar(0, 255, 255), -1);

        std::string classString = labels[idx] + ' ' + std::to_string(confidences[idx]).substr(0, 4);
        putText(frame, classString, cv::Point(boxes[index].tl().x, boxes[index].tl().y), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);
        cv::imshow("YOLOv11 onnxrunning", frame);
    }

    //calculate FPS render it
    float t = (cv::getTickCount() - start) / static_cast<float>(cv::getTickFrequency());
    putText(frame, cv::format("FPS: %.2f", 1.0 / t), cv::Point(20, 40), cv::FONT_HERSHEY_PLAIN, 2.0, cv::Scalar(255, 0, 0), 2, 8);
    cv::imshow("YOLOv11 onnxrunning", frame);
    cv::imwrite("result.jpg", frame);
    cv::waitKey(0);

    session_options.release();
    session_.release();
    return 0;
}

上述代码是我使用的c++调用onnx模型的代码,在我使用cpu时代码可以正常运行。但是当我使用gpu运行时它产生了错误:The requested API version [18] is not available, only API versions [1, 17] are supported in this build. Current ORT Version is: 1.17.1
我使用的是onnxruntime-gpu1.20.1版本,opencv是4.5的版本,cuda是11.8几,cudnn是8x。上述该问题应该怎么解决?

  • 写回答

1条回答 默认 最新

  • 关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    从错误信息来看,你正在尝试使用 ONNX Runtime 的一个版本(可能是 1.20.1),但你的构建只支持到 API 版本 17,而你正在尝试使用 API 版本 18。这个问题可能是由于你的 ONNX Runtime 版本与你的 CUDA 或 cuDNN 版本不兼容造成的。下面是一些可能的解决方案:

    1. 更新 ONNX Runtime 版本:确保你使用的是与 CUDA 和 cuDNN 兼容的 ONNX Runtime 版本。有时,最新版本的 ONNX Runtime 可能包含对新的 CUDA 和 cuDNN 版本的兼容性更新。你可以尝试下载并使用一个更新的版本,确保它与你的 CUDA 和 cuDNN 版本兼容。
    2. 检查 CUDA 和 cuDNN 版本:确认你的 CUDA 和 cuDNN 版本是否与你的 ONNX Runtime 版本兼容。有时候,某些版本的 CUDA 或 cuDNN 可能与某些版本的 ONNX Runtime 不完全兼容。你可以查看 ONNX Runtime 的官方文档,找到推荐的 CUDA 和 cuDNN 版本。
    3. 重新编译 ONNX Runtime:如果你有条件的话,可以尝试重新编译 ONNX Runtime,确保它是针对你的 CUDA 和 cuDNN 版本优化的。在编译时,确保你设置了正确的 CUDA 和 cuDNN 路径,并使用了正确的版本标志。
    4. 使用更低版本的 API:如果你的代码使用了某些新的 API 功能,而这些功能在你的当前构建版本中不可用,你可以尝试修改代码以使用较低版本的 API 功能。这可能意味着你需要修改你的代码中的一些调用或参数设置。

    基于你提供的错误信息,我建议首先尝试更新 ONNX Runtime 到一个更新的版本,并确保它与你的 CUDA 和 cuDNN 版本兼容。如果问题仍然存在,你可以考虑重新编译 ONNX Runtime 或使用更低版本的 API。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月23日