Parallel processing 使用共享内存在cuda内核中应用高斯掩码

Parallel processing 使用共享内存在cuda内核中应用高斯掩码,parallel-processing,cuda,convolution,Parallel Processing,Cuda,Convolution,我正在努力完成udacity“并行编程入门”课程的家庭作业,我被第二个作业卡住了,这基本上是使用CUDA对图像应用高斯模糊遮罩。 我想通过利用共享内存来有效地实现这一点。 我解决“边界像素问题”的想法是启动比块中实际像素数更多的线程:例如,如果我将输入图像划分为16x16大小的活动像素块,并且我有一个9x9大小的掩码,那么我的实际块尺寸将是(对于x和y):16+2*(9/2)=24。通过这种方式,我在一个块中启动24个线程,这样“外部”线程将仅用于将像素从输入img加载到共享mem,而“内部”线

我正在努力完成udacity“并行编程入门”课程的家庭作业,我被第二个作业卡住了,这基本上是使用CUDA对图像应用高斯模糊遮罩。 我想通过利用共享内存来有效地实现这一点。 我解决“边界像素问题”的想法是启动比块中实际像素数更多的线程:例如,如果我将输入图像划分为16x16大小的活动像素块,并且我有一个9x9大小的掩码,那么我的实际块尺寸将是(对于x和y):16+2*(9/2)=24。通过这种方式,我在一个块中启动24个线程,这样“外部”线程将仅用于将像素从输入img加载到共享mem,而“内部”线程对应于实际执行计算的活动像素(除了在共享mem中缓存)

由于某种原因,它不起作用。从附加的代码中可以看出,我可以将像素缓存到共享内存中,但是在计算过程中出现了严重错误,我附加了一个我得到的糟糕结果的图像

               __global__ void gaussian_blur(const unsigned char* const inputChannel,
               unsigned char* const outputChannel,
               int numRows, int numCols,
               const float* const filter, const int filterWidth)
               {

int filter_radius = (int)(filterWidth / 2); //getting the filter "radius"

int x = blockDim.x*blockIdx.x+threadIdx.x;
int y = blockDim.y*blockIdx.y+threadIdx.y;

if(x>=(numCols+filter_radius) || y>=(numRows+filter_radius)) 
    return;

int px = x-filter_radius;
int py = y-filter_radius;

//clamping

if(px<0) px = 0;
if(py<0) py = 0;
//if(px>=numCols) px = numCols-1;
// if(py>=numRows) py = numRows-1;

 __shared__ unsigned char tile[(16+8)*(16+8)]; //16 active pixels + 2*filter_radius

 tile[threadIdx.y*24+threadIdx.x] = inputChannel[py*numCols+px];

 __syncthreads();  

//Here everything is working fine: if I do
//  outputChannel[py*numCols+px] = tile[threadIdx.y*24+threadIdx.x]; 
//then I am able to see the perfect reconstruction of the input image.

//caching the filter
__shared__ float t_filter[81]; //9x9 conv mask

if(threadIdx.x==0 && threadIdx.y==0)
{
    for(int i=0; i<81; i++)
        t_filter[i] = filter[i];
}

__syncthreads();


//I am checking the threadIdx of the threads and I am performing the mask computation
//only to those threads that are pointing to active pixels:
//i.e. all the threads whose id is greater or equal to the filter radius,
//but smaller than the whole block of active pixels will perform the computation.
//filter_radius = filterWidth/2 = 9/2 = 4
//blockDim.x or y = 16 + filterWidth*2 = 16+8 = 24
//active pixel index limit = filter_radius+16 = 4+16 = 20
//is that correct?


if(  
     threadIdx.y>=filter_radius && threadIdx.x>=filter_radius &&
     threadIdx.x < 20 && threadIdx.y < 20
  )
{ 

    float value = 0.0;

    for(int i=-filter_radius; i<=filter_radius; i++)
        for(int j=-filter_radius; j<=filter_radius; j++)
        {
            int fx = i+filter_radius;
            int fy = j+filter_radius;

            int ty = threadIdx.y+i;
            int tx = threadIdx.x+j;

            value += ((float)tile[ty*24+tx])*t_filter[fy*filterWidth+fx];
        }
    outputChannel[py*numCols+px] = (unsigned char) value; 
}     
\uuuu全局\uuuuu无效高斯模糊(常量无符号字符*常量输入通道,
无符号字符*常量输出通道,
int numRows,int numCols,
常量浮点*常量筛选器,常量整数筛选器宽度)
{
int filter_radius=(int)(filterWidth/2);//获取过滤器“radius”
intx=blockDim.x*blockIdx.x+threadIdx.x;
int y=blockDim.y*blockIdx.y+threadIdx.y;
如果(x>=(numCols+过滤器半径)| | y>=(numRows+过滤器半径))
返回;
int px=x-滤波器的半径;
int py=y-过滤器的半径;
//夹紧
如果(px=numRows)py=numRows-1;
__共享无符号字符块[(16+8)*(16+8)];//16个活动像素+2*过滤器半径
tile[threadIdx.y*24+threadIdx.x]=输入通道[py*numCols+px];
__同步线程();
//这里一切正常:如果我这样做了
//outputChannel[py*numCols+px]=平铺[threadIdx.y*24+threadIdx.x];
//然后我就能看到输入图像的完美重建。
//缓存过滤器
__共享浮点数t_过滤器[81];//9x9转换掩码
if(threadIdx.x==0&&threadIdx.y==0)
{
对于(int i=0;i=filter\u radius&&threadIdx.x>=filter\u radius&&
threadIdx.x<20&&threadIdx.y<20
)
{ 
浮动值=0.0;

对于(int i=-filter_radius;i,在您的实现中,每个块永远不会计算边界(在边缘的一个过滤半径内)像素的模糊。这意味着您希望块重叠以便覆盖边界。如果查看每个块的
x
索引的域

int x = blockDim.x*blockIdx.x+threadIdx.x;
考虑到上述特定的内核执行,我们将

blockIdx.x = 0: x = [0,23]
blockIdx.x = 1: x = [24,46]
... etc

正如你所看到的,每个块都会考虑你的图像的一个独特部分,但是你已经告诉每个块不在边界上计算。这意味着每个块的边界从你的计算中被省略(因此,你的图像中的黑色网格)。 你需要计算你的指数,比如

int x = (blockDim.x-2*filter_radius)*blockIdx.x+threadIdx.x;
现在我们的
x
索引的域将如下所示

blockIdx.x = 0: x = [0,23]
blockIdx.x = 1: x = [16,39]
... etc

From:“寻求调试帮助的问题”(“为什么此代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现该问题所需的最短代码。没有明确问题说明的问题对其他读者不有用。请参阅:CUDA内核本身不是MCVE。最好,您的MCVE应该是独立的,不需要OpenCV或其他框架,也不需要单独的数据文件。很抱歉,我在这里浏览了一些CUDA问题,没有一个问题显示了全部内容。其中一些可能显示内核调用本身,但我在处理这些问题时非常确定h images,它们都不提供自己的函数来读取和输出图像文件,以避免使用OpenCV或其他框架。我正在添加内核调用并发布编译所需的其他文件的链接。我认为这应该足够了。至于这段代码应该做些什么,我认为已经解释得非常清楚了。
blockIdx.x = 0: x = [0,23]
blockIdx.x = 1: x = [16,39]
... etc