Размытие по Гауссу с вопросами БПФ

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

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

    • If true, does it go like this - 1D FFT on every row, and then 1D FFT on every column, then multiply with the 2D kernel and then inverse transform of every column and the inverse transform of every row? Or do I have to multiply with a 1D kernel after each 1D FFT Transform?
  2. Теперь я понимаю, что размер ядра должен быть того же размера, что и изображение (строка в случае 1D). Но как это повлияет на края? Нужно ли заполнять края изображения нулями? Если да, то размер ядра должен быть равен размеру изображения до или после заполнения?

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

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

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

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

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

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

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


person rwb    schedule 16.08.2011    source источник
comment
связанные: stackoverflow.com/q/42560434/6338809   -  person Joe'    schedule 24.07.2018


Ответы (2)


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

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

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

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

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

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

Ответ на изменение

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

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

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

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

person Jason B    schedule 16.08.2011
comment
Спасибо за ответ. Теперь я понимаю, что преобразование БПФ состоит из «действительной» и «мнимой» части. Скажем, у меня есть изображение размером 512x512. Какие будут размеры реальной и мнимой частей? Должен ли я умножать их обоих на fft ядра? - person rwb; 16.08.2011
comment
Пожалуйста, смотрите мое редактирование в вопросе. Спасибо. - person rwb; 16.08.2011
comment
Спасибо за ответ. Таким образом, БПФ изображения не меняется, даже если его масштабировать вверх / вниз. Большое спасибо за информацию. - person rwb; 17.08.2011
comment
Извините, я, должно быть, неправильно понял. Если вы масштабируете изображение, вам нужно снова выполнить БПФ. - person Jason B; 18.08.2011

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

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

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

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

person Phonon    schedule 16.08.2011
comment
Спасибо за ответ. Пожалуйста, смотрите мое редактирование в вопросе. - person rwb; 16.08.2011