技术开发 频道

CUDA 技巧与经验 关于block、thread

  基本思路是:

  1.在原有图像周围扩展像素,向外扩展像素数由邻域决定,如4-邻域和8-邻域扩展1个像素,24-邻域扩展2个像素等

  2.每个block处理输出图像中长宽为16x16的一小部分,每个thread处理输出图像中的1个像素。这样每个block的线程数是256,符合nv推荐的192-256的范围。

  texture的版本可以直接参考imagedenoising

  shared memory的版本的可以参考以下代码(仅作示例,不能运行,处理4-邻域问题,其中i_data为global中的原始图像,func代表使用算子计算的过程)

shared type s_data[18][18];
shared type o_data[
16][16];
s_data[tid.x
+ 1] = i_data[bid.x*16+bid.y*640*18+tid.x-640];
s_data[
18*17 + tid.x + 1] = i_data[bid.x*16+bid.y*640*18+tid.x];
s_data[
18+tid.x*18] = i_data[bid.x*16+bid.y*640*18+tid.y*640-1];
s_data[
35+tid.x*18] = i_data[bid.x*16+bid.y*640*18+tid.y*640+1];
s_data[(tid.x
+1)*18+(tid.y)+1]=i_data[bid.x*16+bid.y*640*18+tid.y*640+tid.x];//中间256个
o_data[tid.x*16+tid.y]=func(
s_data[tid.x
*18+tid.y+1],//邻点1
s_data[(tid.x+1)*18+tid.y],//邻点4
s_data[(tid.x+1)*18+tid.y+1],//中心点
s_data[(tid.x+1)*18+tid.y+2],//邻点2
s_data[(tid.x+2)*18+tid.y+2],//邻点3);

  这种方法可以归纳为:以输出结果组织数据,将与输出相关的数据输入同一block

  投影问题:

  这里的投影问题特指通过投影进行维度压缩的问题,如医学成像中常见的radon变换(当然,医学影像处理中更常见的是radon逆变换,但逆变换用傅式变换处理更好,此处不再赘述)。

  这一类问题有一些例子:给手照x光片,我们的手是三维的,而最后出来的x光片则是平面的。做核磁共振(CT)时,实际上传感器是一个线阵,一直绕着我们的身体旋转,在不同的角度将我们身体的一个二维的截面投影到一维的传感器上。

  以CT为例,实质上是将输入矩阵进行旋转后投影到一行上。设图像与传感器夹角为theta,可以根据tid.x * sin(theta) + tid.y*cos(theta)求出点(tid.x, tid.y)在线阵上的投影。此时结果与输入的数据是一对多的关系,而且随着角度不同,很难确定是由哪些点决定最终输出。

  此时可以采用这样的方法:按照输入组织数据,每个block处理一行或者一个子矩阵并各自输出结果,最终将各block结果进行累加。

  用这样的方法解决CT造影问题,将输入图像按行输入各个block,各block将旋转后的行存入一个长度为floor(1.414*max(width,height))的行向量

  然后将各行输出的结果累加,即可得到最终结果。


0
相关文章