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

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

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

文章目录

  • 【深度学习】【Opencv】python/C++调用onnx模型【基础】
  • 前言
  • Python版本OpenCV
    • Windows平台安装OpenCV
    • opencv调用onnx模型
  • C++版本OpenCV
    • Windows平台安装OpenCV
    • opencv调用onnx模型
      • 简单使用
      • 调用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_cpu python=3.10 -y
# 激活环境
activate opencv_onnx_cpu
# 安装opencv
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python

查看opencv版本

import cv2
cv2.__version__

opencv调用onnx模型

现在代码抛开任何pytorch相关的依赖,也抛开了onnx相关的依赖,只使用opencv完成了整个推理流程。

import cv2
import numpy as np

def normalizeImage(image,mean,std):
    normalized = image.astype(np.float32)
    normalized = normalized / 255.0 - mean
    normalized = normalized / std
    return normalized

def main():
    # 读取图片
    image = cv2.imread(r"./animal-1.jpg")
    # 将BGR图像转换为RGB格式
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # 获取图像的大小
    ori_w, ori_h, = image.shape[0], image.shape[1]

    # 指定调整后的大小
    new_width = 416
    new_height = 416
    # 图片尺寸缩放
    resized_img = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA)

    # 定义每个通道的归一化参数
    mean = np.array([0.485, 0.456, 0.406]).astype(np.float32)  # 均值
    std = np.array([0.229, 0.224, 0.225]).astype(np.float32)  # 标准差
    # 图片归一化
    normalized = normalizeImage(resized_img, mean, std)

    # 加载ONNX模型
    net = cv2.dnn.readNetFromONNX("PFNet.onnx")  # 加载训练好的识别模型
    # onnx是多输出,每个输出都会对应一个name,因此需要获取所有输出的name
    output_layer_names = net.getUnconnectedOutLayersNames()
    blob = cv2.dnn.blobFromImage(normalized)  # 由图片加载数据 这里还可以进行缩放、归一化等预处理
    # 将Blob设置为模型的输入
    net.setInput(blob)
    # 运行前向传播,将所有输出name作为参数传递
    out = net.forward(output_layer_names)
    out = np.squeeze(out[3]) * 255.0
    output = cv2.resize(out, (ori_h, ori_w), interpolation=cv2.INTER_AREA)

    # 保存图像
    cv2.imwrite('saved_opencv_python_image.png', output)

if __name__ == '__main__':
    main()

C++版本OpenCV

Windows平台安装OpenCV

官网下载安装文件地址,博主使用opencv-4.8.0-windows.exe版本

双击运行解压后即可,博主重命名为opencv_cpu:

打开VS 2019:新建新项目—->空项目—->配置项目—->项目路径以及勾选“将解决方案和项目放在同一目录中—->点击创建。
在解决方案–>源文件–>右键添加新建项。这里暂时可以默认空着不做处理。

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

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

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

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

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

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

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

opencv_world480.lib

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

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

D:\C++_demo\opencv_cpu\build\x64\vc16\bin
===>
D:\C++_demo\opencv_onnx_cpu\x64\Releas


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

opencv调用onnx模型

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

简单使用

这里简单验证一下opencv是否安装成功,适用于包括博主在内的许多对c++不熟悉的人来说,代码完成了简单的图像的读取与显示。

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
	Mat src = imread("./animal-1.jpg");
	//没有图像输入
	if (src.empty()) {
		printf("....\n");
		return -1;
	}
	//namedWindow("输入窗口", WINDOW_FREERATIO);
	imshow("输入窗口", src);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

调用onnx模型

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

#include <iostream>
#include <string>
#include <vector>
#include<opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
using namespace std;
cv::Mat normalizeImage(const cv::Mat& image, const cv::Scalar& mean, const cv::Scalar& std) {
    cv::Mat normalized;
    image.convertTo(normalized, CV_32F);
    cv::subtract(normalized / 255.0, mean, normalized);
    cv::divide(normalized, std, normalized);
    return normalized;
}
int main()
{   
    // 读取图片
    cv::Mat bgrImage = cv::imread("./animal-1.jpg", cv::IMREAD_COLOR);
    // 图片格式转化bgr-->rgb
    cv::Mat rgbImage;
    cv::cvtColor(bgrImage, rgbImage, cv::COLOR_BGR2RGB);
    // 获取图像的大小
    cv::Size originalSize(rgbImage.cols, rgbImage.rows);
    cv::Mat resizedImage;

    // 定义目标图像大小
    cv::Size targetSize(416, 416);
    //图片尺寸缩放
    cv::resize(rgbImage, resizedImage, targetSize, 0, 0, cv::INTER_AREA);

    // 定义每个通道的归一化参数
    cv::Scalar mean(0.485, 0.456, 0.406); // 均值
    cv::Scalar std(0.229, 0.224, 0.225);  // 标准差
    // 图片归一化
    cv::Mat normalized = normalizeImage(resizedImage, mean, std);
    
    // 加载ONNX模型
    cv::dnn::Net net = cv::dnn::readNetFromONNX("D:/C++_demo/opencv_onnx_cpu/PFNet.onnx");
    cv::Mat blob = cv::dnn::blobFromImage(normalized);
    // 将Blob设置为模型的输入
    net.setInput(blob);
    // 运行前向传播
    std::vector<cv::Mat> output_probs;
    // 获取多输出对应的名称
    std::vector<cv::String> output_layer_names = net.getUnconnectedOutLayersNames();
    net.forward(output_probs, output_layer_names);
    cv::Mat prediction = output_probs[3];
    cv::Mat mask;
    cv::resize(prediction.reshape(1, 416) * 255.0, mask, originalSize, 0, 0, cv::INTER_AREA);
    cv::imwrite("saved_opencv_c++_image.png", mask);
    return 0;
}

总结

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

版权声明:本文为博主作者:牙牙要健康原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/yangyu0515/article/details/132894953

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2024年1月3日
下一篇 2024年1月3日

相关推荐