Ядро OpenCL для Canny

Я пытаюсь достичь Canny Edge Detection с помощью ядра OpenCL очень простым и простым способом.

Я использую оригинальное ядро ​​SobelFilter для выполнения таких шагов, как немаксимальное подавление и пороговое значение.

Но я теряюсь в достижении пикселей и выполнении математических расчетов с ними с помощью:

__kernel void sobel_filter(__global uchar4* inputImage, __global uchar4* outputImage)

Не могли бы вы дать мне идеи или показать мне простые примеры для достижения этого? Это будет высоко оценено. С уважением.


person Community    schedule 04.06.2017    source источник
comment
какую ошибку вы получаете при запуске?   -  person huseyin tugrul buyukisik    schedule 05.06.2017
comment
stackoverflow.com/questions/17815687/   -  person huseyin tugrul buyukisik    schedule 05.06.2017
comment
Как вы передавали данные в GPU? Как буфер изображения или как простой буфер?   -  person huseyin tugrul buyukisik    schedule 05.06.2017
comment
hypot означает sqrt(x² + y²), а деление на 2 означает, что он берет только половину по такой причине, как использование char (так что его половина от 255 максимум) для буферов вместо uchar? Взятие sqrt из float4 также означает sqrt каждого элемента (4 из них) отдельно, как здесь для красного, зеленого и синего. convert_ эффективно конвертировать (вероятно)   -  person huseyin tugrul buyukisik    schedule 05.06.2017


Ответы (2)


Фильтр Собеля изначально разделим на измерения 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
comment
Спасибо, г-н Хусейн, за ваш ответ и руководство. Это сработало как прелесть! - person ; 06.06.2017
comment
Приложите больше усилий к стороне C++. Тогда у вас не будет никаких трудностей, если вы когда-нибудь перейдете на sycl и аналогичный синтаксический обновленный сахар opencl. - person huseyin tugrul buyukisik; 06.06.2017

Вычислительная библиотека ARM имеет продуманную реализацию Canny CL ядро

person kanna    schedule 06.06.2017
comment
Спасибо за руководство! - person ; 06.06.2017