Opencv_CUDA实现推理图像前处理与后处理

Opencv_CUDA实现推理图像前处理与后处理

  • 通过trt 或者 openvino部署深度学习算法时,往往会通过opencv的Mat及算法将图像转换为固定的格式作为输入
  • openvino图像的前后处理后边将在单独的文章中写出
  • 今晚空闲搜了一些opencv_cuda的使用方法,在此总结一下
  • 前提是已经通过CMake将cuda和opencv重新编译好了C++库

1.前处理

  • 参考:【基于opencv-cuda的常见图像预处理】
 
// -------------- opencv ----------------------- # 
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
// ---------------- opencv-cuda ---------------- #
#include <opencv2/cudawarping.hpp>
#include <opencv2/cudaarithm.hpp>
#include <opencv2/cudaimgproc.hpp>// ------------ cuda ------------------------- #
#include <cuda_runtime_api.h>
// ------------------- nvinfer1 ------------------ # 
#include "NvInfer.h"// ------------ standard libraries  --------------- # 
#include <iostream>
#include <assert.h>
#include <string>
#include <vector>// ---------------------------------------------- #void preprocessImage(const std::string& image_path, float* gpu_input,nvinfer1::Dims3& dims)
{// read imagecv::Mat frame = cv::imread(image_path);if(frame.empty()){std::cerr << "failed to load image: " << image_path << "!" << std::endl;return;}// uploadcv::cuda::GpuMat gpu_frame;gpu_frame.upload(frame);// resize// CHW orderauto input_width = dims.d[2];auto input_height = dims.d[1];auto channels = dims.d[0];auto input_size = cv::Size(input_width, input_height);cv::cuda::GpuMat resized;cv::cuda::resize(gpu_frame, resized, input_size, 0, 0, cv::INTER_LINEAR);//*  ------------------------ Pytorch ToTensor and Normalize ------------------- */cv::cuda::GpuMat flt_image;resized.convertTo(flt_image, CV_32FC3, 1.f/255.f);cv::cuda::subtract(flt_image, cv::Scalar(0.485f, 0.346f, 0.406f), flt_image,cv::noArray(), -1);cv::cuda::divide(flt_image, cv::Scalar(0.229f, 0.224f, 0.225f), flt_image, 1, -1);//* ----------------------------------------------------------------------------------- /// BGR To RGBcv::cuda::GpuMat rgb;cv::cuda::cvtColor(flt_image, rgb, cv::COLOR_BGR2RGB);// toTensor(copy data to input float pointer channel by channel)std::vector<cv::cuda::GpuMat> rgb_out;for(size_t i=0; i<channels; ++i){rgb_out.emplace_back(cv::cuda::GpuMat(cv::Size(input_width, input_height), CV_32FC1, gpu_input + i * input_width * input_height));}cv::cuda::split(flt_image, rgb_out); // opencv HWC order -> CHW order
}// calculate size of tensor
size_t getSizeByDim(const nvinfer1::Dims& dims)
{size_t size = 1;for (size_t i = 0; i < dims.nbDims; ++i){size *= dims.d[i];}return size;
}int main()
{std::string image_path = "./turkish_coffee.jpg";// CHW ordernvinfer1::Dims3 input_dim(3, 640, 640);auto input_size = getSizeByDim(input_dim) * sizeof(float);// allocate gpu memory for network inference// 此处的buffer可以认为是TensorRT engine推理时在GPU上分配的输入显存std::vector<void*> buffers(1);cudaMalloc(&buffers[0], input_size);// preprocesspreprocessImage(image_path, (float*)buffers[0], input_dim);// downloadcv::cuda::GpuMat gpu_output;std::vector<cv::cuda::GpuMat> resized;for (size_t i = 0; i < 3; ++i){resized.emplace_back(cv::cuda::GpuMat(cv::Size(input_dim.d[2], input_dim.d[1]), CV_32FC1, (float*)buffers[0] + i * input_dim.d[2] * input_dim.d[1]));}cv::cuda::merge(resized, gpu_output);cv::cuda::GpuMat image_out;// normalizegpu_output.convertTo(image_out, CV_32FC3, 1.f * 255.f);// downloadcv::Mat dst;image_out.download(dst);cv::imwrite("../01_test_demo.jpg", dst);for(void* buf:buffers){cudaFree(buf);}return 0;
}
  • 原图与结果图:
    在这里插入图片描述

2. 输出后处理

  • 下边通过一个trt demo展示一下后处理操作
  • 源码实现如下:
#include <iostream>
#include <fstream>
#include <NvInfer.h>
#include <memory>
#include <NvOnnxParser.h>
#include <vector>
#include <cuda_runtime_api.h>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/core/cuda.hpp>
#include <opencv2/cudawarping.hpp>
#include <opencv2/core.hpp>
#include <opencv2/cudaarithm.hpp>
#include <algorithm>
#include <numeric>// destroy TensorRT objects if something goes wrong
struct TRTDestroy
{template <class T>void operator()(T* obj) const{if (obj){obj->destroy();}}
};template <class T>
using TRTUniquePtr = std::unique_ptr<T, TRTDestroy>;// calculate size of tensor
size_t getSizeByDim(const nvinfer1::Dims& dims)
{size_t size = 1;for (size_t i = 0; i < dims.nbDims; ++i){size *= dims.d[i];}return size;
}// get classes names
std::vector<std::string> getClassNames(const std::string& imagenet_classes)
{std::ifstream classes_file(imagenet_classes);std::vector<std::string> classes;if (!classes_file.good()){std::cerr << "ERROR: can't read file with classes names.\n";return classes;}std::string class_name;while (std::getline(classes_file, class_name)){classes.push_back(class_name);}return classes;
}// preprocessing stage ------------------------------------------------------------------------------------------------
void preprocessImage(const std::string& image_path, float* gpu_input, const nvinfer1::Dims& dims)
{// read input imagecv::Mat frame = cv::imread(image_path);if (frame.empty()){std::cerr << "Input image " << image_path << " load failed\n";return;}cv::cuda::GpuMat gpu_frame;// upload image to GPUgpu_frame.upload(frame);auto input_width = dims.d[2];auto input_height = dims.d[1];auto channels = dims.d[0];auto input_size = cv::Size(input_width, input_height);// resizecv::cuda::GpuMat resized;cv::cuda::resize(gpu_frame, resized, input_size, 0, 0, cv::INTER_NEAREST);// normalizecv::cuda::GpuMat flt_image;resized.convertTo(flt_image, CV_32FC3, 1.f / 255.f);cv::cuda::subtract(flt_image, cv::Scalar(0.485f, 0.456f, 0.406f), flt_image, cv::noArray(), -1);cv::cuda::divide(flt_image, cv::Scalar(0.229f, 0.224f, 0.225f), flt_image, 1, -1);// to tensorstd::vector<cv::cuda::GpuMat> chw;for (size_t i = 0; i < channels; ++i){chw.emplace_back(cv::cuda::GpuMat(input_size, CV_32FC1, gpu_input + i * input_width * input_height));}cv::cuda::split(flt_image, chw);
}// post-processing stage ----------------------------------------------------------------------------------------------
void postprocessResults(float *gpu_output, const nvinfer1::Dims &dims, int batch_size)
{// get class namesauto classes = getClassNames("imagenet_classes.txt");// copy results from GPU to CPUstd::vector<float> cpu_output(getSizeByDim(dims) * batch_size);cudaMemcpy(cpu_output.data(), gpu_output, cpu_output.size() * sizeof(float), cudaMemcpyDeviceToHost);// calculate softmaxstd::transform(cpu_output.begin(), cpu_output.end(), cpu_output.begin(), [](float val) {return std::exp(val);});auto sum = std::accumulate(cpu_output.begin(), cpu_output.end(), 0.0);// find top classes predicted by the modelstd::vector<int> indices(getSizeByDim(dims) * batch_size);std::iota(indices.begin(), indices.end(), 0); // generate sequence 0, 1, 2, 3, ..., 999std::sort(indices.begin(), indices.end(), [&cpu_output](int i1, int i2) {return cpu_output[i1] > cpu_output[i2];});// print resultsint i = 0;while (cpu_output[indices[i]] / sum > 0.005){if (classes.size() > indices[i]){std::cout << "class: " << classes[indices[i]] << " | ";}std::cout << "confidence: " << 100 * cpu_output[indices[i]] / sum << "% | index: " << indices[i] << "\n";++i;}
}// main pipeline ------------------------------------------------------------------------------------------------------
int main(int argc, char* argv[])
{if (argc < 3){std::cerr << "usage: " << argv[0] << " model.onnx image.jpg\n";return -1;}std::string model_path(argv[1]);std::string image_path(argv[2]);int batch_size = 1;// initialize TensorRT engine and parse ONNX modelTRTUniquePtr<nvinfer1::ICudaEngine> engine{nullptr};//初始化engine.........省略// get sizes of input and output and allocate memory required for input data and for output datastd::vector<nvinfer1::Dims> input_dims; // we expect only one inputstd::vector<nvinfer1::Dims> output_dims; // and one outputstd::vector<void*> buffers(engine->getNbBindings()); // buffers for input and output datafor (size_t i = 0; i < engine->getNbBindings(); ++i){auto binding_size = getSizeByDim(engine->getBindingDimensions(i)) * batch_size * sizeof(float);cudaMalloc(&buffers[i], binding_size);if (engine->bindingIsInput(i)){input_dims.emplace_back(engine->getBindingDimensions(i));}else{output_dims.emplace_back(engine->getBindingDimensions(i));}}if (input_dims.empty() || output_dims.empty()){std::cerr << "Expect at least one input and one output for network\n";return -1;}// preprocess input datapreprocessImage(image_path, (float *) buffers[0], input_dims[0]);// inferencecontext->enqueue(batch_size, buffers.data(), 0, nullptr);// postprocess resultspostprocessResults((float *) buffers[1], output_dims[0], batch_size);for (void* buf : buffers){cudaFree(buf);}return 0;
}

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

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

相关文章

云服务器ECS运维管理

目录 实时掌握CPU、内存使用情况 实时掌握存储的使用情况 定期对云服务器数据做好备份 定期检查云服务器的安全运行情况 要想保证云服务器长期稳定的使用&#xff0c;除了依靠阿里云&#xff08;云服务提供商&#xff09;的技术支持&#xff0c;自身必要的安全维护手段也是…

W6100-EVB-Pico评估版介绍

文章目录 1 简介2 硬件资源2.1 硬件规格2.2 引脚定义2.3 工作条件 3 参考资料3.1 Datasheet3.2 原理图3.3 尺寸图&#xff08;尺寸&#xff1a;mm&#xff09;3.4 参考例程 4 硬件协议栈优势 1 简介 W6100-EVB-Pico是一款基于树莓派RP2040和全硬件TCP/IP协议栈以太网芯片W6100的…

ApiPost测试token验证端口(若依)

首先ApiPost自带默认环境与Mock环境。 接下来自己创建新环境设置变量。 注&#xff1a;若本地环境与生产环境端口不一致&#xff0c;这里的url也要带上端口号 创建一个本地环境&#xff0c;增加环境变量url&#xff0c;默认值为localhost。 再新建一个生产环境。 新建一个登…

Hadoop集群部署

目录 1 模板虚拟机环境准备 1.1 修改网卡配置文件 扩展 1.2 修改主机名 1.3 在虚拟机中需要的基础文件包 1.4 关闭防火墙 1.5 创建Hadoop的账户及文件 2 模板虚拟机安装JDK 3 模板虚拟机安装Hadoop 4 克隆虚拟机 5 虚拟机配置主机名称映射 6 集群分发脚本 7 SSH无…

HTML代码全解析

HTML代码全解析实例解析 <!DOCTYPE html> 声明为 HTML5 文档<html> 元素是 HTML 页面的根元素<head> 元素包含了文档的元&#xff08;meta&#xff09;数据&#xff0c;如 <meta charset"utf-8"> 定义网页编码格式为 utf-8。<title> 元…

1233. 全球变暖(bfs宽搜相邻点)

题目&#xff1a; 1233. 全球变暖 - AcWing题库 思路&#xff1a;bfs 1.临接问题&#xff0c;最短路径问题--->bfs。 2.被完全淹没--->岛屿所以部分均临海。 代码&#xff1a; #include<bits/stdc.h> using namespace std; const int N1010; struct Point …

【Linux系统编程】进程状态

介绍 进程的状态指的是进程在执行过程中所处的状态。进程的状态随着进程的执行和外界条件的变化而转换。我们可用 kill 命令来进程控制进程的状态。 kill中的 kill -l 指令用于查看系统中定义的所有信号及其对应的编号。这些信号可以用于 kill 命令来向进程发送特定的信号控制其…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Toast组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Toast组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Toast组件 Toast 的应用场景也非常广泛&#xff0c;比如网络请求出错了可以弹一个…

鸿蒙开发(二)- 鸿蒙DevEco开发环境搭建

上篇说到&#xff0c;鸿蒙开发目前势头旺盛&#xff0c;头部大厂正在如火如荼地进行着&#xff0c;华为也对外宣称已经跟多个厂商达成合作。目前看来&#xff0c;对于前端或客户端开发人员来说&#xff0c;掌握下鸿蒙开发还是有些必要性的。如果你之前是从事Android开发的&…

论文阅读<CF-YOLO: Cross Fusion YOLO for Object Detection in Adverse Weather.....>

论文链接&#xff1a;https://arxiv.org/pdf/2309.08152.pdfhttps://arxiv.org/pdf/2206.01381.pdfhttps://arxiv.org/pdf/2309.08152.pdf 代码链接&#xff1a;https://github.com/DiffPrompter/diff-prompter 目前没有完整代码放出。 恶劣天气下的目标检测主要有以下三种解…

Stable Diffusion系列(三):网络分类与选择

文章目录 网络分类模型基座模型衍生模型二次元模型2.5D模型写实风格模型 名称解读 VAELora嵌入文件放置界面使用 网络分类 当使用SD webui绘图时&#xff0c;为了提升绘图质量&#xff0c;可以多种网络混合使用&#xff0c;可选的网络包括了模型、VAE、超网络、Lora和嵌入。 …

引用jquery.js的html5基础页面模板

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

使用LLaMA-Factory微调ChatGLM3

1、创建虚拟环境 略 2、部署LLaMA-Factory &#xff08;1&#xff09;下载LLaMA-Factory https://github.com/hiyouga/LLaMA-Factory &#xff08;2&#xff09;安装依赖 pip3 install -r requirements.txt&#xff08;3&#xff09;启动LLaMA-Factory的web页面 CUDA_VI…

Java经典框架之Spring MVC

Spring MVC Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Spring MVC 入门案例 2. 基…

JVS低代码平台:多级菜单配置的详细教程与演示

多级菜单是软件系统一种常见的用户界面设计&#xff0c;它允许用户通过点击或选择不同的菜单项来执行不同的操作或访问不同的功能。多级菜单通常由多个级别的菜单组成&#xff0c;每个级别都包含一组可选择的菜单项。用户可以通过点击或选择菜单项来进入下一级菜单&#xff0c;…

【MYSQL】MYSQL 的学习教程(七)之 慢 SQL 优化思路

1. 慢 SQL 优化思路 慢查询日志记录慢 SQLexplain 分析 SQL 的执行计划profile 分析执行耗时Optimizer Trace 分析详情确定问题并采用相应的措施 1. 慢查询日志记录慢 SQL 如何定位慢SQL呢&#xff1f; 我们可以通过 慢查询日志 来查看慢 SQL。 ①&#xff1a;开启慢查询日志…

vr虚拟高压电器三维仿真展示更立体全面

VR工业虚拟仿真软件的应用价值主要体现在以下几个方面&#xff1a; 降低成本&#xff1a;通过VR技术进行产品设计和开发&#xff0c;可以在虚拟环境中进行&#xff0c;从而减少对物理样机的依赖&#xff0c;降低试错成本和时间。此外&#xff0c;利用VR技术构建的模拟场景使用方…

蓝桥杯-Excel地址[Java]

目录&#xff1a; 学习目标&#xff1a; 学习内容&#xff1a; 学习时间&#xff1a; 题目&#xff1a; 题目描述: 输入描述: 输出描述: 输入输出样例: 示例 1: 运行限制: 题解: 思路: 学习目标&#xff1a; 刷蓝桥杯题库日记 学习内容&#xff1a; 编号96题目Ex…

Find My文具盒|苹果Find My技术与文具盒结合,智能防丢,全球定位

文具盒&#xff0c;学生用来装钢笔、铅笔、尺子、橡皮等文具的盒子。质地种类很多&#xff0c;一般有木质、铁质、塑料等制品&#xff0c;形状各异&#xff0c;多为长方体形状。文具盒能培养学生的管理能力。使用文具盒的过程就是一个管理自己的过程。每次使用文具之前&#xf…

Android/iOS APP备案流程指南

Android/iOS APP备案流程指南 摘要 本文通过详细介绍了工信部对移动互联网应用程序&#xff08;APP&#xff09;备案的要求&#xff0c;解释了APP备案的定义、时间节点、办理流程以及腾讯云、阿里云的备案流程&#xff0c;最后提供了常见问题的解答。 引言 随着移动互联网的…