Размытие по Гауссу с БПФ Вопросы - PullRequest
5 голосов
/ 16 августа 2011

У меня есть текущая реализация Gaussian Blur, использующая обычную свертку. Он достаточно эффективен для небольших ядер, но как только размер ядра становится немного больше, производительность падает. Итак, я думаю реализовать свертку с использованием БПФ. У меня никогда не было опыта обработки изображений, связанных с БПФ, поэтому у меня есть несколько вопросов.

  1. Можно ли разделить свертку на основе 2D БПФ на две одномерные свертки?

    • Если true, то идет ли это так - 1D FFT в каждой строке, а затем 1D FFT в каждом столбце, затем умножить на двумерное ядро ​​и затем обратное преобразование каждого столбца и обратное преобразование каждой строки? Или мне нужно умножать на 1D ядро ​​после каждого 1D БПФ-преобразования?
  2. Теперь я понимаю, что размер ядра должен соответствовать размеру изображения (строка в случае 1D). Но как это повлияет на края? Нужно ли дополнять края изображения нулями? Если так, то размер ядра должен быть равен размеру изображения до или после заполнения?

Кроме того, это проект C ++, и я планирую использовать kissFFT, поскольку это коммерческий проект. Вы можете предложить любые лучшие альтернативы. Спасибо.

РЕДАКТИРОВАТЬ: Спасибо за ответы, но у меня есть еще несколько вопросов.

  1. Я вижу, что мнимая часть входного изображения будет иметь все нули. Но будет ли на выходе мнимая часть также быть нулями? Нужно ли умножать ядро ​​Гаусса на вещественную и мнимую части?

  2. У меня есть экземпляры одного и того же изображения, которые будут размыты в разных масштабах, то есть одно и то же изображение масштабировано до разных размеров и размыто при разных размерах ядра. Нужно ли выполнять БПФ каждый раз, когда я масштабирую изображение, или я могу использовать одно и то же БПФ?

  3. Наконец, если я хотел визуализировать БПФ, я понимаю, что к БПФ должен применяться фильтр журнала. Но я действительно заблудился, какую часть следует использовать для визуализации БПФ? Реальная часть или мнимая часть.

  4. Также для изображения размером 512x512, что будет размером с реальной и мнимой частями. Будут ли они одинаковой длины?

Еще раз спасибо за ваши подробные ответы.

Ответы [ 2 ]

12 голосов
/ 16 августа 2011
  1. 2-D БПФ является отделимым, и вы правы в том, как его выполнить, за исключением того, что вы должны умножить на 2-D БПФ 2D-ядра. Если вы используете kissfft, более простой способ выполнить 2-D FFT - просто использовать kiss_fftnd в каталоге инструментов пакета kissfft. Это сделает многомерное БПФ.

  2. Размер ядра не обязательно должен быть определенного размера. Если ядро ​​меньше, чем изображение, вам нужно просто обнулить его до размера изображения перед выполнением 2-D FFT. Вы также должны обнулять края изображения, так как конволюция, выполняемая умножением в частотной области, фактически является круговой сверткой, и результаты обертываются по краям.

Итак, подведем итог (учитывая, что размер изображения составляет M x N):

  1. придумать двумерное ядро ​​любого размера (U x V)
  2. заполнение нулями ядра до (M + U-1) x (N + V-1)
  3. возьмите 2-D FFT ядра
  4. заполнение нулями изображения до (M + U-1) x (N + V-1)
  5. взять 2-D БПФ изображения
  6. умножить FFT ядра на FFT изображения
  7. принять обратное 2-D БПФ результата
  8. обрезать мусор по краям

Если вы выполняете один и тот же фильтр несколько раз для разных изображений, вам не нужно выполнять 1-3 каждый раз.

Примечание: Размер ядра должен быть достаточно большим, чтобы это было быстрее, чем прямое вычисление свертки. Кроме того, реализовали ли вы свою прямую свертку, воспользовавшись тем, что двумерный гауссов фильтр является отделимым ( см. несколько абзацев в разделе «Механика»)? То есть вы можете выполнить 2-D свертку как 1-D свертки в строках, а затем в столбцах. Я обнаружил, что это быстрее, чем большинство подходов, основанных на FFT, если ядра не очень большие.

Ответ на редактирование

  1. Если вход действительный, выход будет сложным, за исключением редких случаев. БПФ вашего гауссова ядра также будет сложным, поэтому умножение должно быть сложным умножением. Когда вы выполняете обратное БПФ, вывод должен быть реальным, поскольку ваше входное изображение и ядро ​​реальны. Выходные данные будут возвращены в виде сложного массива, но мнимые компоненты должны быть нулевыми или очень маленькими (ошибка с плавающей запятой) и могут быть отброшены.

  2. Если вы используете одно и то же изображение, вы можете повторно использовать изображение FFT, но вам нужно будет обнулить его, исходя из вашего самого большого размера ядра. Вам нужно будет вычислить БПФ всех разных ядер.

  3. Для визуализации следует использовать величину комплексного выхода. Логарифмическая шкала просто помогает визуализировать меньшие компоненты вывода, когда более крупные компоненты заглушают их в линейном масштабе. Шкала Децибел часто используется и задается либо 20*log10(abs(x)), либо 10*log10(x*x'), которые эквивалентны. (x - комплексное выходное значение FFT, а x' - комплексное сопряжение x).

  4. Вход и выход БПФ будут одинакового размера. Также действительные и мнимые части будут иметь одинаковый размер, поскольку одно действительное и одно мнимое значение образуют одну выборку.

5 голосов
/ 16 августа 2011

Помните, что свертка в пространстве эквивалентна умножению в частотной области.Это означает, что как только вы выполняете БПФ как для изображения, так и для маски (ядра), вам нужно только выполнить умножение по точкам, а затем выполнить ОБПФ результата.Сказав это, вот несколько слов предостережения.

Вы, вероятно, знаете, что при цифровой обработке сигналов мы часто используем круговую свертку , а не линейнуюсвертка .Это происходит из-за любопытной периодичности .Проще говоря, это означает, что DFT (и FFT, который является его вычислительно эффективным вариантом) предполагает, что ваш сигнал является периодическим, а когда вы фильтруете свой сигнал таким образом - предположим, что ваше изображение N x M пикселей - что требуется пиксель в (1, m ) соседу или пиксель в ( N , m ) длянекоторые м <<em> М .Вы сигнализируете виртуально вокруг себя.Это означает, что ваша гауссова маска будет усреднять пиксели в дальнем правом углу с пикселями в дальнем левом углу, и то же самое относится к верху и низу.Это может быть или не быть желательным, но в общем случае все равно приходится иметь дело с краевыми артефактами.Однако гораздо проще забыть об этой проблеме при работе с умножением БПФ, потому что проблема перестает быть очевидной.Есть много способов решить эту проблему.Лучший способ - это просто дополнить изображение нулями и позже удалить лишние пиксели.

Очень полезная вещь при использовании гауссовского фильтра в частотной области состоит в том, что вам никогда не придется брать его FFT.Хорошо известен тот факт, что преобразование Фурье гауссовского является гауссовским (некоторые технические детали здесь ).Все, что вам нужно было бы сделать, это дополнить изображение нолями (сверху и снизу), сгенерировать гауссиан в частотной области, умножить их вместе и взять IFFT.Тогда все готово.

Надеюсь, это поможет.

...