2016-06-28 45 views
2

我試圖用cuda實現多個黑色(0)和白色(255)圖像侵蝕,我使用了一個方形(5x5)結構元素。我實現的內核採用unsigned char其中存儲的數組緩衝區nImg圖像200X200 px。以允許多個圖像的侵蝕simultaneosly使一個網格與3D結構:cuda多圖像侵蝕不起作用

  • 每個塊具有strel(5×5)的尺寸
  • 網格具有高度= IMAGE_HEIGHT/blockDim.y寬度= IMAGE_WIDTH/blockDim.xZ = nImg

我已經嘗試來實現它延伸那sample

問題是,如果我存儲一個線程塊考慮的像素爲共享緩衝區塊之間共享的線程; 允許快速內存訪問,該算法無法正常工作。我嘗試更改bindex,對於我犯的錯誤,但我找不到解決方案。

有什麼建議嗎?

這裏是我的代碼:

//strel size 
#define STREL_W 5 
#define STREL_H 5 

// distance from the cente of strel to strel width or height 
#define R (STREL_H/2) 

//size of the 2D region that each block consider i.e all the neighborns that each thread in a block consider 
#define BLOCK_W (STREL_W+(2*R)) 
#define BLOCK_H (STREL_H+(2*R)) 

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

    //array stored in shared memory,that contain all pixel neighborns that each thread in a block consider 
    __shared__ unsigned char fast_acc_arr[BLOCK_W*BLOCK_H]; 

    // map thread in a 3D structure 
    int col = blockIdx.x * STREL_W + threadIdx.x -R ; 
    int row = blockIdx.y * STREL_H + threadIdx.y -R ; 
    int plane = blockIdx.z * blockDim.z + threadIdx.z; 

    // check if a foreground px of strel is not contain in a region of the image with size of strel (if only one px is not contain the image is eroded) 
    bool is_contain = true; 


    // clamp to edge of image 
    col = max(0,col); 
    col = min(col,w-1); 

    row = max(0,row); 
    row = min(row,h-1); 

    //map each thread in one dim coord to map 3D structure(grid) with image buffer(1D) 
    unsigned int index = (plane * h * w) + (row * w) + col; 

    unsigned int bindex = threadIdx.y * blockDim.y + threadIdx.x; 


    //each thread copy its pixel of the block to shared memory (shared with thread of a block) 
    fast_acc_arr[bindex] = buffer_in[index]; 

    __syncthreads(); 



    //the strel must be contain in image, thread.x and thread.y are the coords of the center of the mask that correspond to strel in image, and it must be contain in image 
    if((threadIdx.x >= R) && (threadIdx.x < BLOCK_W-R) && (threadIdx.y >= R) && (threadIdx.y <BLOCK_H-R)){ 

     for(int dy=-R; dy<=R; dy++){ 
      if(is_contain == false) 
      break; 

      for (int dx = -R ; dx <= R; dx++) { 

       //if only one element in mask is different from the value of strel el --> the strel is not contain in the mask --> the center of the mask is eroded (and it's no necessary to consider the other el of the mask this is the motivation of the break) 
       if (fast_acc_arr[bindex + (dy * blockDim.x) + dx ] != 255){ 

        buffer_out[index ] = 0; 
        is_contain = false; 
        break; 
       } 
      } 
     } 
     // if the strel is contain into the image the the center is not eroded 
     if(is_contain == true) 
      buffer_out[index] = 255; 
     } 

} 

這是我的內核設置:

dim3 block(5,5,1); 
dim3 grid(200/(block.x),200/(block.y),nImg); 

我的內核調用:

erode_multiple_img_SM<<<grid,block>>>(dimage_src,dimage_dst,200,200); 

我的圖像輸入和輸出:

輸入:input輸出(150拋光輪元素):output

代碼而不共享存儲器(低速):

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



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

    bool is_contain = true; 
    col = max(0,col); 
    col = min(col,w-1); 

    row = max(0,row); 
    row = min(row,h-1); 



    for(int dy=-STREL_H/2; dy<=STREL_H/2; dy++){ 
     if(is_contain == false) 
      break; 
     for (int dx = -STREL_W/2 ; dx <= STREL_W/2; dx++) { 
      if (buffer_in[(plane * h * w) +(row + dy) * w + (col + dx) ] !=255){ 
       buffer_out[(plane * h * w) + row * w + col ] = 0; 
       is_contain = false; 
       break; 
      } 
     } 
    } 
    if(is_contain == true) 
     buffer_out[(plane * h * w) + row * w +col ] = 255; 

} 

修訂版算法

我嘗試遵循samples做卷積。我改變輸入圖像,現在有512×512大小和我寫的算法:

#define STREL_SIZE 5 


#define TILE_W 16 
#define TILE_H 16 

#define R (STREL_H/2) 

#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_W +STREL_SIZE ]; 

    // global mem address of this thread 
    int col = blockIdx.x * blockDim.x + threadIdx.x; 
    int row = blockIdx.y * blockDim.y + threadIdx.y; 

    int plane = blockIdx.z * blockDim.z +threadIdx.z; 

    int gLoc = (plane*h/w)+ row*w +col; 

    bool is_contain = true; 

    // load cache (32x32 shared memory, 16x16 threads blocks) 
    // each threads loads four values from global memory into shared mem 
    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(); 


    //buffer_out[gLoc] = data[threadIdx.x][threadIdx.y]; 

     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; 
     } 

}

我的內核設置現在是:

dim3 block(16,16); 
dim3 grid(512/(block.x),512/(block.y),nImg); 

輸入: input

輸出: output

似乎圍裙的像素不傳至輸出緩衝器copyied

+0

請改善您問題中代碼的格式。這是很難閱讀張貼。 – talonmies

+0

我評論它並縮進,我希望不難用這個編輯來閱讀 – userfi

回答

1

您可能需要閱讀更詳細的說明和更好的例子代碼就如何實現圖像卷積CUDA以下鏈接內核功能。

http://igm.univ-mlv.fr/~biri/Enseignement/MII2/Donnees/convolutionSeparable.pdf

https://www.evl.uic.edu/sjames/cs525/final.html

基本上使用尺寸(5×5)的卷積濾波器並不意味着設置線程塊的大小爲(5×5)。

典型地,用於不可分離的卷積,可以使用尺寸的螺紋塊(16×16),來計算(16×16)的輸出圖像上的像素的塊。要達到此目的,您需要使用(16 x 16)線程協作讀取從輸入圖像到共享內存的((2 + 16 + 2)x(2 + 16 + 2))像素塊。

+0

我已經實現了沒有共享內存的算法,它能正常工作,我會發布它。 thx爲您的答案。 – userfi

+0

@userfi所以現在你知道你對多圖像沒有問題。這只是使用共享內存的一個問題。 – kangshiyin

+0

是的,但我解決不了。我將閱讀您的鏈接以瞭解有關共享內存映射的信息。 – userfi