Каков наиболее эффективный способ реализации фильтра свертки в пиксельном шейдере?

Реализация свертки в пиксельном шейдере несколько дорогостоящая по отношению к очень большому количеству выборки текстур.

Прямым способом реализации фильтра свертки является создание N x N запросов на фрагмент с использованием двух циклов для каждого фрагмента. Простой расчет говорит о том, что изображение 1024x1024, размытое галорианским ядром 4x4, нуждается в поиске 1024 x 1024 x 4 x 4 = 16M.

Что можно сделать по этому поводу?

  • Можно ли использовать некоторую оптимизацию, которая потребует меньше поисков? Меня не интересуют оптимизации, зависящие от ядра, например, для гауссовых (или они специфичны для ядра?)
  • Можно ли, по крайней мере, сделать эти поиски быстрее, каким-то образом используя локальность пикселей, с которыми можно было бы работать?

Спасибо!

Ответы

Ответ 1

Гауссовские ядра разделяются, что означает, что вы можете выполнить горизонтальный проход сначала, затем вертикальный проход (или наоборот). Это превращает O (N ^ 2) в O (2N). Это работает для всех разделяемых фильтров, а не только для размытия (не все фильтры являются разделимыми, но многие из них, а некоторые "хороши" ).

Или, в частном случае фильтра размытия (Гаусс или нет), которые представляют собой "взвешенные суммы", вы можете воспользоваться интерполяцией текстур, которая может быть быстрее для небольших размеров ядра (но окончательно не для большие размеры ядра).

EDIT: изображение для метода "линейной интерполяции"

The "linear interpolation method"

EDIT (по просьбе Джерри Коффина), чтобы обобщить комментарии:

В методе "фильтра текстур" линейная интерполяция приведет к получению взвешенной суммы соседних текселей в соответствии с обратным расстоянием от места выборки до центра текселя. Это делается с помощью оборудования для текстурирования, бесплатно. Таким образом, 16 пикселей можно суммировать в 4 наборах. Фильтрация текстур может быть использована в дополнение к разделению ядра.

В примере изображения, в левом верхнем углу, ваш образец (круг) попадает в центр текселя. То, что вы получаете, такое же, как "ближайшая" фильтрация, вы получаете это значение texel. В правом верхнем углу вы находитесь посередине между двумя текселями, то, что вы получаете, составляет среднее 50/50 между ними (на фото более светлого шейдера синего). В правом нижнем углу вы выбираете между 4 текселями, но несколько ближе к верхнему левому. Это дает вам средневзвешенное значение для всех 4, но с весом, смещенным к верхнему левому (самый темный оттенок синего).

Следующие предложения приветствуются datenwolf (см. ниже):

"Другие методы, которые я хотел бы предложить, работают в пространстве Фурье, где свертка превращается в простой продукт преобразованного сигнала с преобразованием Фурье и преобразованного ядра Фурье. Хотя преобразование Фурье на самом графическом процессоре довольно утомительно для реализации, по крайней мере, используя OpenGL шейдеры, но это довольно легко сделать в OpenCL. На самом деле я реализую такие вещи с помощью OpenCL, теперь в OpenCL много обработки изображений в моем 3D-движке.

OpenCL специально разработан для работы на графических процессорах. Быстрое преобразование Фурье на самом деле является частью примера кода в статье Википедии OpenCL: en.wikipedia.org/wiki/OpenCL и да, прирост производительности огромен. БПФ выполняет не более O (n log n), наоборот. Представление четкости ядра фильтра может быть предварительно вычислено. Путь FFT → умножается на ядро ​​- > IFFT, что сводится к операциям O (n + 2n log n). Обратите внимание, что фактическая свертка есть только O (n).

В случае сепарабельной, конечной свертки, такой как гауссовское размытие, решение разделения будет превосходить метод Фурье. Но в случае обобщенных, возможных несепарабельных ядер методы Фурье, вероятно, являются самым быстрым доступным методом. OpenCL отлично интегрируется с OpenGL, например. вы можете использовать буферы OpenGL (текстуры и вершины) для ввода и вывода программ OpenCL. "

Ответ 2

Более чем сепарабельные гауссовские фильтры также вычисляются в O (1):

Существуют рекурсивные вычисления, такие как Deriche one:

http://hal.inria.fr/docs/00/07/47/78/PDF/RR-1893.pdf