【yolov8部署实战】VS2019环境下使用C++和OpenCV环境部署yolo项目|含详细注释源码

一、前言

之前一阵子一直在做的就是怎么把yolo项目部署成c++项目,因为项目需要嵌套进yolo模型跑算法。因为自己也是本科生小白一枚,基本上对这方面没有涉猎过,自己一个人从网上到处搜寻资料,写代码,调试,期间遇到的bug不能说多,只能说很多!!!

最开始的思路一直都是,有没有什么办法能够直接用C++代码直接调用整个yolo项目,也就是如何用C++调用python项目。

这期间真的,碰壁不少,先是安装opencv环境,能显示图像了,然后就是调用python。网上的教程很少或者说基本没有关于如何直接用c++调用整个python项目的。一般也是用c++调用一个python脚本文件的。可即使就是用c++调用一个python脚本文件,也遇到了数不尽的bug。无法找到python36.dll呀、python环境变量冲突呀…怎么说呢,反正是网上关于c++调用python脚本的bug,不管是查得到的还是查不到的,我全遇到了…

下面是自己记录的一些问题以及解决办法:

  • 途中报错:由于找不到python36.dll,无法继续执行代码。重新安装程序可能会解决此问题

    只要重新下载python37.dll解压复制到C:\Windows\System32\这里就行了

  • QT调用python脚本时遇到的坑(十一大坑全有)

  • Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding, when trying to start uwsgi这个问题应该还是跟环境变量什么的有关系,最后还是没解决(可能是我电脑上python环境太多太杂乱了?)反正试了很多办法也没解决。最后的最后呢,换了台电脑,重新按照教程,注意一些坑点,成功调用了一个python脚本文件。

主要参考教程如下:

  • VS+QT调用python脚本

  • C++ QT调用python脚本并将软件打包发布

在这里特别想感谢第一篇教程的博主十里春风_jzh,因为在调用python脚本的时缺少遇到了很多bug和困难,这个博主一直耐心回答帮助我解决问题,真的十分感谢!这也是为什么我一直坚持写博客,分享知识的原因,因为一个人的力量总是渺小的,而更多人的智慧是无量的!
在这里插入图片描述


在这里插入图片描述
最后由于精力耗费太大,网上相关资料又太少,虽然实现了C++调用一个python脚本文件,但是还是没有实现C++直接调用一整个python项目的。(当时不知道为什么QT项目又只能在Debug模式下跑、也想到又要集成python整个大的项目,最后的软件体积是否会非常大?))况且网上的方法一般还是把yolo模型用其他C++框架(opencv-dnn、onnxruntime、TensorRT)部署的比较多,于是转战直接用c++和相关框架来部署了。

当时记录的新路历程:
⭐yolo转为onnx,用c++进行推理
发现直接用c++去调用整个yolov8的ultralytics项目网上的方法少之又少,而且通过了解知道yolo的底层框架什么的其实也是c++,看到很多用c++部署yolo的都是转换为onnx模型,现在那就按照这种方法试试吧,毕竟参考资料很多。虽然之前一开始也想到了这种部署方法,但是出于对c++的恐惧以及对Yolov8项目的没有很深入的了解,还有pytorch这些框架的不了解,感觉很害怕,怕自己弄错,于是想着偷懒,如果能找到c++直接调用python整个项目的该多好。但是现在才反应过来,技术的懒你是一点也偷不了,这块你不克服、你不去弄懂、你不去尝试,你就跨不过去这个坎。反而弄懂之后不但扫清了你的障碍,还对这块技术有了更深入的了解,还可以反观之前那种偷懒方法隐含的弊端。

一开始是发现YOLO官方直接有相关的onnxruntime-cpp的代码实现:ultralytics/examples
/YOLOv8-ONNXRuntime-CPP/。

  • 注意点一、改变语言标准为c++17

    VS2019修改C++标准(支持C++17)

  • 注意点2:配置好onnx环境()

  • cuda和onnxruntime的环境配置(40系列的显卡至cuda至少要11.8->这个点暂时不确定,因为后来我在项目中使用11.2版本的cuda没有问题)

    VS2019配置onnxruntime推理环境

    使用gpu版本onnxruntime的推理需要使用cuda

    cuda的安装过程看这个CUDA安装及环境配置——最新详细版
    结合CUDA11.0+VS2019+WIN10环境配置

⭐⭐⭐❗❗❗❗主要还是参考官方yolo教程,但是yolo的教程运行起来还是报错,然后还是一开始使用的这个博客使用opencv的方法进行Yolov8的推理:(注意环境必须是opencv4.8.0/4.8.1

yolov8 opencv模型部署(C++版)

但是出现问题:opencv4.8版本ok,enableCuda也设置了true,但是推理一张图片居然要5s,看任务管理器也发现没有用GPU,看这个博客评论得到以下点\

  • 使用CUDA需要将cv::Mat类型转换为GpuMat(好吧,后来试了这个发现显示cv没有GpuMat,不知道是不是英文opencv需要进行编译的原因(劝退了,opencv编译太难了
  • ❗博主也给出opencv+cuda源码编译有(看来需要将opencv进行特定的编译?)同时也给出可以直接使用tensorrt,速度会比opencv+cuda快很多,说折腾这个时间成本高,且折腾完了所以对于也相对较慢(博主也给出了tensorrt进行部署的教程:win10下 yolov8 tensorrt模型部署✨

(🙇🏻‍♀️说实话当时tensorrt有点劝退了,好像有点复杂,再试试如何启用opencv进行cuda加速把)

下面先给出基于opencv版本的yolo部署:

二、opencv部署:

2.1:前言

yolov8 opencv模型部署(C++ 版)
参考学习的博客:win10下 yolov8 tensorrt模型部署✨

使用opencv推理yolov8模型,仅依赖opencv,无需其他库,以yolov8s为例子,注意:

使用opencv4.8.1 !
使用opencv4.8.1 !
使用opencv4.8.1 !
如果你使用别的版本,例如opencv4.5,可能会出现错误

至于怎么安装yolov8、训练模型、导出onnx博客中都有,这里不做详细解释。关于vs2019配置opencv环境的博客网上也是一大堆,这里也不再重复造轮子了

2.2:代码(含详细注释版)

inference.h

#ifndef INFERENCE_H
#define INFERENCE_H// Cpp native
#include <fstream>
#include <vector>
#include <string>
#include <random>// OpenCV / DNN / Inference
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>//Detection结构体用来保存目标检测的结果实例
struct Detection
{int class_id{ 0 };//整形变量用来存储检测到的目标的类别,默认值为0std::string className{};//字符串变量用来存储检测到的目标的名称,默认值为空字符串float confidence{ 0.0 };//目标检测的置信度(即对目标存在的确定程度)。默认值为0.0。cv::Scalar color{};//OpenCV库中的Scalar类型变量,用于存储颜色信息。它可以表示RGB、BGR或灰度颜色空间中的颜色cv::Rect box{}; //cv::Rect 类型包含四个成员变量:x、y、width 和 height
};//Infrence类用来执行目标检测
class Inference
{
public://构造函数(modelInputShape是值模型的大小,默认为640,640;classesTxtFile是类别名称的文本文件路径(可选参数,默认为空字符串);runWithCuda是一个布尔值,指示是否使用CUDA加速运行(可选参数,默认为true)。Inference(const std::string& onnxModelPath, const cv::Size& modelInputShape = { 640, 640 }, const std::string& classesTxtFile = "", const bool& runWithCuda = true);//公有成员函数,用于执行目标检测推断。它接受一个cv::Mat类型的输入图像,并返回一个std::vector<Detection>类型的检测结果。该函数将执行目标检测算法,将检测到的目标信息封装到Detection结构体中,并将所有检测结果存储在一个向量中。std::vector<Detection> runInference(const cv::Mat& input);//私有成员函数,用于内部操作
private://loadClassesFromFile函数从文本文件中加载类别名称void loadClassesFromFile();//loadOnnxNetwork函数加载ONNX模型void loadOnnxNetwork();//formatToSquare函数将输入图像调整为正方形形状。cv::Mat formatToSquare(const cv::Mat& source);//这些是私有成员变量std::string modelPath{};//存储模型文件路径std::string classesPath{};//类别文件路径bool cudaEnabled{};//CUDA加速的状态//字符串向量,用于存储目标检测的类别名称。默认情况下,它包含了一些通用的目标类别名称std::vector<std::string> classes{ "screw", "number", "pump" };//std::vector<std::string> classes{ "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush" };//这是一个OpenCV库中的Size2f类型变量,用于存储模型的输入形状(宽度和高度)。cv::Size2f modelShape{};//设置目标检测的阈值float modelConfidenceThreshold{ 0.25 };//目标置信度的阈值float modelScoreThreshold{ 0.45 };//目标得分的阈值float modelNMSThreshold{ 0.50 };//非最大抑制的阈值//布尔变量,指示是否使用letterbox技术将输入图像调整为正方形形状bool letterBoxForSquare = true;//该类封装了目标检测推断的相关操作和参数,通过调用构造函数和成员函数,你可以加载模型、执行推断,并获取目标检测的结果cv::dnn::Net net;//penCV库中的Net类型变量,用于存储加载的目标检测网络模型
};#endif // INFERENCE_H

inference.cpp

#include "inference.h"Inference::Inference(const std::string& onnxModelPath, const cv::Size& modelInputShape, const std::string& classesTxtFile, const bool& runWithCuda)
{modelPath = onnxModelPath;modelShape = modelInputShape;classesPath = classesTxtFile;cudaEnabled = runWithCuda;loadOnnxNetwork();// loadClassesFromFile(); The classes are hard-coded for this example
}std::vector<Detection> Inference::runInference(const cv::Mat& input)
{cv::Mat modelInput = input;if (letterBoxForSquare && modelShape.width == modelShape.height)modelInput = formatToSquare(modelInput);cv::Mat blob;cv::dnn::blobFromImage(modelInput, blob, 1.0 / 255.0, modelShape, cv::Scalar(), true, false);net.setInput(blob);std::vector<cv::Mat> outputs;net.forward(outputs, net.getUnconnectedOutLayersNames());//cv::Mat cpuOutput;//outputs[0].copyTo(cpuOutput);  // 将数据从 GPU 复制到 CPU 的 cv::Mat 对象中//float* data = reinterpret_cast<float*>(outputs.data);  // 将数据赋值给 float* 指针int rows = outputs[0].size[1];int dimensions = outputs[0].size[2];bool yolov8 = true;// yolov5 has an output of shape (batchSize, 25200, 85) (Num classes + box[x,y,w,h] + confidence[c])// yolov8 has an output of shape (batchSize, 84,  8400) (Num classes + box[x,y,w,h])if (dimensions > rows) // Check if the shape[2] is more than shape[1] (yolov8){yolov8 = true;rows = outputs[0].size[2];dimensions = outputs[0].size[1];outputs[0] = outputs[0].reshape(1, dimensions);cv::transpose(outputs[0], outputs[0]);}//if (cv::cuda::getCudaEnabledDeviceCount() > 0) { // 检查是否启用了GPU计算//    //    cv::cuda::GpuMat gpuData(outputs[0]);  // 将 GPU 数据包装到 cv::cuda::GpuMat 中//    cv::Mat cpuData;//    gpuData.download(cpuData);  // 将 GPU 数据下载到 CPU 的 cv::Mat 中//    float* data = (float*)cpuData.data;  // 获取 CPU 上的数据指针//}//else { // 在没有启用GPU计算时,直接使用CPU内存中的数据指针//    data = (float*)outputs[0].data;//}//float* data = (float*)outputs[0].data;//************************GPU和CPU的数据交换//cv::UMat umatData = outputs[0].getUMat(cv::ACCESS_READ);//cv::Mat cpuData;//umatData.copyTo(cpuData);//********************************//float* data = (float*)cpuData.data;float* data = (float*)outputs[0].data;float x_factor = modelInput.cols / modelShape.width;float y_factor = modelInput.rows / modelShape.height;std::vector<int> class_ids;std::vector<float> confidences;std::vector<cv::Rect> boxes;for (int i = 0; i < rows; ++i){if (yolov8){float* classes_scores = data + 4;cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);cv::Point class_id;double maxClassScore;minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);if (maxClassScore > modelScoreThreshold){confidences.push_back(maxClassScore);class_ids.push_back(class_id.x);float x = data[0];float y = data[1];float w = data[2];float h = data[3];int left = int((x - 0.5 * w) * x_factor);int top = int((y - 0.5 * h) * y_factor);int width = int(w * x_factor);int height = int(h * y_factor);boxes.push_back(cv::Rect(left, top, width, height));}}else // yolov5{float confidence = data[4];if (confidence >= modelConfidenceThreshold){float* classes_scores = data + 5;cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);cv::Point class_id;double max_class_score;minMaxLoc(scores, 0, &max_class_score, 0, &class_id);if (max_class_score > modelScoreThreshold){confidences.push_back(confidence);class_ids.push_back(class_id.x);float x = data[0];float y = data[1];float w = data[2];float h = data[3];int left = int((x - 0.5 * w) * x_factor);int top = int((y - 0.5 * h) * y_factor);int width = int(w * x_factor);int height = int(h * y_factor);}}}data += dimensions;}std::vector<int> nms_result;cv::dnn::NMSBoxes(boxes, confidences, modelScoreThreshold, modelNMSThreshold, nms_result);std::vector<Detection> detections{};for (unsigned long i = 0; i < nms_result.size(); ++i){int idx = nms_result[i];Detection result;result.class_id = class_ids[idx];result.confidence = confidences[idx];std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> dis(100, 255);result.color = cv::Scalar(dis(gen),dis(gen),dis(gen));result.className = classes[result.class_id];result.box = boxes[idx];detections.push_back(result);}return detections;
}void Inference::loadClassesFromFile()
{std::ifstream inputFile(classesPath);if (inputFile.is_open()){std::string classLine;while (std::getline(inputFile, classLine))classes.push_back(classLine);inputFile.close();}
}void Inference::loadOnnxNetwork()
{net = cv::dnn::readNetFromONNX(modelPath);if (cudaEnabled){std::cout << "\nRunning on CUDA" << std::endl;net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);}else{std::cout << "\nRunning on CPU" << std::endl;net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);}
}cv::Mat Inference::formatToSquare(const cv::Mat& source)
{int col = source.cols;int row = source.rows;int _max = MAX(col, row);cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);source.copyTo(result(cv::Rect(0, 0, col, row)));return result;
}

核心调用功能代码

   //执行视频检测算法和处理bool runOnGPU = false;int deviceId = 0; // 指定要使用的GPU设备的索引cv::cuda::setDevice(deviceId);// 1. 设置你的onnx模型// 注意,在这个例子中类别是硬编码的,'classes.txt'只是一个占位符。Inference inf("D:/C++(2019)/models/static_best.onnx", cv::Size(640, 640), "classes.txt", runOnGPU); // classes.txt 可以缺失// 2. 设置你的输入视频路径std::vector<std::string> videoPaths;videoPaths.push_back("D:/C++(2019)/data/video_good/test_video.mp4");//ui.status->setText("video path:D:/C++(2019)/data/video_good/test_video.mp4");//这里还是硬编码,可以自主选择所有视频列表中的哪些视频进行检测(这里测试第一个视频for (int i = 0; i < 1; ++i){const std::string& videoPath = videoPaths[i];cv::VideoCapture videoCapture(videoPath);if (!videoCapture.isOpened()){ui.status->setText("Failed to open video: ");std::cerr << "Failed to open video: " << videoPath << std::endl;continue;}cv::Mat frame;while (videoCapture.read(frame)){// Inference starts here...std::vector<Detection> output = inf.runInference(frame);int detections = output.size();std::cout << "Number of detections: " << detections << std::endl;for (int i = 0; i < detections; ++i){Detection detection = output[i];cv::Rect box = detection.box;cv::Scalar color = detection.color;//根据类别不同,显示不同的颜色if (detection.class_id == 0) {color = cv::Scalar(0, 255, 0); // 红色 (B, G, R)}else if (detection.class_id == 1) {color = cv::Scalar(0, 0, 255); // 红色 (B, G, R)}else {color = cv::Scalar(255, 0, 0); // 红色 (B, G, R)}// Detection boxcv::rectangle(frame, box, color, 2);// Detection box textstd::string classString = detection.className + ' ' + std::to_string(detection.confidence).substr(0, 4);cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);cv::rectangle(frame, textBox, color, cv::FILLED);cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);}cv::namedWindow("Inference", cv::WINDOW_NORMAL); // 创建具有可调整大小功能的窗口cv::imshow("Inference", frame); // 在窗口中显示图像if (cv::waitKey(1) == 27) // Press Esc to exitbreak;}cv::destroyAllWindows();}

三、调用GPU-OpenCV的编译问题

你会发现,从官网上下下来的opencv4.8.1,配置到vs环境中,就算你把上面核心调用功能中的代码runOnGPU设置为了true,打开任务管理器,还是发现没有调用GPU,这是为什么呢?

我们看看GPT的回答:
当使用OpenCV部署模型时,无法调用GPU可能有以下几个原因:

  • OpenCV版本: 确保你使用的OpenCV版本是支持GPU的。OpenCV 4.2及以上版本在DNN模块中提供了对GPU的支持。
  • GPU支持的构建: OpenCV需要使用具有GPU支持的构建版本。如果你是从预编译的二进制文件安装的OpenCV,可能没有包含GPU支持。你可能需要从源代码编译OpenCV,并确保在编译时启用了CUDA支持。
  • CUDA和cuDNN: 为了让OpenCV利用GPU加速,你的系统上应该安装了NVIDIA的CUDA Toolkit和cuDNN库,并且它们应该与你的GPU兼容。
    模型兼容性:并非所有的深度学习模型都能在GPU上运行。确保你的模型支持GPU加速。
  • 代码配置: 在代码中,你需要明确指定使用GPU。例如,在OpenCV的DNN模块中,你可以使用cv::dnn::Net::setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA)和cv::dnn::Net::setPreferableTarget(cv::dnn::DNN_TARGET_CUDA)来指定后端和目标。
  • GPU资源: 如果你的系统中有多个GPU或者GPU资源被其他应用占用,OpenCV可能无法访问它们。你可能需要配置你的代码或环境,以确保正确的GPU被选中和使用。
  • 操作系统和驱动程序: 确保你的操作系统和NVIDIA驱动程序是最新的,并且与你的CUDA Toolkit版本兼容。
  • 硬件限制: 你的GPU硬件必须支持CUDA,这意味着它应该是NVIDIA的GPU。并非所有的NVIDIA GPU都支持CUDA,而且较老的型号可能不支持最新版本的CUDA Toolkit。

如果你确定了以上各项都已满足,但仍然无法使用GPU,你可能需要检查你的具体代码配置或查阅OpenCV的官方文档以获取更多信息。在某些情况下,可能还需要查看错误日志或使用调试工具来确定问题所在。

说到底一句话核心就是:官网下载下来的都是预编译的Opencv,预编译的版本不支持GPU!需要你自己手动进行编译!!!!

你看到这个时候可能跟我当时有一样的疑问:为什么官方非要弄一个预编译版本呢?直接加上支持GPU的不可以吗?

我们再来看GPT的回答:

预编译的OpenCV二进制文件通常不包括GPU支持,原因包括:

  • 兼容性问题: 预编译的二进制文件是为了在尽可能多的系统上运行,而不是针对特定的硬件或软件配置。因为CUDA和GPU加速是NVIDIA专有的技术,只适用于NVIDIA的GPU,预编译的OpenCV版本需要在没有NVIDIA硬件的系统上也能工作。
  • 版本控制: CUDA和cuDNN有多个版本,与特定版本的NVIDIA GPU驱动和硬件兼容。预编译的OpenCV需要用户自己根据他们的具体环境编译CUDA支持。
  • 文件大小: 包括GPU支持的预编译二进制文件会显著增大,因为它们需要包含额外的库和资源。为了减少下载和安装时间,通常不包含这些额外的组件。
    许可和法律问题:CUDA是NVIDIA的专有技术,与之相关的分发可能涉及特定的许可和法律限制。
  • 用户需求: 并非所有OpenCV用户都需要GPU支持。许多用户在不需要进行大规模图像处理或机器学习任务的情况下使用OpenCV,这时CPU运行可能就足够了。

因此,预编译的OpenCV版本通常不包括对GPU的支持,以保持最大的通用性和便捷性。需要GPU加速的用户可以根据自己的具体硬件配置从源代码编译OpenCV,并启用CUDA支持。

说到底,核心问题还是前面两点。因为各个用户的硬件各种各样,要想调用GPU,就必须和具体场景兼容。像我们后面使用Tensorrtonnxruntime进行调用GPU时,也要根据自己的硬件选择合适的CUDACUDNN,这个原理是一样的!

所以,那我们就编译一下呗,编译一下一个支持当前硬件水平的OpenCV呗。

没错,当时心高气傲的我也是这么说的,知道我第四天还以为各种报错而编译不出来gpu版本的opencv时,我终于像它低头了!

这里,关于网上编译gpu版本的opencv的教程很多,我也试了很多(虽然最后我也没编译成功)。下面是我当时根据各个教程以及实验总结出来的步骤:

OpenCV+CUDA进行编译(cmake+vs2019)

  • Step1:下载好OpenCV4.8.1的源码、OpenCV4.8.1 contrib
  • Step2:放入cmake:
    • 第一次configure
    • 第2次configure后:
    • 搜索CUDA,勾选三个;
    • 搜索world,不用勾选BUILD_opencv_world(后续用Vs编译时会导致不正确:无法引入opencv_worldxxx.lib文件)
    • 搜索MOULDELS,把value改成OpenCV4.8.1 contrib的moulds路径
    • 输入SET,查找OPENCV_GENERATE_SETUPVARS,不勾选
    • 输入test查找OPENCV_PERF_TESTS、BUILD_TESTS\BUILD_opencv_tests,不勾选
    • 输入java和JAVA,取消相应勾选
    • 输入python,取消相应勾选
    • 搜索Nonfree,这个控制是否编译扩展库,如果使用需要勾选
    • 第3次configure后:
    • 再次搜索cuda,将CUDA_arch_bin中的显卡算例改成自己的显卡算力,并且勾选enable_fast_math,取消勾选rgbd了
    • 然后configure,然后再generate,再open project
    • 在vs2019中先双击CMakeTargets目录先的ALL_BUILD右键点击·生成·,然后漫长等待之后再点击同样目录下的INSTALL右键生成

Tips:这处坑点挺多的,比如有文件下不下来要手动下载,最好对参考几个博客再开始用cmake编译!!!

最后,是我的同学在第四天终于编译成功!但是呢,我用的时候却出现问题!

现象就是一个检测结果也没有!
后来我们一步一步debug,在源码发现了问题:我们现在在c++环境下用opencv可以运行yolov8n. onnx模型,而且推理结果是准确的。但是启用cuda之后模型输出结果有问题,net.forward(outputs, net.getUnconnectedOutLayersNames());的结果outputs[0]的data总是0,导致推理结果不准确,好像是cpu到gpu之间数据传输的问题,网上也没搜到。

这个问题也不了了之了,不知道是同学编译的opencv有问题,还是其他的问题!因为在网上也没有找到答案…

另外,在这期间我们还用onnxruntime部署了,可喜可贺的是终于能成功调用gpu了!但是!精度特别差,很多在python版本的yolo里面跑,几乎92+%的置信度,在onnxruntime部署的根本没检测出来!!!由于知识能力有限,我也不知道是神经网络的问题还是其他的问题,这个问题也搁置了。。。

关于onnxruntime部署的我会再写一篇博客详细介绍一下,以及代码!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/715934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黑马JavaWeb开发跟学(三)Web前端开发Vue-Element

黑马JavaWeb开发跟学三.Web前端开发Vue-Element 1 Ajax1.1 Ajax介绍1.1.1 Ajax概述1.1.2 Ajax作用1.1.3 同步异步 1.2 原生Ajax1.3 Axios1.3.1 Axios的基本使用1.3.2 Axios快速入门1.3.3 请求方法的别名1.3.4 案例 2 前后台分离开发2.1 前后台分离开发介绍2.2 YAPI2.2.1 YAPI介…

【GPU驱动开发】-mesa简介

前言 不必害怕未知&#xff0c;无需恐惧犯错&#xff0c;做一个Creator&#xff01; 一、mesa介绍 Mesa 是一个开源的3D图形库&#xff0c;它实现了多种图形API&#xff0c;包括 OpenGL、Vulkan 和 OpenCL。Mesa 的目标是提供一个开源、跨平台的图形库&#xff0c;使得开发者…

ABAP - SALV教程08 列设置热点及绑定点击事件

实现思路&#xff1a;将列设置成热点&#xff0c;热点列是可点击的&#xff0c;再给SALV实例对象注册点击事件即可&#xff0c;一般作用于点击单号跳转到前台等功能 "设置热点方法METHODS:set_hotspot CHANGING co_alv TYPE REF TO cl_salv_table...."事件处理方法M…

合宙esp32-c3 进入深度睡眠无法唤醒解决一例

手贱&#xff0c;昨天收到了嘉立创最新的esp32 s3,想测试一下电流功耗&#xff0c;于是顺便测试了一下以前的合宙esp32 c3 无串口芯片的版本 打算对比一下c3和s3的功耗相差多少&#xff0c;结果把自己玩死了&#xff1a; void setup() {esp_deep_sleep_start();// esp_light_s…

oppo手机备忘录记录怎么转移到华为手机?

oppo手机备忘录记录怎么转移到华为手机?使用oppo手机已经有三四年了&#xff0c;因为平时习惯&#xff0c;在手机系统的备忘录中记录了很多重要的笔记&#xff0c;比如工作会议的要点、读书笔记、购物清单、朋友的生日提醒等。这些记录对我来说非常重要&#xff0c;我可以通过…

2000-2021年300+地级市进出口总额数据

2000-2021年300地级市进出口总额数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;进出口总额 3、单位&#xff1a;万美元 4、来源&#xff1a;城市年鉴、各省年鉴、城市公报、2021年为城市统计年鉴中进口额出口额加总之后换算成万美元&#xff0c;已尽最大可能进行…

1.亿级积分数据分库分表:总体方案设计

项目背景 以一个积分系统为例&#xff0c;积分系统最核心的有积分账户表和积分明细表&#xff1a; 积分账户表&#xff1a;每个用户在一个品牌下有一个积分账户记录&#xff0c;记录了用户的积分余额&#xff0c;数据量在千万级积分明细表&#xff1a;用户每次积分发放、积分扣…

数据结构——Top-k问题

Top-k问题 方法一&#xff1a;堆排序&#xff08;升序&#xff09;&#xff08;时间复杂度O(N*logN)&#xff09;向上调整建堆&#xff08;时间复杂度&#xff1a;O(N * logN) &#xff09;向下调整建堆&#xff08;时间复杂度&#xff1a;O(N) &#xff09;堆排序代码 方法二&…

LeetCode---386周赛

题目列表 3046. 分割数组 3047. 求交集区域内的最大正方形面积 3048. 标记所有下标的最早秒数 I 3049. 标记所有下标的最早秒数 II 一、分割数组 这题简单的思维题&#xff0c;要想将数组分为两个数组&#xff0c;且分出的两个数组中数字不会重复&#xff0c;很显然一个数…

人工智能指数报告2023

人工智能指数报告2023 主要要点第 1 章 研究与开发第 2 章 技术性能第 3 章 人工智能技术伦理第 4 章 经济第 5 章 教育第 6 章 政策与治理第 7 章 多样性第 8 章 舆论 人工智能指数是斯坦福大学以人为本的人工智能研究所&#xff08;HAI&#xff09;的一项独立倡议&#xff0c…

Java 石头剪刀布小游戏

一、任务 编写一个剪刀石头布游戏的程序。程序启动后会随机生成1~3的随机数&#xff0c;分别代表剪刀、石头和布&#xff0c;玩家通过键盘输入剪刀、石头和布与电脑进行5轮的游戏&#xff0c;赢的次数多的一方为赢家。若五局皆为平局&#xff0c;则最终结果判为平局。 二、实…

KubeSphere平台安装系列之三【Linux多节点部署KubeSphere】(3/3)

**《KubeSphere平台安装系列》** 【Kubernetes上安装KubeSphere&#xff08;亲测–实操完整版&#xff09;】&#xff08;1/3&#xff09; 【Linux单节点部署KubeSphere】&#xff08;2/3&#xff09; 【Linux多节点部署KubeSphere】&#xff08;3/3&#xff09; **《KubeS…

新一代电话机器人开源PHP源代码

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码 项目地址&#xff1a;https://gitee.com/ddrjcode/robotphp 代理商页面演示地址 http://119.23.229.15:8080 用户名&#xff1a;c0508 密码&#xff1a;123456 包含 AI外呼管理&#xff0c;话术管理&#xff0c;CR…

每日一题 — 复写零

1089. 复写零 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 首先找到最后一个复写的数&#xff1a; 双指针算法&#xff1a; 1、先判断 cur 位置上的值 2、然后决定 dest 移动一步还是两步 3、然后判断 dest 是否到终点了 4、最后 cur 处理越界的情况 arr[n-1] …

思维题(蓝桥杯 填空题 C++)

目录 题目一&#xff1a; ​编辑 代码&#xff1a; 题目二&#xff1a; 代码&#xff1a; 题目三&#xff1a; 代码&#xff1a; 题目四&#xff1a; 代码&#xff1a; 题目五&#xff1a; 代码&#xff1a; 题目六&#xff1a; 代码七&#xff1a; 题目八&#x…

用python和pygame库实现刮刮乐游戏

用python和pygame库实现刮刮乐游戏 首先&#xff0c;确保你已经安装了pygame库。如果没有安装&#xff0c;可以通过以下命令安装&#xff1a; pip install pygame 示例有两个。 一、简单刮刮乐游戏 准备两张图片&#xff0c;一张作为背景bottom_image.png&#xff0c;一张作…

Leetcoder Day35| 动态规划part02

62.不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff…

Android 显示系统框架

一.FrameBuffer FrameBuffer 介绍&#xff1a; FrameBuffer中文译名为帧缓冲驱动&#xff0c;它是出现在2.2.xx内核中的一种驱动程序接口。主设备号为29&#xff0c;次设备号递增。 Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer机制模仿显卡的功能…

Day11:信息打点-Web应用企业产权指纹识别域名资产网络空间威胁情报

目录 Web信息收集工具 业务资产-应用类型分类 Web单域名获取-接口查询 Web子域名获取-解析枚举 Web架构资产-平台指纹识别 思维导图 章节知识点&#xff1a; Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用…

dart中的事件队列与微任务

dart在每个事件循环中&#xff0c;会先执行同步任务代码&#xff0c;然后分别检查两个任务队列&#xff1a;微任务队列和事件队列。dart总是先执行微任务队列中的代码&#xff0c;然后才是事件队列中的代码。当两个队列中的任务都执行完成后&#xff0c;线程进入休眠状态&#…