C++ cuda卷积映射

C++ cuda卷积映射,c++,image-processing,cuda,C++,Image Processing,Cuda,我正在尝试为每个线程块复制一个映像补丁,并将其复制到共享内存中 在我的数据被复制后(我使用矩阵< /强>)到共享内存中,我想要一个映射映射共享内存中的掩码的中心,我考虑卷积和图像缓冲区中的掩码的中心。p> 我想要这样做,因为如果我尝试对图像进行卷积,共享内存中掩码的中心似乎与存储在全局内存中的图像缓冲区的中心不对应 在下面的代码中,我编写了一个简单图像黑白腐蚀算法的示例,当我将卷积的结果放入输出图像时,中心似乎不对应 我使用512x512px图像编写样本 我的设置是: //block and g

我正在尝试为每个线程块复制一个映像补丁,并将其复制到共享内存中

在我的数据被复制后(我使用<强>矩阵< /强>)到共享内存中,我想要一个映射映射共享内存中的掩码的中心,我考虑卷积和图像缓冲区中的掩码的中心。p> 我想要这样做,因为如果我尝试对图像进行卷积,共享内存中掩码的中心似乎与存储在全局内存中的图像缓冲区的中心不对应

在下面的代码中,我编写了一个简单图像黑白腐蚀算法的示例,当我将卷积的结果放入输出图像时,中心似乎不对应

我使用512x512px图像编写样本

我的设置是:

//block and grid size
dim3 block(16,16);
dim3 grid(512/(block.x),512/(block.y),1);
这是我的内核:

#define STREL_SIZE 5

#define TILE_W 16
#define TILE_H 16

#define R (STREL_SIZE/2)

//size of tile image + apron
#define BLOCK_W (TILE_W+(2*R))
#define BLOCK_H (TILE_H+(2*R))


 __global__ void erode_multiple_img_SM_v2(unsigned char * buffer_in,
                            unsigned char * buffer_out,
                            int w,int h ){

    // Data cache: threadIdx.x , threadIdx.y
    __shared__ unsigned char data[TILE_W +STREL_SIZE  ][TILE_H +STREL_SIZE ];


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

     // global mem address of this thread
     int gLoc =  row*w +col;


     int x, y;  // image based coordinate



     if((col<w)&&(row<h)) {
         data[threadIdx.x][threadIdx.y]=buffer_in[gLoc];

     if (threadIdx.y > (h-STREL_SIZE))
          data[threadIdx.x][threadIdx.y + STREL_SIZE]=buffer_in[gLoc + STREL_SIZE];

     if (threadIdx.x >(w-STREL_SIZE))
          data[threadIdx.x + STREL_SIZE][threadIdx.y]=buffer_in[gLoc+STREL_SIZE];

     if ((threadIdx.x >(w-STREL_SIZE)) && (threadIdx.y > (h-STREL_SIZE)))
          data[threadIdx.x+STREL_SIZE][threadIdx.y+STREL_SIZE] =     buffer_in[gLoc+2*STREL_SIZE];

     //wait for all threads to finish read
     __syncthreads();

      unsigned char min_value = 255;
      for(x=0;x<STREL_SIZE;x++){
          for(y=0;y<STREL_SIZE;y++){
              min_value = min( (data[threadIdx.x+x][threadIdx.y+y]) , min_value);
              }

          }
      buffer_out[gLoc]= min_value;
      }
}
内核调用改为使用相同的方式:

erode_multiple_img_SM<<<grid,block>>>(dimage_src,dimage_dst,512,512);
侵蚀多个img SM(dimage src,dimage dst,512512);
其中内核的参数为:

  • dimage\u src:包含输入图像的大小为高度x宽度的无符号字符的缓冲区
  • dimage_dst:*包含内核生成的输出图像的大小为**高x宽的无符号字符缓冲区
  • 512:第三个参数是图像的宽度
  • 512:第四个参数是图像的高度
  • 记住我的图像样本是黑白的,但是这个版本的侵蚀也可以使用灰度

    这里是我的工作内核

    #define STREL_W 5
    #define STREL_H 5
    
    #define STREL_SIZE 5
    
    
    #define TILE_W 16
    #define TILE_H 16
    
    #define R (STREL_SIZE/2)
    
    
    #define BLOCK_W (TILE_W+(2*R))
    #define BLOCK_H (TILE_H+(2*R))
    
    __global__ void erode_multiple_img_working(unsigned char * buffer_in,
                                unsigned char * buffer_out,
                                int w,int h ){
    
    
        __shared__ unsigned char fast_acc_mat[BLOCK_w][BLOCK_H];
    
        int ty = threadIdx.y;
        int tx = threadIdx.x;
    
    
        int row_o = blockIdx.y * TILE_W + ty;
        int col_o = blockIdx.x * TILE_H + tx;
    
    
        int row_i = row_o - R;
        int col_i = col_o - R;
    
        //in of img size
        if((row_i >= 0) && (row_i < h) && (col_i >= 0) && (col_i < w) ){
    
            fast_acc_mat[ty][tx] = buffer_in[ row_i * w + col_i];
    
        }
        else{
    
            fast_acc_mat[ty][tx] = 0;
    
        }
    
    
        __syncthreads();
    
    
    
    
    
        if( ty < TILE_H && tx < TILE_W ){
    
            unsigned char min_val=255;
            for(int i = 0; i < STREL_SIZE; i++) {
                for(int j = 0; j < STREL_SIZE; j++) {
    
                    min_val = min( fast_acc_mat[i+ty][j+tx] , min_val );
    
                }
            }
            if(row_o < h && col_o < w)
                    buffer_out[row_o * w + col_o] = min_val;
    
            }
    
         }
    
    <代码>#定义STREL W 5 #定义STREL_H 5 #定义STREL_尺寸5 #定义TILE_W 16 #定义TILE_H 16 #定义R(拉伸尺寸/2) #定义块W(平铺W+(2*R)) #定义块H(平铺H+(2*R)) __全局\uuuuu无效侵蚀\u多重\u img\u工作(无符号字符*缓冲区\u in, 未签名字符*缓冲区输出, 整数w,整数h){ __共享的无符号字符快速存取[块w][块H]; int ty=threadIdx.y; int tx=线程idx.x; int row\u o=块IDX.y*块W+ty; int col_o=blockIdx.x*TILE_H+tx; int row_i=row_o-R; int col_i=col_o-R; //在img尺寸范围内 如果((行i>=0)和&(行i=0)和&(列i 这是我的腐蚀图像(输出):

    我实现了一个方案,显示了Eric描述的算法部分如何在共享内存中加载磁贴的像素:


    您只需要[20][20]个共享内存,而不需要[21][21]。应该改成

    __shared__ unsigned char data[TILE_W + STREL_SIZE-1][TILE_H + STREL_SIZE-1];
    
    另一个问题是数据加载。正确的方法是协同使用(16 x 16)线程从输入读取(16+4)x(16+4)像素以共享内存。这可以分为四个部分:

    1) 第一部分:线程(0:15,0:15)加载像素(0:15,0:15)

    2) 第二部分:线程(0:15,12:15)加载像素(0:15,16:19)

    3) 第三部分:线程(12:15,0:15)加载像素(16:19,0:15)

    4) 第四部分:线程(12:15,12:15)加载像素(16:19,16:19)

    但是在你的代码中,你把索引搞乱了。 对于零件2~4,只有螺纹块中的部分螺纹可以工作,并且还需要额外的边界检查

    对于第二部分,您应该使用线程(0:15,12:15)将像素(0:15,16:19)读取为

    if(threadIdx.y>(平铺H-STREL大小))
    数据[threadIdx.x][threadIdx.y+STREL_SIZE-1]=行+STREL_SIZE-1(平铺W-STREL_SIZE))
    数据[threadIdx.x+STREL_SIZE-1][threadIdx.y]=col+STREL_SIZE-1(TILE_W-STREL_SIZE))&(threadIdx.y>(TILE_H-STREL_SIZE)))
    
    data[threadIdx.x+STREL_SIZE-1][threadIdx.y+STREL_SIZE-1]=(行+STREL_SIZE-1请添加一个。舒尔我将代码放在github中好吗?我不能将所有代码放在帖子中,因为它太大了。但如果您认为这有助于理解问题,我也会将内核调用放在帖子中。代码属于问题,而不是外部链接。这也是如此(“最短代码…在问题本身中)。如果代码对于问题来说太长,那么您没有创建一个合适的。不够好。您如何使用您的内核?
    w
    h
    ?感谢您的回答,现在我很困惑。我不明白您如何映射平铺图像与共享内存的坐标。您能解释一下吗?对于第一部分,我必须更改ge缓冲区的索引_in[gLocl]?然后我还需要将块尺寸更改为20x20?@userfi我认为我的解释足够清楚。我不能做得更好,否则答案太长。我建议你阅读前几天我给你的链接以了解更多细节,它们是完美的教学文档。@Eric我也尝试按照你的描述修改我的代码,但结果类似@Eric也许我理解,网格大小必须是:网格(512/平铺,512/平铺)正确吗?黑色细线不存在。第一部分是平铺x平铺
    erode_multiple_img_SM<<<grid,block>>>(dimage_src,dimage_dst,512,512);
    
    #define STREL_W 5
    #define STREL_H 5
    
    #define STREL_SIZE 5
    
    
    #define TILE_W 16
    #define TILE_H 16
    
    #define R (STREL_SIZE/2)
    
    
    #define BLOCK_W (TILE_W+(2*R))
    #define BLOCK_H (TILE_H+(2*R))
    
    __global__ void erode_multiple_img_working(unsigned char * buffer_in,
                                unsigned char * buffer_out,
                                int w,int h ){
    
    
        __shared__ unsigned char fast_acc_mat[BLOCK_w][BLOCK_H];
    
        int ty = threadIdx.y;
        int tx = threadIdx.x;
    
    
        int row_o = blockIdx.y * TILE_W + ty;
        int col_o = blockIdx.x * TILE_H + tx;
    
    
        int row_i = row_o - R;
        int col_i = col_o - R;
    
        //in of img size
        if((row_i >= 0) && (row_i < h) && (col_i >= 0) && (col_i < w) ){
    
            fast_acc_mat[ty][tx] = buffer_in[ row_i * w + col_i];
    
        }
        else{
    
            fast_acc_mat[ty][tx] = 0;
    
        }
    
    
        __syncthreads();
    
    
    
    
    
        if( ty < TILE_H && tx < TILE_W ){
    
            unsigned char min_val=255;
            for(int i = 0; i < STREL_SIZE; i++) {
                for(int j = 0; j < STREL_SIZE; j++) {
    
                    min_val = min( fast_acc_mat[i+ty][j+tx] , min_val );
    
                }
            }
            if(row_o < h && col_o < w)
                    buffer_out[row_o * w + col_o] = min_val;
    
            }
    
         }
    
    __shared__ unsigned char data[TILE_W + STREL_SIZE-1][TILE_H + STREL_SIZE-1];
    
     if (threadIdx.y > (TILE_H-STREL_SIZE))
          data[threadIdx.x][threadIdx.y + STREL_SIZE-1] = row + STREL_SIZE-1<h ? buffer_in[(row + STREL_SIZE-1)*w + col] : 0;
    
     if (threadIdx.x > (TILE_W-STREL_SIZE))
          data[threadIdx.x + STREL_SIZE-1][threadIdx.y] = col + STREL_SIZE-1<w ? buffer_in[row*w+col + STREL_SIZE-1] : 0;
    
     if ((threadIdx.x > (TILE_W-STREL_SIZE)) && (threadIdx.y > (TILE_H-STREL_SIZE)))
          data[threadIdx.x + STREL_SIZE-1][threadIdx.y + STREL_SIZE-1] = (row + STREL_SIZE-1<h && col + STREL_SIZE-1<w) ? buffer_in[(row + STREL_SIZE-1)*w + col + STREL_SIZE-1] : 0;