CUDA--图像拉伸(使用纹理内存texture)

   CUDA里的图像拉伸有很多方法,比较常用的方法是将图像放大后,利用卷积对图像进行滤波处理。这种方法时间复杂度高,处理复杂。相对而言,使用纹理内存进行图像拉伸,由于纹理内存本身对传入的图像数组有线性滤波作用,所以使用纹理拾取函数从源图像纹理内存取值,赋值给输出图像,即可完成图像拉伸及图像滤波两种功能。

利用纹理内存的硬件插值功能,直接使用浮点型的坐标读取相应的源图像“像素”值,并赋值给目标图像。这里没有进行对源图像读取的越界检查,这是因为纹理内存硬件插值功能可以处理越界访问的情况,越界访问会按照事先的设置得到一个相对合理的像素颜色值,不会引起错误。
    使用cuda数组储存图像数据时,滤波效果更好。
    但是texture纹理内存做数据寄存器是不可取的,实验证明其存取速度并不高。纹理内存更适于图像放缩及图像旋转处理。
 
kernel函数如下:
// 宏:DEF_BLOCK_X 和 DEF_BLOCK_Y
// 定义了默认的线程块尺寸。
#define DEF_BLOCK_X  32
#define DEF_BLOCK_Y   8
 
// Kernel 函数:_stretchImgKer(拉伸图像)
// 根据给定的拉伸倍数 N 和 M,将输入图像拉伸,将其尺寸从 width * height 变成 
// (width * N) * (height * N)
 
// 全局变量:texRef(作为输入图像的纹理内存引用)
// 纹理内存只能用于全局变量,因此将硬件插值的旋转变换的 Kernel 函数的输入图像列
// 于此处。
static texture texRef;
 
// Kernel 函数:_StretchImgKer(拉伸图像)
static __global__ void _stretchImgKer(
        ImageCuda inimg, ImageCuda outimg, int timesWidth, int timesHeight)//拉伸倍数                                                                              //timesWidth*timesHeight
{
    // 计算当前线程的位置。
    int c = blockIdx.x * blockDim.x + threadIdx.x;
    int r = blockIdx.y * blockDim.y + threadIdx.y;
 
    // 检查第一个像素点是否越界,如果越界,则不进行处理,一方面节省计算
    // 资源,另一方面防止由于段错误导致程序崩溃。
    if (r >= outimg.imgMeta.height || c >= outimg.imgMeta.width)
       return;
  
// 计算第一个输出坐标点对应的图像数据数组下标。
    int outidx = r * outimg.pitchBytes + c;
 
    // 通过目标坐标点反推回源图像中的坐标点,这一步是关键,图像的旋转处理也可使用
    float inc = c/(float)timesWidth;
    float inr = r/(float)timesHeight;
 
    // 通过上面的计算,求出了第一个输出坐标对应的源图像坐标。这里利用纹理内存的
    // 硬件插值功能,直接使用浮点型的坐标读取相应的源图像“像素”值,并赋值给目
    // 标图像。这里没有进行对源图像读取的越界检查,这是因为纹理内存硬件插值功能
    // 可以处理越界访问的情况,越界访问会按照事先的设置得到一个相对合理的像素颜
    // 色值,不会引起错误。纹理拾取同时也具有平滑滤波作用,输出图像噪声小。
    outimg.imgMeta.imgData[outidx] = tex2D(texRef,inc,inr);
}
 
主函数中进行以下处理即可:
//为CUDA数组分配内存,并将输入图像拷贝到内存
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(sizeof (unsigned char) * 8, 0, 0, 0, cudaChannelFormatKindUnsigned);    
 
    //纹理和数组绑定
 
errcode = cudaBindTexture2D( NULL, &texRef, inimg->imgData, &channelDesc, inimg->width, inimg->height, inimgCud->pitchBytes);
  
if (errcode != NO_ERROR)
   return errcode;
    
    // 计算调用 Kernel 函数的线程块的尺寸和线程块的数量。
    dim3 blocksize, gridsize;
    blocksize.x = DEF_BLOCK_X;
    blocksize.y = DEF_BLOCK_Y;
    gridsize.x = (outsubimgCud.imgMeta.width + blocksize.x - 1) / blocksize.x;
    gridsize.y = (outsubimgCud.imgMeta.height + blocksize.y - 1) / blocksize.y;
    
    // 调用核函数。
    _stretchImgKer<<>>(
        insubimgCud, outsubimgCud, timesWidth, timesHeight);
实验结果如下,纹理拾取处理得到的图像滤波效果还是很好的:

转载于:https://www.cnblogs.com/north-north/archive/2013/04/01/2993724.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值