使用Openvino部署C++的Yolov5时类别信息混乱问题记录

news2024/11/15 8:36:39

使用Openvino部署C++的Yolov5时类别信息混乱问题记录

简单记录一下。

一、问题描述

问题描述:在使用Yolov5的onnx格式模型进行C++的Openvino进行模型部署时,通过读取classes.txt获得类别信息时,出现模型类别混乱,或者说根本就不给图像赋予类别标签的情况。
在这里插入图片描述

二、解决办法

通过debug程序,发现是读取txt文件时的问题,读入txt文件时,会读出几行空白的数据。
在这里插入图片描述
最终发现原因是classes.txt文件中,多了几个空白的换行。需要尽量留意,删除掉空白的换行

三、部署测试代码

三个部分,需要提取配置好opencv和openvino

1.main.cpp
#include <opencv2/opencv.hpp>  
#include <boost/filesystem.hpp>  
#include <iostream>  
#include <string>  
#include "yolov5vino.h"

namespace fs = boost::filesystem;
YOLOv5VINO yolov5VINO;

int main() {
 

    std::string sourceDir = "D:/work/C++Code/Yolov5Openvino/Test/testimgs";
    std::string destDir = "D:/work/C++Code/Yolov5Openvino/Test/output";
    std::string ModelPath = "D:/work/C++Code/Yolov5Openvino/Test/best.onnx";
    std::string ClassesPath = "D:/work/C++Code/Yolov5Openvino/Test/classes.txt";


    yolov5VINO.init(ModelPath, ClassesPath);

    // 确保目标目录存在  
    if (!fs::exists(destDir)) {
        fs::create_directories(destDir);
    }

    // 遍历源目录中的所有文件  
    for (fs::directory_iterator end, dir(sourceDir); dir != end; ++dir) {
        if (fs::is_regular_file(dir->status())) {
            std::string filePath = dir->path().string();
            std::string fileName = dir->path().filename().string();

            // 读取图片  
            cv::Mat img = cv::imread(filePath, cv::IMREAD_COLOR);
            if (img.empty()) {
                std::cerr << "Failed to load image: " << filePath << std::endl;
                continue;
            }

            
            std::vector<Detection> outputs;
            yolov5VINO.detect(img, outputs);
            yolov5VINO.drawRect(img, outputs);

            // 构造目标文件路径  
            std::string destFilePath = destDir + "/" + fileName;

            // 保存图  
            if (!cv::imwrite(destFilePath, img)) {
                std::cerr << "Failed to save image: " << destFilePath << std::endl;
            }
            else {
                std::cout << "Saved image: " << destFilePath << std::endl;
            }
        }
    }

    return 0;
}
2.Yolv5nivo.h
#pragma once
#ifndef YOLOV5VINO_H
#define YOLOV5VINO_H
#include <fstream>
#include <opencv2/opencv.hpp>
#include <inference_engine.hpp>
#define NOT_NCS2
using namespace std;
using namespace InferenceEngine;

struct Detection
{
    int class_id;
    float confidence;
    cv::Rect box;
};

class YOLOv5VINO
{
public:
    YOLOv5VINO();
    ~YOLOv5VINO();
    void init(string modelPath, string classPath);
    cv::Mat formatYolov5(const cv::Mat& source);
    void detect(cv::Mat& image, vector<Detection>& outputs);
    void drawRect(cv::Mat& image, vector<Detection>& outputs);
    void loadClassList(string classPath);
private:
    float m_scoreThreshold = 0.5;
    float m_nmsThreshold = 0.6;
    float m_confThreshold = 0.5;

    //"CPU","GPU","MYRIAD"
#ifdef NCS2
    const std::string m_deviceName = "MYRIAD";
    const std::string m_modelFilename = "configFiles/yolov5sNCS2.xml";
#else
    const std::string m_deviceName = "CPU";
    const std::string m_modelFilename = "best.onnx";
#endif // NCS2
    const std::string m_classfile = "classes.txt";
    size_t m_numChannels = 3;
    size_t m_inputH = 416;
    size_t m_inputW = 416;
    size_t m_imageSize = 0;
    std::string m_inputName = "";
    std::string m_outputName = "";
    const vector<cv::Scalar> colors = { cv::Scalar(255, 255, 0), cv::Scalar(0, 255, 0), cv::Scalar(0, 255, 255), cv::Scalar(255, 0, 0) };

    InferRequest m_inferRequest;
    Blob::Ptr m_inputData;
    

public:
    vector<std::string> m_classNames;
    //const vector<std::string> m_classNames = { "138A","8151","B1100","JH8161","RE85","S22","KA90","T105","TX2295" };
   // const vector<string> m_classNames = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light" };
};
#endif
3.yolov5vino.cpp
#include "yolov5vino.h"

YOLOv5VINO::YOLOv5VINO()
{
}

YOLOv5VINO::~YOLOv5VINO()
{
}


void YOLOv5VINO::init(string modelPath, string classPath)
{
    InferenceEngine::Core ie;
    InferenceEngine::CNNNetwork network = ie.ReadNetwork(modelPath);
    InputsDataMap inputs = network.getInputsInfo();
    OutputsDataMap outputs = network.getOutputsInfo();
    for (auto item : inputs)
    {
        m_inputName = item.first;
        auto input_data = item.second;
        input_data->setPrecision(Precision::FP32);
        input_data->setLayout(Layout::NCHW);
        input_data->getPreProcess().setColorFormat(ColorFormat::RGB);
        std::cout << "input name = " << m_inputName << std::endl;
    }

    for (auto item : outputs)
    {
        auto output_data = item.second;
        output_data->setPrecision(Precision::FP32);
        m_outputName = item.first;
        std::cout << "output name = " << m_outputName << std::endl;
    }
    auto executable_network = ie.LoadNetwork(network, m_deviceName);
    m_inferRequest = executable_network.CreateInferRequest();

    m_inputData = m_inferRequest.GetBlob(m_inputName);
    m_numChannels = m_inputData->getTensorDesc().getDims()[1];
    m_inputH = m_inputData->getTensorDesc().getDims()[2];
    m_inputW = m_inputData->getTensorDesc().getDims()[3];
    m_imageSize = m_inputH * m_inputW;

   loadClassList(classPath);
   
}


void YOLOv5VINO::loadClassList(string classPath)
{
    std::ifstream ifs(classPath);
    std::string line;
    while (getline(ifs, line))
    {
        m_classNames.push_back(line);
    }
    ifs.close();
}

cv::Mat YOLOv5VINO::formatYolov5(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;
}


void YOLOv5VINO::detect(cv::Mat& image, vector<Detection>& outputs)
{
    cv::Mat input_image = formatYolov5(image);
    cv::Mat blob_image;
    cv::resize(input_image, blob_image, cv::Size(m_inputW, m_inputH));
    cv::cvtColor(blob_image, blob_image, cv::COLOR_BGR2RGB);

    float* data = static_cast<float*>(m_inputData->buffer());
    for (size_t row = 0; row < m_inputH; row++) {
        for (size_t col = 0; col < m_inputW; col++) {
            for (size_t ch = 0; ch < m_numChannels; ch++) {
#ifdef NCS2
                data[m_imageSize * ch + row * m_inputW + col] = float(blob_image.at<cv::Vec3b>(row, col)[ch]);
#else
                data[m_imageSize * ch + row * m_inputW + col] = float(blob_image.at<cv::Vec3b>(row, col)[ch] / 255.0);
#endif // NCS2
            }
        }
    }
    auto start = std::chrono::high_resolution_clock::now();

    m_inferRequest.Infer();
    auto output = m_inferRequest.GetBlob(m_outputName);
    const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());

    //维度信息
    const SizeVector outputDims = output->getTensorDesc().getDims();//1,6300[25200],9
    float x_factor = float(input_image.cols) / m_inputW;
    float y_factor = float(input_image.rows) / m_inputH;
    float* dataout = (float*)detection_out;
    const int dimensions = outputDims[2];
    const int rows = outputDims[1];
    vector<int> class_ids;
    vector<float> confidences;
    vector<cv::Rect> boxes;
    for (int i = 0; i < rows; ++i)
    {
        float confidence = dataout[4];
        if (confidence >= m_confThreshold)
        {
            float* classes_scores = dataout + 5;
            cv::Mat scores(1, m_classNames.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 > m_scoreThreshold)
            {
                confidences.push_back(confidence);
                class_ids.push_back(class_id.x);

                float x = dataout[0];
                float y = dataout[1];
                float w = dataout[2];
                float h = dataout[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));
            }
        }
        dataout += dimensions;
    }
    vector<int> nms_result;
    cv::dnn::NMSBoxes(boxes, confidences, m_scoreThreshold, m_nmsThreshold, nms_result);
    for (int i = 0; i < nms_result.size(); i++)
    {
        int idx = nms_result[i];
        Detection result;
        result.class_id = class_ids[idx];
        result.confidence = confidences[idx];
        result.box = boxes[idx];
        outputs.push_back(result);
    }
    std::sort(outputs.begin(), outputs.end(), [](const Detection& a, const Detection& b) {
        return a.confidence > b.confidence; // 从大到小排序  
        });
}

void YOLOv5VINO::drawRect(cv::Mat& image, vector<Detection>& outputs)
{
    int detections = outputs.size();
    for (int i = 0; i < detections; ++i)
    {
        auto detection = outputs[i];
        auto box = detection.box;
        auto classId = detection.class_id;
        const auto color = colors[classId % colors.size()];
        rectangle(image, box, color, 3);

        rectangle(image, cv::Point(box.x, box.y - 40), cv::Point(box.x + box.width, box.y), color, cv::FILLED);
        putText(image, m_classNames[classId].c_str(), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 1.5, cv::Scalar(0, 0, 0), 2);
    }

}

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

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

相关文章

【原创】java+swing+mysql学分管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 开发背景&#xff1a; 随着信息技术的…

嵌入式单片机中在线调试工具使用方法

大家好,相信很多小伙伴都听说过,或者用过SystemView这款工具。 它是一个可以在线调试嵌入式系统的工具,它可以分析RTOS有哪些中断、任务执行了,以及这些中断、任务执行的先后关系。 还可以查看一些内核对象持有和释放的时间点,比如信号量、互斥量、事件、消息队列等,这在…

Vue3 form表单赋值后,input输入框无法输入

1.使用reactive初始化数据: 需要用一个对象包裹数据,使其变成响应式数据 Form表单及JS中的使用都需要 “paramr.formUser” 进行调用 原因: 使用reactive生成的响应式数据&#xff0c;在直接赋值时把响应式数据给替换为了普通数据了&#xff0c;导致无法监听数据的变化。 2. …

Flutter——权威常用组件demo代码开源

背景 自学的过程中&#xff0c;并记录下来仅供大家一起学习 开源地址&#xff1a;https://github.com/z244370114/flutter_demo

软件测试经典面试题,助你面试加分

一 时间紧迫的情况下&#xff0c;如何做好测试工作&#xff1f; 对需求要明确&#xff0c;对需求的优先级也要明确&#xff0c;在项目的过程中就可以少做变更的工作。减少测试的工作量。 由资深测试工程师对测试用例进行设计&#xff0c;并进行用例评审。 用例要重点覆盖主要…

Cocos Creator2D游戏开发(10)-飞机大战(8)-计分和结束

现在游戏基本能完了, 飞机能发射子弹,打了敌机,敌机也能炸; 接下来要做计分了; 步骤: 搞出一个lable让lable显示炸了多少飞机 开搞: ①创建一个Lable标签 ② root.ts文件 添加 property(Label) player_score: Label; // 标签属性 标签绑定 ③ 代码添加 注册 然后回调 contac…

iOS弱引用

背景&#xff1a;在面试过程中被问到如果两个对象已经发生循环引用了&#xff0c;该如何将他们剪断&#xff0c;在运行态的时候。 由于这个场景比较抽象&#xff0c;我理解面试官是希望我通过运行时的方法和方式来解决循环引用。 解决方案一: 重写setter用关联对象来实现wea…

【C++11】:右值引用移动语义完美转发

目录 前言一&#xff0c;左值引用和右值引用二&#xff0c;左值引用与右值引用比较三&#xff0c;探索引用的底层四&#xff0c;右值引用使用场景和意义4.1 解决返回值问题4.2 STL容器插入接口的改变 五&#xff0c;移动语义六&#xff0c;完美转发6.1 模板中的&& 万能…

【动态路由协议】RIP

一、前导知识 动态路由协议分类&#xff1a; 1.IGP(内部网关协议&#xff0c;位于同一个自治系统内) 1.1距离矢量路由协议 RIP&#xff08;距离矢量路由&#xff09; 1.2链路状态路由协议 OSPF&#xff08;开放式最短路径优先&#xff09; IS-IS&#xff08;中间系统到中间系统…

Xinstall新玩法:Web直接打开App,用户体验再升级!

在移动互联网时代&#xff0c;App已成为我们日常生活中不可或缺的一部分。然而&#xff0c;在App推广和运营过程中&#xff0c;许多开发者面临着从Web端引流到App的难题。这时&#xff0c;Xinstall作为国内专业的App全渠道统计服务商&#xff0c;提供了一种创新的解决方案——通…

【前端 21】Vue Router路由配置

Vue Router路由配置 在Vue.js项目中&#xff0c;Vue Router是官方提供的路由管理器&#xff0c;用于构建单页面应用&#xff08;SPA&#xff09;。它允许我们通过不同的URL访问不同的页面组件&#xff0c;而无需重新加载页面。下面&#xff0c;我将详细介绍如何在Vue项目中配置…

【研发日记】Matlab/Simulink技能解锁(十二)——Stateflow中的两种状态机嵌套对比

文章目录 前言 项目背景 两级状态机 函数状态机 分析和应用 总结 参考资料 前言 见《【研发日记】Matlab/Simulink技能解锁(七)——两种复数移相算法》 见《【研发日记】Matlab/Simulink技能解锁(八)——分布式仿真》 见《【研发日记】Matlab/Simulink技能解锁(九)——基…

将 HuggingFace 模型转换为 GGUF 及使用 ollama 运行 —— 以 Qwen2-0.5B 为例

前言 最近&#xff0c;阿里发布了Qwen2的系列模型&#xff0c;包括0.5B, 1.5B, 7B, 57B-A14B 和 72B&#xff0c;中英文效果都很好。 因为模型太新&#xff0c;目前还没有 GGUF 版本可以下载&#xff0c;于是转下GGUF&#xff0c;并分享转换教程。 什么是 GGUF&#xff1f; …

[VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建

文章目录 VS Code扩展机制项目搭建创建UI元素活动栏按钮主边栏视图主边栏工具栏按钮侧边栏右键菜单编辑器右键菜单 项目地址 [VS Code扩展]写一个代码片段管理插件&#xff08;一&#xff09;&#xff1a;介绍与界面搭建[VS Code扩展]写一个代码片段管理插件&#xff08;二&…

Io.net系统概述-核心功能;Io,net自动匹配资源与任务;两种令牌:IO和IOSD;

目录 Io.net 一、系统概述 二、核心功能 三、经济系统 四、产品与服务 五、团队与融资 六、市场前景与竞争优势 Io,net自动匹配资源与任务 一、动态资源分配机制 二、高级算法自动匹配资源与任务 三、用户界面与反馈机制 两种令牌:IO和IOSD。简单举例说明 $IO令牌…

2024四大硬盘数据恢复工具推荐!

不知道你有没有遇到过这种情况&#xff0c;电脑里的重要文件突然就不见了&#xff0c;可能是不小心删了&#xff0c;或者是硬盘出了点小问题。这时候&#xff0c;下面这几个好用的硬盘数据恢复工具就能帮你解决问题&#xff01; 一、福昕数据恢复 链接&#xff1a;www.pdf365…

【从英文中重建数字】python刷题记录

R2-字符串 目录 解简单方程法 线性代数法 ps: 就是从里面找出one,two,zero,---nine 想到哈希表,key代表单词&#xff0c;value代表0---9 用t表示单词&#xff0c;那不就是t在s中的查找问题了吗 但这样显然有些麻烦&#xff0c;在于t是不确定的,t需要遍历一遍keys()&…

万物分割(Segment Anything Model)C++模型推理部署

概述 SAM 是一种先进的人工智能模型&#xff0c;已经证明了在分割复杂和多样化图像方面具有优异的表现。该模型是计算机视觉和图像分割领域的一个重大突破。 SAM 的架构旨在处理各种图像分割任务&#xff0c;包括对象检测、实例分割和全景分割。这意味着该模型可以应用于各种用…

2024年Google Play上架指南:开发者账号与上包环境防关联

移动应用市场瞬息万变&#xff0c;成功上架Google Play商店无疑是每一位开发者的重要目标。然而&#xff0c;要确保应用程序顺利通过审核并获得持久的上架资格&#xff0c;开发者需要格外重视账号注册和上包环境管理这两个关键环节。 近年来&#xff0c;Google不断加强对开发者…

vtk2three之用three绘制vtk的Calculator公式

Calculator公式 vtk里面可以用这个过滤器filter&#xff0c;来绘制一个公式的点阵&#xff0c;想着其实可以把这个作为第一个切入点来把vtk里面的数据源引入到threejs里面&#xff0c;把threejs当作一个render&#xff0c;dataSource就是来自于这个vtk&#xff0c;下面先上一个…