Вопрос по c++, image – CUDA маленькое ядро 2d свертка - как это сделать
=======================================================================

Я несколько дней экспериментировал с ядрами CUDA, чтобы выполнить быструю двумерную свертку между изображением 500x500 (но я также мог бы варьировать размеры) и очень маленьким двумерным ядром (ядром лапласиана 2d, так что это тоже ядро 3x3). маленький, чтобы получить огромное преимущество со всеми нитями куда).

Я создал классическую реализацию CPU (две для циклов, так легко, как вы думаете), а затем я начал создавать ядра CUDA.

После нескольких разочаровывающих попыток выполнить более быструю свертку я получил следующий код:
<http://www.evl.uic.edu/sjames/cs525/final.html> (см. раздел «Общая память»), он в основном позволяет блоку потоков 16x16 загружать все необходимые данные свертки в общую память и затем выполняет свертку.

Ничего, процессор все еще намного быстрее. Я не пробовал подход FFT, потому что CUDA SDK утверждает, что он эффективен при больших размерах ядра.

Читаете ли вы все, что я написал, мой вопрос:

**how can I perform a fast 2D convolution between a relatively large image and a very small kernel (3x3) with CUDA?**

 что ядро 3x3 не подходит для подхода, основанного на FFT. Лучший способ справиться с этим - вставить ядро в постоянную память (или, если вы используете карту Fermi +, это не должно иметь большого значения).

Поскольку вы знаете размер ядра, самый быстрый способ сделать это - прочитать куски входного изображения / сигнала в общую память и выполнить развернутую операцию умножения и сложения.

--

Если вы готовы использовать библиотеки для выполнения этой операции[ArrayFire](https://github.com/arrayfire/arrayfire) а также[OpenCV](http://docs.opencv.org/modules/gpu/doc/image_processing.html)
имеют высоко оптимизированные процедуры Convolution, которые могут сэкономить вам много времени на разработку.

Я не слишком знаком с OpenCV, но в ArrayFire вы можете сделать что-то вроде следующего.

```
array kernel = array(3, 3, h_kernel, afHost); // Transfer the kernel to gpu
array image  = array(w, h, h_image , afHost); // Transfer the image  to gpu
array result = convolve2(image, kernel);       // Performs 2D convolution

```

**EDIT**

Дополнительным преимуществом использования ArrayFire является его пакетная операция, позволяющая выполнять свертку параллельно. Вы можете прочитать о том, как свертки поддерживают пакетные операции над[Вот](http://www.arrayfire.com/docs/group__signal__func__convolve2.htm)

Например, если у вас было 10 изображений, которые вы хотите свернуть, используя одно и то же ядро, вы можете сделать что-то вроде следующего:

```
array kernel = array(3, 3, h_kernel, afHost);     // Transfer the kernel to gpu
array images = array(w, h, 10, h_images, afHost); // Transfer the images to gpu
array res    = convolve2(images, kernel); // Perform all operations simultaneously

```

--

Полное раскрытие: я работаю в AccelerEyes и активно работаю над ArrayFire.