Фильтр Собеля изначально разделим на измерения X и Y при выполнении ядра. Таким образом, можно сканировать только по X, или только по Y, или по обоим в одном и том же цикле ядра, чтобы добиться обнаружения краевых функций.
Используя совет пользователя azer89
здесь: Обработка изображений — реализация фильтра Собеля
Я подготовил это ядро:
__kernel void postProcess(__global uchar * input, __global uchar * output)
{
int resultImgSize=1024;
int pixelX=get_global_id(0)%resultImgSize; // 1-D id list to 2D workitems(each process a single pixel)
int pixelY=get_global_id(0)/resultImgSize;
int imgW=resultImgSize;
int imgH=resultImgSize;
float kernelx[3][3] = {{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}};
float kernely[3][3] = {{-1, -2, -1},
{0, 0, 0},
{1, 2, 1}};
// also colors are separable
int magXr=0,magYr=0; // red
int magXg=0,magYg=0;
int magXb=0,magYb=0;
// Sobel filter
// this conditional leaves 10-pixel-wide edges out of processing
if( (pixelX<imgW-10) && (pixelY<imgH-10) && (pixelX>10) && (pixelY>10) )
{
for(int a = 0; a < 3; a++)
{
for(int b = 0; b < 3; b++)
{
int xn = pixelX + a - 1;
int yn = pixelY + b - 1;
int index = xn + yn * resultImgSize;
magXr += input[index*4] * kernelx[a][b];
magXg += input[index*4+1] * kernelx[a][b];
magXb += input[index*4+2] * kernelx[a][b];
magYr += input[index*4] * kernely[a][b];
magYg += input[index*4+1] * kernely[a][b];
magYb += input[index*4+2] * kernely[a][b];
}
}
}
// magnitude of x+y vector
output[(pixelX+pixelY*resultImgSize)*4] =sqrt((float)(magXr*magXr + magYr*magYr)) ;
output[(pixelX+pixelY*resultImgSize)*4+1]=sqrt((float)(magXg*magXg + magYg*magYg)) ;
output[(pixelX+pixelY*resultImgSize)*4+2]=sqrt((float)(magXb*magXb + magYb*magYb)) ;
output[(pixelX+pixelY*resultImgSize)*4+3]=255;
}
Здесь индексы были умножены на 4, потому что они интерпретировались как массив uchar
в качестве параметров ядра. uchar
— это один байт в OpenCL (по крайней мере, для моей системы).
Вот видео об этом:
Пример фильтра Собеля
если это работает и для вас, вы должны принять решение azer89
. Но это не очень оптимизировано и может занять 1-2 миллисекунды для низкоуровневого графического процессора и даже больше, если только ЦП для изображения 1024x1024. Данные изображения отправляются в буфер OpenCL (не буфер изображения) с использованием массива байтов (языка C#) и параметров запуска ядра:
- Глобальный диапазон = 1024*1024 (обработка 1 потока на пиксель)
- Локальный диапазон = 256 (это не важно)
- Размер копии буфера 1024*1024*4 (байт для формата rgba)
также 2D-массивы kernelx и kernely здесь были float
, поэтому создание их char
могло сделать его быстрее. Также вы можете проверить результаты (зажать, разделить, ...), если результат выглядит намного более красочным, чем ожидалось. Представление/интерпретация на стороне хоста также важна для обработки недостаточного и чрезмерного количества цветов.
person
huseyin tugrul buyukisik
schedule
05.06.2017
sqrt(x² + y²)
, а деление на 2 означает, что он берет только половину по такой причине, как использование char (так что его половина от 255 максимум) для буферов вместо uchar? Взятие sqrt из float4 также означает sqrt каждого элемента (4 из них) отдельно, как здесь для красного, зеленого и синего. convert_ эффективно конвертировать (вероятно) - person huseyin tugrul buyukisik   schedule 05.06.2017