【深度学习】【Opencv】【GPU】python/C++调用onnx模型【基础】

news2024/12/22 22:56:14

【深度学习】【Opencv】【GPU】python/C++调用onnx模型【基础】

提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论

文章目录

  • 【深度学习】【Opencv】【GPU】python/C++调用onnx模型【基础】
  • 前言
  • Python版本OpenCV
    • Windows平台安装OpenCV
    • opencv调用onnx模型
  • C++版本OpenCV_GPU
    • Windows平台编译安装OpenCV
    • opencv调用onnx模型
  • 总结


前言

OpenCV是一个基于BSD许可发行的跨平台计算机视觉和机器学习软件库(开源),可以运行在Linux、Windows、Android和Mac OS操作系统上。可以将pytorch中训练好的模型使用ONNX导出,再使用opencv中的dnn模块直接进行加载使用。
系列学习目录:
【CPU】Pytorch模型转ONNX模型流程详解
【GPU】Pytorch模型转ONNX格式流程详解
【ONNX模型】快速部署
【ONNX模型】多线程快速部署
【ONNX模型】opencv_cpu调用onnx
【ONNX模型】opencv_gpu调用onnx


Python版本OpenCV

Windows平台安装OpenCV

博主在win10环境下装anaconda环境,而后搭建onnx模型运行所需的openCV环境。

# 搭建opencv环境
conda create -n opencv_onnx_gpu python=3.10.9 -y
# 激活环境
activate opencv_onnx_gpu 

博主使用opencv-4.8.0版本,GPU版本不能直接通过pip下载安装进行使用,必须要在本地进行编译。编译过程具体参考博主的博文windows10下opencv4.8.0-cuda Python版本源码编译教程。

import cv2
cv2.__version__

opencv调用onnx模型

随便拷贝一组数据用来测试数据GPU版本相比于CPU版本在速度上的提升。在项目路径下博主拷贝了CAMO数据集。

将PFNet.onnx也拷贝到项目路径下。

使用opencv并调用gpu完成了整个推理流程。

import cv2
import numpy as np
import glob
import os
import time

def readImagesInFolder(folderPath,images):
    fileNames = glob.glob(os.path.join(folderPath, '*.jpg'))
    for fileName in fileNames:
        bgrImage = cv2.imread(fileName, cv2.IMREAD_COLOR)
        if bgrImage is not None:
            rgbImage = cv2.cvtColor(bgrImage, cv2.COLOR_BGR2RGB)
            images.append(rgbImage)

def transformation(image, targetSize, mean, std):
    resizedImage = cv2.resize(image, targetSize, interpolation=cv2.INTER_AREA)
    normalized = resizedImage.astype(np.float32)
    normalized /= 255.0
    normalized -= mean
    normalized /= std
    return normalized

def loadModel(onnx_path):
    net = cv2.dnn.readNetFromONNX(onnx_path)
    return net

def main():
    # 图片存放文件路径
    folderPath = "D:/deeplean_demo/opencv_onnx_gpu/CAMO/c"
    rgbImages = []
    readImagesInFolder(folderPath, rgbImages)
    # 加载ONNX模型
    onnx_path = "D:/deeplean_demo/opencv_onnx_gpu/PFNet.onnx"
    net = loadModel(onnx_path)
    # 设置CUDA为后端
    # net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
    # net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    output_probs = []
    output_layer_names = net.getUnconnectedOutLayersNames()
    # 定义目标图像大小
    target_size = (416, 416)
    # 定义每个通道的归一化参数
    mean = (0.485, 0.456, 0.406) # 均值
    std = (0.229, 0.224, 0.225)  # 标准差
    # 开始计时
    start = time.time()
    for rgb_image in rgbImages:
        # 获取图像的大小
        original_size = (rgb_image.shape[1], rgb_image.shape[0])
        # 图片归一化
        normalized = transformation(rgb_image, target_size, mean, std)
        print(normalized.shape[:2])
        blob = cv2.dnn.blobFromImage(normalized)
        # 将Blob设置为模型的输入
        net.setInput(blob)
        # 运行前向传播
        output_probs = net.forward(output_layer_names)
        # 获取最完整的预测
        prediction = output_probs[3]
        # 预测图变mask
        mask = cv2.resize(np.squeeze(prediction)* 255.0, original_size, interpolation=cv2.INTER_AREA)
    end = time.time()
    # 计算耗时
    elapsed_time = end - start
    # 打印耗时
    print("Elapsed time:", elapsed_time, "seconds")

if __name__ == "__main__":
    main()

gpu模式下250张图片只用了大约13秒。

假设注释掉与gou相关的代码

net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

cpu模式下250张图片就用了大约95秒。


C++版本OpenCV_GPU

Windows平台编译安装OpenCV

博主使用opencv-4.8.0版本,GPU版本不能直接通过官网下载exe进行使用,必须要在本地进行编译。编译过程具体参考博主的博文【windows10下opencv4.8.0-cuda C++版本源码编译教程】。
编译完成后,在输出的文件夹内找到install文件,将其拷贝合适的位置。

博主新建了一个名为opencv_gpu的文件夹,并将install重命名位build放在其中。

打开VS 2019:新建新项目---->空项目---->配置项目---->项目路径以及勾选“将解决方案和项目放在同一目录中---->点击创建。

在解决方案–>源文件–>右键添加新建项。这里暂时可以默认空着不做处理。

设置OpenCV路径:项目---->属性。假设没有新建cpp文件,空项目的属性页就不会存在C/C++这一项目。

添加附加包含目录:Release | x64---->C/C+±—>常规---->附加包含目录。

D:\C++_demo\opencv_gpu\build\x64\vc16\bin
D:\C++_demo\opencv_gpu\build\bin
D:\C++_demo\opencv_gpu\build\include
D:\C++_demo\opencv_gpu\build\include\opencv2

链接器:Release | x64---->链接器---->常规---->附加包含目录。

D:\C++_demo\opencv_gpu\build\x64\vc16\lib

链接器:Release | x64---->链接器---->输入---->附加依赖项。

在D:\C++_demo\opencv_gpu\build\x64\vc16\lib下找到附加依赖项的文件。

opencv_world480.lib

在Release x64模式下测试,将opencv_world480.dll文件复制到自己项目的Release下。

没有Release目录时,需要在Release | x64模式下运行一遍代码,代码部分在下一节提供,读者可以先行新建文件复制代码。

D:\C++_demo\opencv_gpu\build\x64\vc16\bin
===>
D:\C++_demo\opencv_onnx_gpu\x64\Releas


这里博主为了方便安装的是release版本的,读者可以安装debug版本的,流程基本一致,只需要将属性的Release | x64变成Debug | x64,然后附加依赖项由opencv_world480.lib变成opencv_world480d.lib,再将opencv_world480d.dll文件复制到自己项目的Release下。前提是你编译了debug版本oepncv。

opencv调用onnx模型

随便拷贝一组数据用来测试数据GPU版本相比于CPU版本在速度上的提升。在项目路径下博主拷贝了CAMO数据集。

将PFNet.onnx也拷贝到项目路径下。

将python版本的opencv转化成对应的c++版本的,发现输出的效果完全一致,onnx模型可以作为c++的接口来供其他应用调用。

#include <iostream>
#include <string>
#include <vector>
#include<opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
using namespace std;
void readImagesInFolder(const std::string& folderPath, std::vector<cv::Mat>& images)
{
    cv::String path(folderPath + "/*.jpg"); // 这里假设你的图片格式是.jpg,如果是其他格式请相应修改
    std::vector<cv::String> fileNames;
    cv::glob(path, fileNames, true); // 通过glob函数获取文件夹内所有符合格式的文件名
    cv::Mat rgbImage;
    for (const auto& fileName : fileNames)
    {   // 使用imread函数读取图片
        cv::Mat bgrImage = cv::imread(fileName, cv::IMREAD_COLOR); 
         // 图片格式转化bgr-->rgb
        if (!bgrImage.empty())
        {
            cv::cvtColor(bgrImage, rgbImage, cv::COLOR_BGR2RGB);
            images.push_back(rgbImage);
        }
    }
}

cv::Mat transformation(const cv::Mat& image, const cv::Size & targetSize, const cv::Scalar& mean, const cv::Scalar& std) {

    cv::Mat resizedImage;
    //图片尺寸缩放
    cv::resize(image, resizedImage, targetSize, 0, 0, cv::INTER_AREA);
    cv::Mat normalized;
    resizedImage.convertTo(normalized, CV_32F);
    cv::subtract(normalized / 255.0, mean, normalized);
    cv::divide(normalized, std, normalized);
    return normalized;
}
cv::dnn::Net loadModel(const string& onnx_path) {
    cv::dnn::Net net = cv::dnn::readNetFromONNX(onnx_path);
    return net;
}
int main()
{   // 图片存放文件路径
    string folderPath = "D:/C++_demo/opencv_onnx_gpu/CAMO/c";
    std::vector<cv::Mat> rgbImages;
    readImagesInFolder(folderPath, rgbImages);

   // string image_path = "./animal-1.jpg";
    // 加载ONNX模型
    string onnx_path = "D:/C++_demo/opencv_onnx_gpu/PFNet.onnx";
    cv::dnn::Net net = loadModel(onnx_path);
    // 设置CUDA为后端
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
    cv::Mat output_prob;
    std::vector<cv::Mat> output_probs;
    std::vector<cv::String> output_layer_names = net.getUnconnectedOutLayersNames();

    // 定义目标图像大小
    cv::Size targetSize(416, 416);
    // 定义每个通道的归一化参数
    cv::Scalar mean(0.485, 0.456, 0.406); // 均值
    cv::Scalar std(0.229, 0.224, 0.225);  // 标准差

    // 开始计时
    auto start = chrono::high_resolution_clock::now();
    for (const auto& rgbImage : rgbImages) {
        // 获取图像的大小
        cv::Size originalSize(rgbImage.cols, rgbImage.rows);
        //cv::imshow("输入窗口", rgbImage);
        //cv::waitKey(0);
        //cv::destroyAllWindows();
        // 图片归一化
        cv::Mat normalized = transformation(rgbImage, targetSize, mean, std);
        std::cout << normalized.size() << std::endl;
        cv::Mat blob = cv::dnn::blobFromImage(normalized);
        // 将Blob设置为模型的输入
        net.setInput(blob);
        // 运行前向传播
        net.forward(output_probs, output_layer_names);
        // 获取最完整的预测
        cv::Mat prediction = output_probs[3];
        // 预测图变mask
        cv::Mat mask;
        cv::resize(prediction.reshape(1, 416) * 255.0, mask, originalSize, 0, 0, cv::INTER_AREA);
    }
    auto end = std::chrono::high_resolution_clock::now();
    // 计算耗时
    std::chrono::duration<double> elapsed = end - start;
    double elapsedTime = elapsed.count();
    // 打印耗时
    std::cout << "Elapsed time: " << elapsedTime << " seconds" << std::endl;
    return 0;
}

gpu模式下250张图片只用了大约16秒。

假设注释掉与gou相关的代码

net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);

cpu模式下250张图片就用了大约95秒。


总结

尽可能简单、详细的介绍Python和C++下Opencv_GPU调用ONNX模型的流程。

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

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

相关文章

视频怎么压缩?视频太大这样处理变小

在当今时代&#xff0c;视频已经成为了我们日常生活中不可或缺的一部分&#xff0c;然而&#xff0c;视频文件往往非常大&#xff0c;给我们的存储和传输带来了很大的不便&#xff0c;那么&#xff0c;如何有效地压缩视频呢&#xff1f; 一、使用压缩软件 首先我们给大家分享一…

免费下载IEEE标准的途径

工作需要&#xff0c;找出了一种方法 下载 访问ieeexplore&#xff0c;搜索待下载标准&#xff0c;如图 找到自己要下载的标准&#xff0c;点开链接&#xff0c;复制doi&#xff0c;如图 访问scihub&#xff0c;找1个可用连接&#xff0c;搜索doi&#xff0c;下载 查标准是否…

【机器学习】PyTorch-MNIST-手写字识别

文章目录 前言完成效果一、下载数据集手动下载代码下载MNIST数据集&#xff1a; 二、 展示图片三、DataLoader数据加载器四、搭建神经网络五、 训练和测试第一次运行&#xff1a; 六、优化模型第二次优化后运行&#xff1a; 七、完整代码八、手写板实现输入识别功能 前言 注意…

Cesium Vue(一)— 项目初始化配置

1. 创建VUE项目工程 创建项目 vue create cesium-vue配置Vue3 2. 创建vue.config.js文件 const { defineConfig } require(vue/cli-service)// The path to the CesiumJS source code const cesiumSource node_modules/cesium/Source; const cesiumWorkers ../Build/C…

Elasticsearch:什么是大语言模型 (LLMs)?

假设你想参加流行的游戏节目 Jeopardy&#xff08;这是一个美国电视游戏节目&#xff0c;参赛者将获得答案并必须猜测问题&#xff09;。 要参加演出&#xff0c;你需要了解任何事情的一切。 所以你决定在接下来的三年里每天都花时间阅读互联网上的所有内容。 你很快就会意识到…

跨境电商:为民营经济注入新活力

中国的民营经济一直以来都是国家经济发展的中流砥柱&#xff0c;而近年来&#xff0c;跨境电商产业崭露头角&#xff0c;为民营经济注入了新的活力和机遇。本文将探讨跨境电商如何成为中国民营企业的助推引擎&#xff0c;以及其对民营经济的积极影响。 民营经济的支柱地位 中国…

elasticsearch (六)filebeat 安装学习

filebeat 安装&#xff1a;文件节拍快速入门&#xff1a;安装和配置 |文件节拍参考 [7.17] |弹性的 (elastic.co) 解压缩后&#xff0c;以配置nginx日志为例。 Nginx module | Filebeat Reference [7.17] | Elastic filebeat 配置中&#xff0c; - module: nginx access: …

私人服务器可以干嘛

目录 搭建个人网站或博客&#xff1a; 远程桌面&#xff1a; 作为网盘储存&#xff1a; 作为测试和学习环境&#xff1a; 推广产品&#xff1a; 游戏私服(注意,仅限于个人自己单机玩)&#xff1a; 个人服务器可以用于多种用途&#xff0c;以下是一些常见的用途&#xff1a;…

解密zkLogin:探索前沿的Sui身份验证解决方案

由于钱包复杂性导致的新用户入门障碍是区块链中一个长期存在的问题&#xff0c;而zkLogin是其简单的解决方案。通过使用前沿的密码学和技术&#xff0c;zkLogin既优雅又复杂。本文深入探讨了zkLogin的工作原理&#xff0c;涵盖了用户和开发者的安全性方面&#xff0c;并解释了S…

44.日期交叉问题(品牌活动天数计算)

思路分析&#xff1a; &#xff08;1&#xff09;计算表中每一条数据所对应的活动天数days &#xff08;2&#xff09;使用posexplode函数对days炸裂求其索引值index &#xff08;3&#xff09;使用开始日期index补全后面每一个活动日期in_date &#xff08;4&#xff09;按品牌…

Jmeter实现一次登录,多次业务请求(不同线程组间共享cookie和变量)

实现目的 很多时候&#xff0c;在进行性能测试时&#xff0c;需要先登录&#xff0c;然后再对需求的事务进行相关性能测试&#xff0c;此时的登录操作&#xff0c;并不在本次性能测试的范围内&#xff0c;所以我们只需要登录一次&#xff0c;然后获取登录成功后的cookie等&…

回顾 | E³CI效能认知与改进论坛,助力企业研发效能度量和提升

2023年8月&#xff0c;TiD质量竞争力大会组委会和ECI专家委员会成功举办TiD大时段课程“度量驱动研发效能提升”与“ECI效能认知与改进论坛”。与会专家以《ECI软件研发效能度量规范》团体标准为要点&#xff0c;为企业研发效能度量和提升分享诸多实践成果与经验。 《ECI软件研…

浅析ArkTS的起源和演进

1 引言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力&#xff0c;到具备类型系统的高效工程开发能力&#xff0c;再到融合声明式UI、多维状态管理等丰富的应用开发能力&#xff0c;共同组成了相关的演进脉…

二十六、【颜色调整】

文章目录 1、色相/饱和度2、色彩平衡3、曲线4、可选颜色 1、色相/饱和度 色相其实就是颜色的亮度&#xff0c;就是我们往颜色里边加白色&#xff0c;白色越多颜色越淡。饱和度就是我们往颜色里边加黑色&#xff0c;黑色越多颜色越浓。如下图&#xff0c;我们调整拾色器里边的颜…

NAT网关在阿里云的应用

NAT网关&#xff08;Network Address Translation Gateway&#xff09;是一种网络地址转换服务&#xff0c;提供NAT代理&#xff08;SNAT和DNAT&#xff09;能力。NAT是用于在本地网络中使用私有地址&#xff0c;在连接互联网时转而使用全局 IP 地址的技术。NAT实际上是为解决I…

408计算机组成原理需要背的部分

1.第一章 1.1计算机发展历程 1.发展历程&#xff1a;电子管-》晶体管-》中小规模集成电路-》超大规模集成电路 2.系统组成&#xff1a;控制器&#xff0c;运算器&#xff0c;存储器&#xff0c;输入设备&#xff0c;输出设备 3.性能指标(常考部分)&#xff1a; 机器字长&#x…

橙河网络:怎么学习python?

大家好&#xff0c;我是橙河网络&#xff0c;今天聊一聊怎么学习python&#xff1f; 学习Python编程可以采取以下步骤&#xff1a; 1.理解Python基础知识&#xff1a;了解Python的基本语法、数据类型、控制流语句、函数、模块和包等基础知识&#xff0c;这些是Python编程的基…

【LeetCode刷题(数据结构与算法面试题)】:最小高度树

给定一个有序整数数组 元素各不相同且按升序排列 编写一个算法 创建一棵高度最小的二叉搜索树 示例: 给定有序数组: [-10,-3,0,5,9] 一个可能的答案是&#xff1a;[0,-3,9,-10,null,5]&#xff0c;它可以表示下面这个高度平衡二叉搜索树 0 / \ -3 9 / / -10 5 确定最小高…

股票价格预测 | Python基于RNN股票预测实战

循环神经网络(RNN)是基于序列数据(如语言、语音、时间序列)的递归性质而设计的,是一种反馈类型的神经网络,其结构包含环和自重复,因此被称为“循环”。它专门用于处理序列数据,如逐字生成文本或预测时间序列数据(例如股票价格)。 (1)one to one:其实和全连接神经网络…

网页版微信客户管理系统,常见疑问解答

1.系统怎么登陆&#xff1f; 请使用谷歌浏览器打开和使用系统&#xff0c;避免出现浏览器不兼容的问题&#xff0c;不建议使用其他浏览器。打开后输入登陆账号和密码即可登陆。 2.怎么登陆微信号&#xff1f; 登陆系统后&#xff0c;点击左上角这个 “” &#xff0c;选择 “…