Я пишу свою собственную реализацию обнаружения sobel egde. Интерфейс моей функции
void sobel_filter(volatile PIXEL * pixel_in, FLAG *EOL, volatile PIXEL * pixel_out, int rows, int cols)
(PIXEL — 8-битный пиксель в оттенках серого)
Для тестирования я изменил интерфейс на:
void sobel_filter (PIXEL пикселей_in [MAX_HEIGHT] [MAX_WIDTH], PIXEL
pix_out [MAX_HEIGHT] [MAX_WIDTH], int row, int cols);
Но, тем не менее, дело в том, что я получаю читать по одному пикселю за раз, что приводит меня к проблеме управления выходными значениями sobel, когда они больше 255 или меньше 0. Если бы у меня была вся картинка с самого начала, Я мог бы нормализовать все выходные значения sobel с их минимальными и максимальными значениями. Но это не возможно для меня.
Это мой код оператора sobel, 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;
}
это версия 2, изменения вносятся только после суммирования весов:
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;
Теперь, для sobel 3×3 оба, кажется, дают хорошие результаты:
;
Но когда я пытаюсь с 5×5 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}};
это становится сложно:
Как видите, для 5х5 результаты довольно плохие, и я не знаю, как нормализовать значения. Есть идеи?
Подумайте о диапазоне значений, которые могут принимать ваши отфильтрованные значения.
Для Sobel 3×3 самое высокое значение X / Y получается, когда пиксели с положительным коэффициентом являются белыми (255), а пиксели с отрицательным коэффициентом — черными (0), что дает в общей сложности 1020. Симметрично, самое низкое значение -1020. После принятия абсолютного значения диапазон составляет от 0 до 1020 = 4 х 255.
Для величины Abs (X) + Abs (Y) вычисление немного сложнее, так как два компонента не могут достичь 1020 одновременно. Если я прав, диапазон от 0 до 1530 = 6 х 255.
Аналогичные цифры для 5×5: 48 x 255 и 66 x 255.
Зная это, вы должны масштабировать значения в меньший диапазон (применить коэффициент уменьшения) и отрегулировать пороговые значения. Логично, что если вы примените коэффициент 3/66 к Собел 5×5, вы вернетесь к аналогичным условиям.
Все зависит от того эффекта, которого вы хотите добиться.
В любом случае, истинный вопрос заключается в следующем: как отфильтрованные значения статистически распределяются для типичных изображений? Потому что нет необходимости держать дальние хвосты дистрибутива.
Вы должны нормализовать результаты ваших вычислений. Для этого вы должны выяснить, насколько «большой» фильтр со всеми абсолютными значениями. Итак, я делаю это:
for(int i = 0; i < mask.length; i++)
for(int j = 0; j < mask[i].length; j++)
size += Math.abs(mask[i][j]);
Где маска — мой трезвый фильтр каждого размера. Поэтому после применения вашего sobel-фильтра вы должны нормализовать значение в вашем коде, оно должно выглядеть так:
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];
}
}
x_weight /= size;
y_weight /= size;
После этого для визуализации вам нужно сместить значения около 128. Просто сделайте это, если хотите визуализировать изображение. В противном случае вы получите проблемы с последующими вычислениями (например, градиент).
x_weight += 128;
y_weight += 128;
Надеюсь, что это работает и поможет.