Как наиболее эффективно реализовать сверточный фильтр в пиксельном шейдере? - PullRequest
14 голосов
/ 09 марта 2011

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

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

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

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

Спасибо!

Ответы [ 3 ]

18 голосов
/ 09 марта 2011

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

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

РЕДАКТИРОВАТЬ: изображение для метода "линейной интерполяции"

The

РЕДАКТИРОВАТЬ (по запросу Джерри Коффина), чтобы суммировать комментарии:

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

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

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

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

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

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

4 голосов
/ 09 марта 2011

Гауссовы фильтры не только разделимы, но и вычисляются в O (1):

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

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

3 голосов
/ 09 марта 2011

ответ Ротоглупа на мой вопрос здесь мой смысл прочитать;в частности, этот пост в блоге о размытии по Гауссу действительно помог мне понять концепцию разделимых фильтров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...