【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 };//整形变量用来存储检测到的目标的类别,默认值为0
    std::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 box
                cv::rectangle(frame, box, color, 2);
                // Detection box text
                std::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 exit
                break;
        }
        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部署的我会再写一篇博客详细介绍一下,以及代码!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 基础入门 基础简介

1. 观察App运行日志 2.Android 开发设计的编程语言 koltin Java c c 3.工程目录结构 4.Gradle 5.build.gradle 文件解析 plugins {id("com.android.application")//用了哪些插件 主配置文件版本控制 所以这里不用写版本 }android {namespace "com.tiger.myap…

C#入门:简单数据类型和强制类型转换

本文由 简悦 SimpRead 转码&#xff0c; 原文地址 mp.weixin.qq.com 本期来讲讲 unity 的脚本语言 —C#&#xff0c;C# 的简单数据类型及范围和强制类型转化的方法。这可是 unity 游戏开发必备技能。 1. 简单数据类型 各个类型的范围&#xff1a; byte -> System.Byte (字节…

STM32利用标准库编写程序proteus仿真流水灯

首先就是建立一个proteus工程&#xff0c;导入元器件画图&#xff1a; 接下来就是下载我已经都复制好的工程&#xff0c;下载后直接解压缩就能用&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Nx5p3Tif6eHBIVkcPfsj9w?pwd1234 提取码&#xff1a;1234 解压后打开…

Ps:快照

“历史记录” History面板可分为快照区和历史记录状态区两个部分。 Photoshop 的快照 snapshot功能允许用户保存当前工作状态的完整副本&#xff0c;这包括图像的所有图层&#xff08;包括图层可见性&#xff09;、图层样式、选区以及颜色模式、位深度等其他属性。 通过创建当前…

《猛兽派对》好玩吗值得买吗?苹果电脑也能装《猛兽派对》吗?猛兽派对好友通行证 动物派对 猛兽对战游戏

目录 一、《猛兽派对》好玩吗&#xff1f; 游戏玩法&#xff1a; 物理引擎&#xff1a; 关卡设计&#xff1a; 游戏特色&#xff1a; 评价&#xff1a; 荣誉&#xff1a; 二、苹果电脑也能装《猛兽派对》吗&#xff1f; 第1步&#xff1a;下载并安装CrossOver这款软件…

【python】1.python3.12.2和pycharm社区版的安装指南

欢迎来CILMY23的博客喔&#xff0c;本篇为【python】1.python3.12.2和pycharm社区版的安装指南&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 目录 一、python3.12.2的下载与安装 1.1下载 1.2安装 二、pycharm的安装 2.1下载安装 2…

windows下安装cnpm

cnpm是淘宝团队开发的一个针对中国用户的npm镜像源&#xff0c;它是npm的一个定制版本。由于国外的npm源在国内访问速度较慢&#xff0c;所以cnpm镜像源可以提供更快的下载速度。cnpm的使用方式与npm基本相同&#xff0c;只需将npm替换为cnpm即可。 要想使用cnpm等先安装node.…

SPA首屏加载慢的优化方案

1、什么是首屏加载&#xff1f; 首屏加载时间主要看FCP(First Contentful Paint)这个指标&#xff0c;它指的是浏览器从响应用户输入网址地址&#xff0c;到首屏内容渲染完成的时间&#xff0c;此时整个网页不一定要全部渲染完成&#xff0c;但需要展示当前视窗需要的内容 首…

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

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

ChatGPT-PLUS AI大语言模型源码

ChatGPT-PLUS 是一个开源的 AI 助手解决方案&#xff0c;它采用了 Go、Vue3 和 element-plus 进行开发。这个系统自带运营管理后台&#xff0c;开箱即用&#xff0c;非常方便。它集成了 OpenAI、Azure、ChatGLM、讯飞星火、文心一言等多个平台的大语言模型&#xff0c;还支持 M…

算法入门-二分搜索(长期更新)

文章目录 情景一 : 二分查找情景二 : 找出一个 > num 的最左侧的位置情景三 : 找出一个 < num 的最右侧的位置leetcode 162 :寻找峰值leetcode 69 : x 的平方根 首先来简介一下二分搜索算法,二分搜索是一种每次砍半的算法,最经典的案例当然是我们的二分查找算法,但是大部…

数据结构从入门到精通——顺序表

顺序表 前言一、线性表二、顺序表2.1概念及结构2.2 接口实现2.3 数组相关面试题2.4 顺序表的问题及思考 三、顺序表具体实现代码顺序表的初始化顺序表的销毁顺序表的打印顺序表的增容顺序表的头部/尾部插入顺序表的头部/尾部删除指定位置之前插入数据和删除指定位置数据顺序表元…

PCB学习笔记4——生产过程

1开料&#xff0c;圆角&#xff0c;刨边 2 埋孔&#xff0c;盲孔&#xff0c;过孔 3沉铜 4压膜 5曝光 6显影

了解 SYN Flood 攻击

文章目录&#xff1a; 什么是 SYN Flood 攻击&#xff1f;对网络的影响SYN Flood 发生的迹象如何解决&#xff1f; 什么是 SYN Flood 攻击&#xff1f; SYN Flood&#xff08;SYN 洪水攻击&#xff09;是一种常见的分布式拒绝服务&#xff08;DDoS - Distributed Denial of Se…

【DDD】学习笔记-聚合和聚合根:怎样设计聚合?

今天我们来学习聚合&#xff08;Aggregate&#xff09;和聚合根&#xff08;AggregateRoot&#xff09;。 我们先回顾下上一讲&#xff0c;在事件风暴中&#xff0c;我们会根据一些业务操作和行为找出实体&#xff08;Entity&#xff09;或值对象&#xff08;ValueObject&…

Java+SpringBoot+Vue.js全栈实践:手机销售网站开发记

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

YOLOv9有效提点|加入SE、CBAM、ECA、SimAM等几十种注意力机制(一)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文将以SE注意力机制为例&#xff0c;演示如何在YOLOv9种添加注意力机制&#xff01; 《Squeeze-and-Excitation Networks》 SENet提出…

翻硬币 刷题笔记

通过模拟观察 我们发现 按一下会改变相邻两个硬币的状态 将硬币排成一排 从对位置下标为5到下标为7 依次翻其本身和其右边的硬币 对5&#xff0c;6&#xff0c;7操作 操作次数为3 此时我们只改变了硬币5和硬币8的状态 因此 每两处不一样的地方&#xff0c;我们想改变…

Java | vscode如何使用命令行运行Java程序

1.在vscode中新建一个终端 2.在终端中输入命令 javac <源文件>此命令执行后&#xff0c;在文件夹中会生成一个与原java程序同名的.class文件。然后输入如下命令&#xff1a; java <源文件名称>这样java程序就运行成功了。&#x1f607;

递归与递推(蓝桥杯 c++)

目录 题目一&#xff1a; 代码&#xff1a; 题目二: 代码&#xff1a; 题目三&#xff1a; 代码&#xff1a; 题目四&#xff1a; 代码&#xff1a; 题目一&#xff1a; 代码&#xff1a; #include<iostream> #include<cstring> using namespace std; int …