opencv中使用cuda加速图像处理

opencv大多数只使用到了cpu的版本,实际上对于复杂的图像处理过程用cuda(特别是高分辨率的图像)可能会有加速效果。是否需要使用cuda需要思考:

  • 1、opencv的cuda库是否提供了想要的算子。在CUDA-accelerated Computer Vision你可以看到cv的cuda库提供了哪些方法。
  • 2、如果要使用cv的cuda库,会涉及到数据从cpu和gpu之间的交换。一张图片首先会被cpu读取到内存中,然后通过api将cpu中的数据搬运到gpu中,而cpu和gpu之间的数据搬运也是很耗时的,比如gpu_dst.download(dst_cpu)将gpu_dst数据搬运到dst_cpu,数据是8976*4960*3,耗时约37ms,如果你的图像处理比较简单,说不定数据搬运的耗时比直接在cpu上运行更长。

1、带cuda的opencv安装

这里的前提是你的nvidia驱动、cuda以及cudnn都安装完成,可以正常使用。

首先下载版本一致的opencv和opencv-contrib(cuda库所在包),然后解压待用。

然后查询你显卡的Compute Capability,进入opencv-4.8.1后创建build文件夹,终端在build中打开后,执行:

cmake \ 
-D CMAKE_BUILD_TYPE=RELEASE \ 
-D BUILD_CUDA_STUBS=ON \         
-D WITH_CUDA=ON \                   
-D CUDA_ARCH_BIN=8.9 \ 
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.8.1/modules .. 

注意,CUDA_ARCH_BIN是你查询到自己显卡的Compute Capability,OPENCV_EXTRA_MODULES_PATH指向你的opencv_contrib-4.8.1/modules。(最后的..不能省略)
在这里插入图片描述
可以看到成功检测到我的11.8的cuda,但是没有cuDNN。不知道是不是新版的原因,我安装好cudnn后通过命令cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2查询cudnn版本没有任何输出,但是确实存在cudnn.h,并在在使用cuda时也没有问题,就没有(后面在opencv使用cuda也没有报错)。

然后:sudo make –j15,表示使用15个线程make,因cpu而异。
最后sudo make install

后续的操作参考ubuntu20.04+opencv+vscode添加环境变量。

2、测试

编写c++代码测试:

#include <opencv2/opencv.hpp>
#include <opencv2/core/cuda.hpp>int main()
{cv::cuda::printCudaDeviceInfo(cv::cuda::getDevice());int count = cv::cuda::getCudaEnabledDeviceCount();printf("GPU Device Count : %d \n", count);return 0;
}

在这里插入图片描述
如果是不支持cuda的cv,则会报错:error: (-216:No CUDA support) The library is compiled without CUDA support in function 'throw_no_cuda'

3、在gpu上旋转图像

实际上,在gpu上使用cv总体分为三步:1)将内存中的数据搬运到gpu上;2)使用cuda方法进行图像处理;3)将处理结果搬运到cpu上;

下面是一个将图像逆时针旋转90度的代码,其中Timer类是一个计时器,从创建起计时,到离开作用域被销毁时的耗时。对于4960*8976\的图像进行测试,RGB指3通道,Gray指单通道,测量upload、rotate和download三个阶段的耗时:

RGB(ms)Gray(ms)
upload93
rotate43
download3712

可以看到对于简单的操作实际上耗时在数据的上传和下载。

#include <opencv2/opencv.hpp>
#include <opencv2/cudawarping.hpp>
#include "timer.h"int main(int argc, char *argv[])
{if (argc != 2){ // 检查是否传入图片路径std::cout << "参数错误" << std::endl;}// 以灰度图模式读取输入图像cv::Mat src = cv::imread(argv[1]);// 实际上对于gpu上的data,可以直接创建cv::cuda::GpuMat imgdata(w,h,*data),将gpudata的地址传给imgdata直接实例化if (src.empty()){std::cerr << "Failed to read input image!" << std::endl;return -1;}cv::Mat dst_cpu; // 在cpu创建一个Mat,接受处理后的图像结果cv::cuda::GpuMat gpu_src, gpu_dst;   // 在gpu创建两个Mat,分别储存旋转前后的图像(因为旋转前后尺寸不一样,所以必须要两个Mat)gpu_dst.create(8976, 4960, CV_8UC3); // 定义旋转后图像尺寸的Matcv::Mat colorImage(8976, 4960, CV_8UC3); // 在cpu创建Mat,一个将灰度图转为RGB图的Mat{{Timer time("upload");gpu_src.upload(src); // 将cpu上的src搬运到gpu的gpu_src中}{Timer time("rotate"); // 计时器,从此刻计时直到离开作用域被销毁// 逆时针旋转90度,将4960*8976转8976*4960,流程是按左上角旋转后,向下平移8976,然后用8976*4960的Mat接受cv::cuda::rotate(gpu_src, gpu_dst, gpu_dst.size(), 90, 0, 8976);}// 将gpu的gpu_dst数据搬运到dst_cpu中(好像只有gpu的数据才有方法){Timer time("download");gpu_dst.download(dst_cpu); // gpu到cpu搬运数据很耗时,RGB数据耗时37ms,Gray数据耗时12ms}}return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
set(CMAKE_BUILD_TYPE Debug)
project(MyProject)# 添加可执行文件
add_executable(draft draft.cpp src/timer.cpp)# 设置包含目录
target_include_directories(draft PRIVATE src)# 查找 OpenCV 库
find_package(OpenCV REQUIRED)# 将 OpenCV 库链接到可执行文件
target_link_libraries(draft PRIVATE ${OpenCV_LIBS} opencv_cudawarping)

4、解决数据上传和下载的耗时

当数据在cpu和gpu之间传输时,一定会有耗时。但是在cpu中存在虚拟内存,即在cpu上的数据可能是保存在位于磁盘的虚拟内存,这和直接在cpu物理内存上肯定是要慢的。所以在cv::cuda中提供了锁页的api,专门从物理内存中开辟空间存放数据:

cv::Mat snapshot(8976, 4960, CV_8UC1);   // cpu上的数据
cv::cuda::registerPageLocked(snapshot);  // 按大小分配锁页内存
gpu_dst.upload(snapshot);                   
// 处理代码
gpu_dst.download(snapshot);
cv::cuda::unregisterPageLocked(snapshot);  // 下载后释放

该方法经过测试,在我的例子中将download从13ms下降到3ms,提升明显

5、Mat创建优化

声明时定义大小,可以显著提高效率

// 只声明不分配大小,cvtColor耗时22ms
cv::Mat img1;
cv::cvtColor(snapshot, img1, cv::COLOR_GRAY2BGR);// 声明且分配大小,cvtColor耗时8ms
cv::Mat img1(8976, 4960, CV_8UC3);
cv::cvtColor(snapshot, img1, cv::COLOR_GRAY2BGR);

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

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

相关文章

百面嵌入式专栏(面试题)C语言面试题22道

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍C语言相关面试题 。 宏定义是在编译的哪个阶段被处理的?答案:宏定义是在编译预处理阶段被处理的。 解读:编译预处理:头文件包含、宏替换、条件编译、去除注释、添加行号。 写一个“标准”宏MIN,这个…

Hexo更换Matery主题

引言 在数字化时代&#xff0c;拥有一个个人博客已经成为许多人展示自己技能、分享知识和与世界互动的重要方式。而在众多博客平台中&#xff0c;Hexo因其简洁、高效和易于定制的特点而备受青睐。本文将详细介绍如何为你的Hexo博客更换主题&#xff0c;让你的个人博客在互联网…

华为 Huawei 交换机 黑洞MAC地址的作用和配置示例

黑洞mac作用&#xff1a;某交换机上配置某个PC的mac地址为黑洞mac&#xff0c;那么这台PC发出来的包都会被交换机丢弃&#xff0c;不会被转发到网络中。 组网需求&#xff1a; 如 图 2-13 所示&#xff0c;交换机 Switch 收到一个非法用户的访问&#xff0c;非法用户的 MAC 地址…

node网站 宝塔 面板配置 防止刷新404

1.问题 我现在配置了一个网站 后台项目 放到了宝塔上 将相应的域名和项目都配置好了 域名也可以访问 但是有的时候 出现了404 类似这种404 这个资源找不到 2.说明 其实这个问题的原因是nginx 的问题 反向代理的原因 3.解决 在这个配置文件中 有个配置文件 # 防止刷新404l…

从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出&#xff1a;[3…

[Java][算法 双指针]Day 02---LeetCode 热题 100---04~07

LeetCode 热题 100---04~07 第一题&#xff1a;移动零 思路 找到每一个为0的元素 然后移到数组的最后 但是需要注意的是 要在给定的数组原地进行修改 并且其他非零元素的相对顺序不能改变 我们采用双指针法 定义两个指针i和j i和j一开始分别都在0索引位置 然后判断j所…

MATLAB环境下基于深层小波时间散射网络的ECG信号分类

2012年&#xff0c;法国工程学院院士Mallat教授深受深度学习结构框架思想的启发&#xff0c;提出了基于小波变换的小波时间散射网络&#xff0c;并以此构造了小波时间散射网络。 小波时间散射网络的结构类似于深度卷积神经网络&#xff0c;不同的是其滤波器是预先确定好的小波…

熔断机制解析:如何用Hystrix保障微服务的稳定性

微服务与系统的弹性设计 大家好,我是小黑,在讲Hystrix之前,咱们得先聊聊微服务架构。想象一下,你把一个大型应用拆成一堆小应用,每个都负责一部分功能,这就是微服务。这样做的好处是显而易见的,更新快,容错性强,每个服务可以独立部署,挺美的对吧?但是,问题也随之而…

从零开始手写mmo游戏从框架到爆炸(十一)— 注册与登录

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 从这一章开始&#xff0c;我们进入业务的部分&#xff0c;从注册登录开始。 创建注册和登录的路由 package com.loveprogrammer.command.server;public interface Se…

杨中科 ASP.NETCORE 高级14 SignalR

1、什么是websocket、SignalR 服务器向客户端发送数据 1、需求&#xff1a;Web聊天;站内沟通。 2、传统HTTP&#xff1a;只能客户端主动发送请求 3、传统方案&#xff1a;长轮询&#xff08;Long Polling&#xff09;。缺点是&#xff1f;&#xff08;1.客户端发送请求后&…

计算机网络概念、组成、功能和分类

文章目录 概要1.怎么学习计算机网络2.概念3.功能、组成4.工作方式、功能组成5.分类 概要 概念、组成、功能和分类 1.怎么学习计算机网络 2.概念 通信设备&#xff1a;比如路由器、路由器 线路&#xff1a;将系统和通信设备两者联系的介质之类的 计算机网络是互连的、自治的的计…

k8s 部署java应用 基于ingress+jar包

k8 集群ingress的访问模式 先部署一个namespace 命名空间 vim namespace.yaml kind: Namespace apiVersion: v1 metadata:name: ingress-testlabels:env: ingress-test 在部署deployment deployment是pod层一层封装。可以实现多节点部署 资源分配 回滚部署等方式。 部署的…

javaEE - 21( 15000字 Tomcat 和 HTTP 协议入门 -2)

一&#xff1a; HTTP 响应 1.1 认识 “状态码” (status code) 状态码表示访问一个页面的结果. (是访问成功, 还是失败, 还是其他的一些情况…)&#xff0c;以下为常见的状态码. 1.1.1 200 OK 这是一个最常见的状态码, 表示访问成功. 抓包抓到的大部分结果都是 200 HTTP/…

Linux环境下配置HTTP代理服务器教程

大家好&#xff0c;我是你们可爱的Linux小助手&#xff01;今天&#xff0c;我将带你们一起探索如何在Linux环境下配置一个HTTP代理服务器。请注意&#xff0c;这不是一次火箭科学的实验&#xff0c;而是一次简单而有趣的冒险。 首先&#xff0c;我们需要明确什么是HTTP代理服…

华为第二批难题一:基于预训练AI模型的元件库生成

我的理解&#xff1a;华为的这个难道应该是想通过大模型技术&#xff0c;识别元件手册上的图文内容&#xff0c;与现有建库工具结合&#xff0c;有潜力按标准生成各种库模型。 正好&#xff0c;我们正在研究&#xff0c;利用知识图谱技术快速生成装配模型&#xff0c;其中也涉…

Spring Boot 笔记 003 Bean注册

使用Idea导入第三方jar包这种方法是不对的 使用maven命令导入jar包 官网下载maven Maven – Download Apache Maven 解压缩后在命令行输入命令&#xff0c;注意看输出的结果&#xff0c;安装的是不是你本地的maven仓库 mvn install:install-file -Dfile"D:\common-pojo-2…

一文带你读懂JSON模块

json模块 JSON (JavaScript Object Notation)&#xff1a;是一个轻量级的数据交换格式模块&#xff0c;受javascript对象文本语法启发&#xff0c;但不属于JavaScript的子集。 常用方法&#xff1a; dump(obj,fp)&#xff1a;将对象以字符串的形式写入文件中。 load(fp)&am…

Elasticsearch(四)

是这样的前面的几篇笔记&#xff0c;感觉对我没有形成知识体系&#xff0c;感觉乱糟糟的&#xff0c;只是大概的了解了一些基础知识&#xff0c;仅此而已&#xff0c;而且对于这技术栈的学习也是为了在后面的java开发使用&#xff0c;但是这里的API学的感觉有点乱&#xff01;然…

【大厂AI课学习笔记】【1.5 AI技术领域】(7)图像分割

今天学习到了图像分割。 这是我学习笔记的脑图。 图像分割&#xff0c;Image Segmentation&#xff0c;就是将数字图像分割为若干个图像子区域&#xff08;像素的集合&#xff0c;也被称为超像素&#xff09;&#xff0c;改变图像的表达方式&#xff0c;以更容易理解和分析。 …

微软.NET6开发的C#特性——委托和事件

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;看到不少初学者在学习编程语言的过程中如此的痛苦&#xff0c;我决定做点什么&#xff0c;下面我就重点讲讲微软.NET6开发人员需要知道的C#特性&#xff0c;然后比较其他各种语言进行认识。 C#经历了多年发展…