【yolov8部署实战】VS2019+OpenCV环境部署yolov8目标检测模型|含详细注释源码

news2024/11/26 8:18:21

一、前言

之前一阵子一直在做的就是怎么把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部署的我会再写一篇博客详细介绍一下,以及代码!

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

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

相关文章

NOIP2002提高组T2:字符串变换

题目链接 字符串变换 题目描述 已知有两个字串 A , B A,B A,B&#xff0c;及一组字串变换的规则&#xff08;至多 6 6 6个规则&#xff09;: A 1 → B 1 A_1→B_1 A1​→B1​ A 2 → B 2 A_2→B_2 A2​→B2​ … 规则的含义为&#xff1a;在 A A A中的子串 A 1 A_1 A1​…

2024关于idea激活码报This license xxxx has been suspended

HOSTS文件中增加 0.0.0.0 www.jetbrains.com 0.0.0.0 account.jetbrains.com 然后

App原生开发:iOS和Android平台的比较(看这一篇就够了)

引言 移动应用的发展在过去几年里取得了巨大的突破&#xff0c;而原生开发作为构建高性能、富有交互性的应用程序的首选方法&#xff0c;一直占据着重要的地位。在这篇文章中&#xff0c;我们将探讨原生开发在两个主流移动平台——iOS和Android上的关键概念和技术。 概念和重…

JSP语言基础(案例代码)

JSP基本语法 编写一个JSP页面&#xff0c;在该页面中显示当前时间 <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8" import"java.util.*"%> <% page import"java.text.SimpleDateF…

ECMAScript6

课程链接 目录 相关介绍什么是ECMA什么是ECMAScript为什么学习ES6 letconst变量解构赋值模板字符串对象简化写法箭头函数函数参数的默认值rest参数扩展运算符Symbol迭代器生成器函数与调用Promise介绍与基本用法Promise封装读取文件Promise.prototype...then方法Promise.catch…

javascript中的强制类型转换和自动类型转换

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;前端泛海 景天的主页&#xff1a;景天科技苑 文章目录 1.转换函数2.强制类型转换&#xff08;1&#xff09;Number类型强转&…

数字社交时代的引领者:Facebook的元宇宙探索

引言&#xff1a; 在当今数字社交时代&#xff0c;人们的社交方式正在经历着翻天覆地的变化。随着虚拟现实技术的不断发展和元宇宙概念的崛起&#xff0c;社交网络正朝着一个全新的未来迈进。作为全球最大的社交网络平台之一&#xff0c;Facebook正在积极探索元宇宙时代的社交…

串联谐振电路基础知识1

电路图 公式 IU/Zin,其中ZinXLXCR XC&#xff1a;表示为容抗 XL&#xff1a;表示为感抗 R&#xff1a;表示为电阻阻值 特性 电感对越是高频的电流的阻力就会越大&#xff0c;对越是低频的电流的阻力就会越小&#xff0c;感抗的大小是与频率是息息相关的&#xff0c;并且可简单…

Spring事务管理与模板对象

1.事务管理 1.事务回顾 事务指数据库中多个操作合并在一起形成的操作序列 事务的作用 当数据库操作序列中个别操作失败时&#xff0c;提供一种方式使数据库状态恢复到正常状态&#xff08;A&#xff09;&#xff0c;保障数据库即使在异常状态下仍能保持数据一致性&#xff…

时钟显示 html JavaScript

sf.html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>时间</title><script>function showTime(){var timenew Date();var datetime.getDate();var yeartime.getFullYear();var monthtime.getMonth()1;var …

DataGrip 连接 Centos MySql失败

首先检查Mysql是否运行&#xff1a; systemctl status mysqld &#xff0c; 如果显示没有启动则需要启动mysql 检查防火墙是否打开&#xff0c;是否打开3306的端口 sudo firewall-cmd --list-all 如果下面3306没有打开则打开3306端口 publictarget: defaulticmp-block-inver…

推荐书籍《低代码平台开发实践:基于React》—— 提升开发效率,构建优质应用

写在前面 随着数字化转型的深入&#xff0c;企业对应用开发效率和灵活性的要求不断提高。低代码平台作为新兴的软件开发方式&#xff0c;通过可视化界面和预构建组件&#xff0c;极大简化了应用开发流程&#xff0c;降低了技术门槛。基于React的低代码平台以其组件化、响应式和…

解决MySQL 5.7在Redhat 9中启动报错:libncurses.so.5和libtinfo.so.5缺失问题

在使用Linux系统搭建MySQL数据库的过程中&#xff0c;我们往往会遇到各种依赖库的问题&#xff0c;尤其是在安装较旧版本的MySQL时。最近&#xff0c;在RedHat 9&#xff08;rocky linux 9&#xff09;系统上安装MySQL 5.7版本时&#xff0c;我遇到了一个典型的依赖库缺失错误&…

动态规划(算法竞赛、蓝桥杯)--状态压缩DP蒙德里安的梦想

1、B站视频链接&#xff1a;E31 状态压缩DP 蒙德里安的梦想_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; const int N12,M1<<N; bool st[N];//st[i]存储合并列的状态i是否合法 long long f[N][M];//f[i][j]表示摆放第i列&#xff0c;状态为…

常用“树”数据结构

哈夫曼树 在许多应用中&#xff0c;树中结点常常被赋予一个表示某种意义的数值&#xff0c;称为该结点的权。从树的根到任意结点的路径长度(经过的边数)与该结点上权值的乘积&#xff0c;称为该结点的带权路径长度。树中所有叶结点的带权路径长度之和称为该树的带权路径长度&am…

有没有无损格式转换mp3的方法?

随着数字音乐的发展&#xff0c;无损音乐格式如FLAC、APE、WAV等越来越受到音乐爱好者的青睐。无损音乐保证了音乐在传输和存储过程中不损失任何原始信息&#xff0c;从而保留了音乐的原汁原味。但有时&#xff0c;出于设备兼容性、空间节省或其他原因&#xff0c;我们可能需要…

C语言项目实战——贪吃蛇

C语言实现贪吃蛇 前言一、 游戏背景二、游戏效果演示三、课程目标四、项目定位五、技术要点六、Win32 API介绍6.1 Win32 API6.2 控制台程序6.3 控制台屏幕上的坐标COORD6.4 GetStdHandle6.5 GetConsoleCursorInfo6.5.1 CONSOLE_CURSOR_INFO 6.6 SetConsoleCursorInfo6.7 SetCon…

Ubuntu/Linux系统下Redis的基本操作命令

版本查询 redis-server --version # 或者redis-server -v 如上图所示&#xff0c;redis-server的版本为6.0.9,证明redis已经安装完成。 启动Redis服务 启动命令如下&#xff1a; redis-server启动成功如下所示&#xff1a; 启动过程中遇到如下问题时&#xff0c;杀死指定端…

Python Web开发记录 Day6:MySQL(关系型数据库)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 六、MySQL1、MySQL-概述和引入①MySQL是什么&am…

阿里云几核服务器够用?内存多少合适?

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人开发者或中小企业选择轻量应用服务器、ECS经济型e实例&#xff0c;企业用户选择ECS通用算力型u1云服务器、ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网aliyunfuwuqi.com整…