Border check in image processing

别来无恙 提交于 2019-12-14 03:14:40

问题


I want to take care the border conditions while handling any filters in image processing .I am extrapolating the border and creating the new boundary.For example I am having 4x3 input :

//Input
int image[4][3] = 
1 2 3 4 
2 4 6 8 
3 6 9 12

//Output
int extensionimage[6][5] =
1 1 2 3 4 4
1 1 2 3 4 4 
2 2 4 6 8 8
3 3 6 9 12 12
3 3 6 9 12 12

My code :

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

void padd_border(int *img,int *extension,int width,int height);

int main(){
    int width = 4,height = 3;
    int *img =  new int[(width) * (height)];
    for(int j = 0;j < height; j++){
        for(int i = 0;i < width; i++){
            img[j*width + i] = (i+1)*(j+1);
            printf("%d\t",img[j*width + i]);
        }
    }
    //Allocate memory for signal extension
    int *extension =  new int[(width + 2) * (height + 2)];

    //Check memory allocation
    if (!extension)
        return 0;

    // init to zero
    memset(extension, 0, sizeof(int)*(width + 2) * (height + 2));

    //Padd the input for border conditions
    padd_border(img,extension,width,height);
    //HERE using "extension" input for dummy functionality 

    delete[] extension;
    delete[] img;

    return 0;
}

void padd_border(int *image,int *extension,int width,int height){

    //   Create image extension
    for (int i = 0; i < height; ++i)
    {
        memcpy(extension + (width + 2) * (i + 1) + 1, image + width * i, width * sizeof(int));
        extension[(width + 2) * (i + 1)] = image[width * i];
        extension[(width + 2) * (i + 2) - 1] = image[width * (i + 1) - 1];
    }

    //   Fill first line of image extension
    memcpy(extension, extension + width + 2, (width + 2) * sizeof(int));
    //   Fill last line of image extension
    memcpy(extension + (width + 2) * (height + 1), extension + (width + 2) * height, (width + 2) * sizeof(int));
}

My questions:

1) I don't want to create "extension" buffer. I want to reuse the image for doing the extrapolation. So is it possible ?

2) How can I use Neon to do so wrt my above code ?

After Changing the code according to PaulR pseudo code ,I am getting some strange results :

Editing My question for run time issues during fixing the border
My Input :

221 220 221 223 230 233 234 235 ..
71  73  70  70  92  130 141 143 ..

I want to this operation to get destination :

 -1*v_m1_m1 + 0*v_m1_0 + 1*v_m1_p1
 -1*v_0_m1  + 0*v_0_0  + 1*v_0_p1       ->V_OUT
 -1*v_p1_m1 + 0*v_p1_0 + 1*v_p1_p1 

after changing the code for border I am getting below valuse:

    221 221 221 221    221 220 221 223   230 233 234 235
    221 221 221 221    221 220 221 223   230 233 234 235
    71  71  71  71     71  73  70  70    92  130 141 143

In scalar code if I want to calculate for 221 (@i,j =0,0) ,With border it is looking like this :

 221 221 220
 221 221 220
 71  71  73

But with vectorization in Neon ,I am getting which is wrong

v_m1_m1.0  v_m1_0.1  v_m1_p1.2
v_0_m1.0   v_0_0.1   v_0_p1.2
v_p1_m1.0  v_p1_0.1  v_p1_p1.2


221 221 230 
221 221 230
71  71  92

my pseudo code:

for i = 0 to nrows - 1
        // init row pointers
        p_row_m1 = src + src_width * MAX(i-1, 0);           // pointing to minus1 row
        p_row_0  = src + src_width * i;                     // pointing to current row
        p_row_p1 = src + src_width * MIN(i+1, src_width-1); // pointing to plus1 row

        v_m1_m1 = vdupq_n_u32(p_row_m1[0]);   // fill left vector from src[i-1][0]
        v_0_m1  = vdupq_n_u32(p_row_0[0]);    // fill left vector from src[i][0]
        v_p1_m1 = vdupq_n_u32(p_row_p1[0]);   // fill left vector from src[i+1][0]

        v_m1_0 = vld1q_u32(&p_row_m1[0]);   // load center vector from src[i-1][0..7]
        v_0_0  = vld1q_u32(&p_row_0[0]);    // load center vector from src[i][0..7]
        v_p1_0 = vld1q_u32(&p_row_p1[0]);   // load center vector from src[i+1][0..7]

        for j = 0 to (ncols - 4) step 4         // assuming 4 elements per SIMD vector

            v_m1_p1  = vld1q_u32(&p_row_m1[j+4]);   // load right vector from src[i-1][0..7]
            v_0_p1   = vld1q_u32(&p_row_0[j+4]);    // load right vector from src[i][0..7]
            v_p1_p1  = vld1q_u32(&p_row_p1[j+4]);   // load right vector from src[i+1][0..7]
    //
    // you now have a 3x3 arrangement of vectors on which
    // you can perform a neighbourhood operation and generate
    // 16 output pixels for the current iteration:
    //
    //    v_m1_m1  v_m1_0  v_m1_p1
    //    v_0_m1   v_0_0   v_0_p1
    //    v_p1_m1  v_p1_0  v_p1_p1
    //
    //               |
    //               V
    //
    //              v_out
    vst1q_s32(v_out, &image_out[i][j])      // store output vector at image_out[i][j..j+15]
    // shuffle vectors so that we can use them on next iteration
    v_m1_m1 = v_m1_0
    v_m1_0  = v_m1_p1

    v_0_m1  = v_0_0 
    v_0_0   = v_0_p1

    v_p1_m1 = v_p1_0
    v_p1_0  = v_p1_p1

  end_for
  // for final iteration we need to handle right edge pixels...
  v_m1_p1 = vdupq_n_u32(p_row_m1[ncols-1])     // fill right vector from image[i-1][ncols-1]
  v_0_p1  = vdupq_n_u32(p_row_0[ncols-1])       // fill right vector from image[i][ncols-1]
  v_p1_p1 = vdupq_n_u32(p_row_p1[ncols-1])     // fill right vector from image[i+1][ncols-1]
  // calculate v_out as above
  vst1q_s32(v_out, &image_out[i][j])        // store output vector at image_out[i][ncols_16..ncols-1]
end_for

回答1:


Here is some pseudo code for performing a 3x3 neighbourhood operation using SIMD with replicated edge pixels. Input image is image[nrows][ncols], output image is image_out[nrows][ncols].

for i = 0 to nrows - 1
  // init row pointers
  p_row_m1 = &image[max(i-1, 0)][0]         // pointer to start of row i-1
  p_row_0 = &image[i][0]                    // pointer to start of row i
  p_row_p1 = &image[min(i+1, ncols-1)][0]   // pointer to start of row i+1
  v_m1_m1 = init_vec(p_row_m1[0])           // fill left vector from image[i-1][0]
  v_0_m1 = init_vec(p_row_0[0])             // fill left vector from image[i][0]
  v_p1_m1 = init_vec(p_row_p1[0])           // fill left vector from image[i+1][0]
  v_m1_0 = load_vec(&p_row_m1[0])           // load centre vector from image[i-1][0..15]
  v_0_0 = load_vec(&p_row_0[0])             // load centre vector from image[i][0..15]
  v_p1_0 = load_vec(&p_row_p1[0])           // load centre vector from image[i+1][0..15]
  for j = 0 to (ncols - 16) step 16         // assuming 16 elements per SIMD vector
    v_m1_p1 = load_vec(&p_row_m1[j+16])     // load right vector from image[i-1][0..15]
    v_0_p1 = load_vec(&p_row_0[j+16])       // load right vector from image[i][0..15]
    v_p1_p1 = load_vec(&p_row_p1[j+16])     // load right vector from image[i+1][0..15]
    //
    // you now have a 3x3 arrangement of vectors on which
    // you can perform a neighbourhood operation and generate
    // 16 output pixels for the current iteration:
    //
    //    v_m1_m1  v_m1_0  v_m1_p1
    //    v_0_m1   v_0_0   v_0_p1
    //    v_p1_m1  v_p1_0  v_p1_p1
    //
    //               |
    //               V
    //
    //              v_out
    //
    store_vec(v_out, &image_out[i][j])      // store output vector at image_out[i][j..j+15]
    // shuffle vectors so that we can use them on next iteration
    v_m1_m1 = v_m1_0
    v_m1_0  = v_m1_p1
    v_0_m1  = v_0_0 
    v_0_0   = v_0_p1
    v_p1_m1 = v_p1_0
    v_p1_0  = v_p1_p1
  end_for
  // for final iteration we need to handle right edge pixels...
  v_m1_p1 = init_vec(p_row_m1[ncols-1])     // fill right vector from image[i-1][ncols-1]
  v_0_p1 = init_vec(p_row_0[ncols-1])       // fill right vector from image[i][ncols-1]
  v_p1_p1 = init_vec(p_row_p1[ncols-1])     // fill right vector from image[i+1][ncols-1]
  // calculate v_out as above
  store_vec(v_out, &image_out[i][j])        // store output vector at image_out[i][ncols_16..ncols-1]
end_for

Note that this assumes 16 pixels per vector and also that ncols is a multiple of 16.



来源:https://stackoverflow.com/questions/29518845/border-check-in-image-processing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!