Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sobel filter algorithm thresholding (no external libs used)

I am writing my own implementation of the sobel egde detection. My function's interface is

void sobel_filter(volatile PIXEL * pixel_in, FLAG *EOL, volatile PIXEL * pixel_out, int rows, int cols)

(PIXEL being an 8bit greyscale pixel)
For testing I changed the interface to:

void sobel_filter(PIXEL pixels_in[MAX_HEIGHT][MAX_WIDTH],PIXEL pixels_out[MAX_HEIGHT][MAX_WIDTH], int rows,int cols);

But Still, the thing is I get to read one pixel at a time, which brings me to the problem of managing the output values of sobel when they are bigger then 255 or smaller then 0. If I had the whole picture from the start, I could normalize all sobel output values with their min and max values. But this is not possible for me.

This is my sobel operator code, ver1:

PIXEL sobel_op(PIXEL_CH window[KERNEL_SIZE][KERNEL_SIZE]){
    const char x_op[KERNEL_SIZE][KERNEL_SIZE] = { {-1,0,1},
                {-2,0,2},
                {-1,0,1}};

    const char y_op[KERNEL_SIZE][KERNEL_SIZE] = { {1,2,1},
                {0,0,0},
                {-1,-2,-1}};
    short x_weight=0;
    short y_weight=0;
    PIXEL ans;
    for (short i=0; i<KERNEL_SIZE; i++){
        for(short j=0; j<KERNEL_SIZE; j++){
            x_weight+=window[i][j]*x_op[i][j];
            y_weight+=window[i][j]*y_op[i][j];
        }
    }
    short val=ABS(x_weight)+ABS(y_weight);
    //make sure the pixel value is between 0 and 255 and add thresholds
    if(val>200)
        val=255;
    else if(val<100)
        val=0;
    ans=255-(unsigned char)(val);
    return ans;

}

this is ver 2, changes are made only after summing up the weights:

short val=ABS(x_weight)+ABS(y_weight);
unsigned char char_val=(255-(unsigned char)(val));
//make sure the pixel value is between 0 and 255 and add thresholds
if(char_val>200)
    char_val=255;
else if(char_val<100)
    char_val=0;
ans=char_val;
return ans;

Now, for a 3x3 sobel both seem to be giving OK results: ver1;

ver2

But when I try with a 5x5 sobel

    const char x_op[KERNEL_SIZE][KERNEL_SIZE] = { {1,2,0,-2,-1},
                {4,8,0,-8,-4},
                {6,12,0,-12,-6},
                {4,8,0,-8,-4},
                {1,2,0,-2,-1}};

const char y_op[KERNEL_SIZE][KERNEL_SIZE] = { {-1,-4,-6,-4,-1},
                {-2,-8,-12,-8,-2},
                {0,0,0,0,0},
                {2,8,12,8,2},
                {1,4,6,4,1}};

it gets tricky: ver1 ver

As you can see, for the 5x5 the results are quite bad and I don't know how to normalize the values. Any ideas?

like image 732
genau Avatar asked Dec 17 '25 11:12

genau


1 Answers

Think about the range of values that your filtered values can take.

For the Sobel 3x3, the highest X/Y value is obtained when the pixels with a positive coefficient are white (255), and the ones with a negative coefficient are black (0), which gives a total of 1020. Symmetrically, the lowest value is -1020. After taking the absolute value, the range is from 0 to 1020 = 4 x 255.

For the magnitude, Abs(X)+Abs(Y), the computation is a little more complicated as the two components cannot reach 1020 at the same time. If I am right, the range is from 0 to 1530 = 6 x 255.

Similar figures for the 5x5 are 48 x 255 and 66 x 255.

Knowing that, you should rescale the values to a smaller range (apply a reduction coefficient), and adjust the thresholds. Logically, if you apply a coefficient 3/66 to the Sobel 5x5, you will return to similar conditions.

It all depends on the effect that you want to achieve.

Anyway, the true question is: how are the filtered values statistically distributed for typical images ? Because it is unnecessary to keep the far tails of the distribution.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!