OpenCV CUDA模块设备层-----用于CUDA 纹理内存(Texture Memory)的封装类cv::cudev::Texture

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

cv::cudev::Texture 是 OpenCV CUDA 模块(opencv_cudaimgproc)中用于 CUDA 纹理内存(Texture Memory) 的封装类。它主要用于在 CUDA 核函数中访问图像数据时,利用纹理内存的缓存机制来提升性能,特别是在图像采样、缩放、仿射变换等操作中。

  • 纹理内存是一种 只读缓存内存,适合随机访问模式。
  • 它有缓存机制,对图像空间局部性访问非常友好。
  • 常用于图像处理中的插值、旋转、透视变换、滤波等任务。

cv::cudev::Texture 的作用

OpenCV 提供了 cv::cudev::Texture 类模板来绑定图像数据到纹理内存中:

template <typename T>
class Texture : public PtrStepSzb
{
public:Texture();explicit Texture(const GpuMat& d_src);void bind(const GpuMat& d_src);void unbind();
};

你可以把它理解为一个“GPU 图像纹理对象”,绑定后可以在核函数中使用类似 CPU 中 cv::getRectSubPix 或 cv::remap 的方式访问像素。

使用步骤示例

步骤 1:包含头文件

#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudev/ptr2d/texture.hpp>

步骤 2:绑定图像到纹理内存

cv::cuda::GpuMat d_src = ...; // 输入图像
cv::cudev::Texture<uchar> tex;
tex.bind(d_src); // 绑定 uchar 类型的图像到纹理内存

你也可以使用其他类型如 uchar3, float 等。
步骤 3:在 CUDA 核函数中访问纹理内存

__global__ void sampleKernel(float* output, int width, int height) {int x = blockIdx.x * blockDim.x + threadIdx.x;int y = blockIdx.y * blockDim.y + threadIdx.y;if (x < width && y < height) {float u = static_cast<float>(x) / width;float v = static_cast<float>(y) / height;// 使用纹理采样器读取像素output[y * width + x] = tex2D(tex, u * width, v * height);}
}

注意:这里使用了 tex2D() 函数,这是 CUDA 运行时 API 中的标准纹理采样函数。

步骤 4:调用核函数并释放资源

dim3 block(16, 16);
dim3 grid((width + 15) / 16, (height + 15) / 16);sampleKernel<<<grid, block>>>();
cudaDeviceSynchronize();tex.unbind(); // 使用完记得解绑

注意事项

内容说明
只读访问Texture memory 是只读的,不能写入
数据类型支持支持 uchar, uchar4, float, float4 等常见格式
性能优化对图像缩放、旋转、仿射变换等操作特别有用
自动边界处理支持 cudaAddressModeClamp, cudaAddressModeWrap 等寻址模式
需要绑定和解绑使用完毕要调用 unbind() 避免资源泄漏

代码示例

头文件:

#ifndef CUDA_UTILS_H
#define CUDA_UTILS_H#include <opencv2/opencv.hpp>
#include <opencv2/cudaimgproc.hpp>// 声明在 .cu 文件中实现的函数
void resizeWithTexture(cv::cuda::GpuMat& d_src, cv::cuda::GpuMat& d_dst, float scale);#endif // CUDA_UTILS_H‘

cu文件:

#include "cuda_utils.h"
#include <opencv2/cudev/ptr2d/texture.hpp>using namespace cv;
using namespace cudev;#include <cuda_runtime.h>
#include <vector_types.h>
#include <iostream>// 定义 CUDA 检查宏
#define CUDA_CHECK(call) \do { \cudaError_t err = call; \if (err != cudaSuccess) { \std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ << ": " \<< cudaGetErrorString(err) << std::endl; \exit(EXIT_FAILURE); \} \} while (0)__global__ void resizeKernel(uchar* dst, int dst_cols, int dst_rows, size_t dst_step,float scale, int src_cols, int src_rows, cudaTextureObject_t texObj) {int x = blockIdx.x * blockDim.x + threadIdx.x;int y = blockIdx.y * blockDim.y + threadIdx.y;if (x < dst_cols && y < dst_rows) {float src_x = x / scale;float src_y = y / scale;// 使用纹理采样器读取像素值float val = tex2D<uchar>(texObj, src_x + 0.5f, src_y + 0.5f);dst[y * dst_step + x] = static_cast<uchar>(val);}
}void resizeWithTexture(cuda::GpuMat& d_src, cuda::GpuMat& d_dst, float scale) {cudaTextureObject_t texObj = 0;// 1. 创建 CUDA ArraycudaArray* cu_array = nullptr;// 获取源图像的通道数并创建对应格式的通道描述符int num_channels = d_src.channels();cudaChannelFormatDesc channel_desc;switch (num_channels) {case 1: channel_desc = cudaCreateChannelDesc<uchar>(); break;case 3: channel_desc = cudaCreateChannelDesc<uchar3>(); break;case 4: channel_desc = cudaCreateChannelDesc<uchar4>(); break;default:std::cerr << "Unsupported number of channels: " << num_channels << std::endl;exit(EXIT_FAILURE);
}CUDA_CHECK(cudaMallocArray(&cu_array, &channel_desc, d_src.cols, d_src.rows, cudaArrayDefault));// 2. 将图像数据拷贝到 CUDA ArrayCUDA_CHECK(cudaMemcpy2DToArray(cu_array, 0, 0,d_src.data, d_src.step,d_src.cols, d_src.rows,cudaMemcpyDeviceToDevice));// 3. 配置纹理资源描述符cudaResourceDesc res_desc = {};memset(&res_desc, 0, sizeof(res_desc));res_desc.resType = cudaResourceTypeArray;res_desc.res.array.array = cu_array;// 4. 配置纹理描述符cudaTextureDesc tex_desc = {};memset(&tex_desc, 0, sizeof(tex_desc));tex_desc.addressMode[0] = cudaAddressModeClamp; // 边界模式tex_desc.addressMode[1] = cudaAddressModeClamp;tex_desc.filterMode = cudaFilterModePoint;      // 最邻近插值tex_desc.readMode = cudaReadModeElementType;tex_desc.normalizedCoords = 0;                  // 坐标单位为像素而非 [0,1]// 5. 创建纹理对象CUDA_CHECK(cudaCreateTextureObject(&texObj, &res_desc, &tex_desc, NULL));// 6. 启动核函数dim3 block(16, 16);dim3 grid((d_dst.cols + block.x - 1) / block.x,(d_dst.rows + block.y - 1) / block.y);resizeKernel<<<grid, block>>>(d_dst.data, d_dst.cols, d_dst.rows, d_dst.step,scale, d_src.cols, d_src.rows, texObj);CUDA_CHECK(cudaDeviceSynchronize());// 7. 清理资源CUDA_CHECK(cudaDestroyTextureObject(texObj));CUDA_CHECK(cudaFreeArray(cu_array));
}

main.cpp:

#include "cuda_utils.h"  // 调用 CUDA 接口
#include <iostream>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/opencv.hpp>int main()
{// 读取图像(灰度图)cv::Mat h_src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png", cv::IMREAD_GRAYSCALE );if ( h_src.empty() ){std::cerr << "Failed to load image!" << std::endl;return -1;}// 创建 GPU 图像cv::cuda::GpuMat d_src, d_dst;d_src.upload( h_src );// 设置目标尺寸(放大两倍)float scale = 2.0f;d_dst.create( cvRound( h_src.rows * scale ), cvRound( h_src.cols * scale ), h_src.type() );// 调用 CUDA 实现的缩放函数resizeWithTexture( d_src, d_dst, scale );// 下载结果cv::Mat h_dst;d_dst.download( h_dst );// 显示结果cv::imshow( "Original", h_src );cv::imshow( "Resized (CUDA Texture)", h_dst );cv::waitKey( 0 );return 0;
}

运行结果

在这里插入图片描述

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

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

相关文章

自主学习-《Self-Adapting Language Models》

代码&#xff1a; https://jyopari.github.io/posts/seal 拟人比喻&#xff1a; 学生把备考的东西&#xff0c;以自己的方式记成笔记精华&#xff0c;更有利于他的理解和记忆。 背景&#xff1a; Self-improving: 本文&#xff1a; 输入外界知识&#xff0c;LLM将其整理为笔记(…

马上行计划管理后端架构

小程序日活未破万低成本高可用及滚动发版实战。 小程序已经积累很多用户了&#xff0c;高可用及滚动发布已经提上日程。 日活未破万&#xff0c;选购多台多家云服务器或者自建机房搭建k8s(Kubernetes)&#xff0c;成本显然有点太高了。因此取了折中的办法本地和云端服务同时启…

C++---类和对象(上)

1.类的定义 1.1类定义格式 首先我们引入一个新的关键字-----class&#xff0c;class定义一个类。 定义方法 跟我们之前定义结构体非常的像 那我们来简单的看一个类的定义 我们C语言实现的时候&#xff0c;结构体和函数是分离的。但是现在不需要&#xff0c;我可以直接写 …

UE5.5构建iOS失败但没有显式错误信息的问题

报错信息如下 UnrealBuildTool failed. See log for more details. (/Users/somebody/Library/Logs/Unreal Engine/LocalBuildLogs/UBA-UnrealDemo-IOS-Shipping_2.txt) AutomationException: UnrealBuildTool failed. See log for more details. (/Users/somebody/Library/Lo…

浅谈 Unity XR:从混战到统一,OpenXR 的演进与现实困境

一.引言 在 XR&#xff08;扩展现实&#xff09;技术日渐普及的今天&#xff0c;Unity 已成为开发 VR、AR 和 MR 应用的主流平台。然而在这个生态蓬勃发展的背后&#xff0c;XR 的接口标准也经历了混乱到统一的演进过程。从早期的厂商割据&#xff0c;到 Unity 的初步抽象&…

Python基础教学:航天工程领域的精确计算和金融领域的精确计算,分别采用的小数保留位数的方法有哪些?有什么区别?-由Deepseek产生

在Python中处理航天工程和金融领域的精确计算时&#xff0c;虽然都强调精度&#xff0c;但因目标需求、误差容忍度和计算性质不同&#xff0c;其小数保留位数的方法和策略存在显著差异。以下是关键方法和区别分析&#xff1a; 一、航天工程领域 核心需求&#xff1a; 物理世界…

机器人玩具:成年人的心灵游乐场与未来前哨

当提及“机器人玩具 ”&#xff0c;许多人脑海中仍会浮现出孩童在游戏垫上摆弄塑料小人的画面。然而&#xff0c;时代已悄然转变——那些曾被视为童年专属的机械伙伴&#xff0c;如今正被越来越多的成年人郑重捧在手中。这不是一种幼稚的退行&#xff0c;而是一场关于创造力、情…

Spring Cloud LoadBalancer深度解析:官方负载均衡方案迁移指南与避坑实践

引言&#xff1a;为什么LoadBalancer正在取代Ribbon&#xff1f; “Ribbon已进入维护模式” —— Spring官方公告 当你的Spring Boot升级到3.x版本&#xff0c;Ribbon的依赖项将无法通过编译。作为Spring Cloud 官方钦定的替代方案&#xff0c;LoadBalancer凭借&#xff1a; ✅…

暴雨服务器成功中标洪湖市政府框架采购项目

近日&#xff0c;在洪湖市政府 2025 年度行政事业单位服务器封闭式框架协议采购项目中&#xff0c;暴雨服务器凭借其卓越的性能、优质的服务以及合理的价格&#xff0c;成功脱颖而出&#xff0c;赢得了该项目的中标资格。这一成果不仅标志着暴雨服务器在政府领域的认可度进一步…

C# 多线程按顺序执行之ManualResetEvent

ManualResetEvent被用于在** 两个或多个线程间** 进行线程信号发送。 多个线程可以通过调用ManualResetEvent对象的WaitOne方法进入等待或阻塞状态。当控制线程调用Set()方法&#xff0c;所有等待线程将恢复并继续执行。 以下是使用ManualResetEvent的例子&#xff0c;确保多线…

SQL里的正则

1393-capital-gainloss https://leetcode.com/problems/capital-gainloss/description/ IDEA报红但是能执行&#xff01; -- 用全部卖出的减去全部买入的 with b as ( select stock_name, sum(price) AS total_buy_price from Stocks where operation Buygroup by stock_na…

计算机求职提前批/求职什么时候投递合适

前言 大家秋招或者春招&#xff0c;可能一直在网上冲浪&#xff0c;看到一些人在鼓吹说提前批开始&#xff0c;秋招开始。必须要赶紧找工作了&#xff0c;再不找就失业了等等。 然后&#xff0c;到自己就开始焦虑&#xff0c;感觉别人都在投简历&#xff0c;自己不投感觉很吃亏…

八种数据结构简介

目录 1.1 数据结构概述 1.2 数据结构的分类 1.2.1 逻辑结构 1&#xff09;集合 2&#xff09;线性结构 3&#xff09;树形结构 4&#xff09;图形结构 1.2.2 物理结构 1&#xff09;顺序存储 2&#xff09;链式存储 3&#xff09;散列存储 4&#xff09;索引存储 …

破壁虚实的情感科技革命:元晟定义AI陪伴机器人个性化新纪元

在人工智能席卷全球的浪潮中&#xff0c;广东中山一家名为元晟传媒科技的企业正悄然改写情感陪伴产业的游戏规则。作为广东元伴智能科技&#xff08;下称“元伴智能”&#xff09;的战略级下属机构&#xff0c;中山元晟传媒科技凭借独特的“技术场景流量”三角模型&#xff0c;…

leetcode_455 分饼干

1. 题意 给一堆饼干&#xff0c;和一群小朋友。饼干有大小&#xff0c;小朋友有胃口值&#xff1b;小朋友不吃比自己胃口小的饼干&#xff0c;问这些饼干能满足多少小朋友食用。 2. 题解 排序贪心 优先用小饼干满足胃口小的小朋友&#xff0c;这样大饼干就能留给胃口大的小朋…

使用 C# 源生成器(Source Generators)进行高效开发:增强 Blazor 及其他功能

.NET 中源生成器的引入彻底改变了我们的开发方式&#xff0c;它消除了动态逻辑&#xff0c;并在编译时生成静态代码。这不仅提高了应用程序的性能&#xff0c;还提升了开发人员的生产力和代码质量。 如果您正在使用Blazor&#xff08;WebAssembly 或服务器&#xff09;或构建需…

word如何插入高清晰的matlab绘图

emf矢量图 在matlab中画好的图另存为emf格式&#xff0c;保存到本地&#xff0c;然后在word中选择插图图片&#xff0c;注意不要复制粘贴。 亲测好用&#xff01;

解锁 ChatGPT 超能力:全新「记忆」功能深度解析!

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

低压电涌保护:构筑电气设备的安全防线

在现代电力系统中&#xff0c;低压电涌保护扮演着至关重要的角色。雷电和电力系统中的瞬态过电压&#xff0c;是威胁电气设备安全运行的潜在风险。低压电涌保护器&#xff08;SPD&#xff09;作为一种专门设计的防护装置&#xff0c;能够有效地抑制这些电涌&#xff0c;确保电气…

GitLab多人协作MR流程规范模版(merge)

以下是一个适用于 GitLab 多人协作的 MR 流程规范模板&#xff0c;涵盖分支策略、MR 创建流程、冲突处理、审查要求和 CI/CD 设置。可以直接复制到团队 Wiki 或文档中使用。 &#x1f4d8; 一、分支策略 main ← 线上生产分支&#xff0c;仅从 release 合并 dev …