Сценарий Д.М., зачем преобразованию Фурье гауссовского кенеля нужен модуль
Недавно я выучил DM_Script для обработки изображений в формате TEM, мне понадобился процесс размытия по Гауссу, и я нашел тот, чье имя называется "Размытие по Гауссу" в http://www.dmscripting.com/recent_updates.html
Этот код реализует алгоритм размытия по Гауссу, умножая быстрое преобразование Фурье (БПФ) исходного изображения на БПФ изображения с ядром Гаусса и, наконец, делая его обратное преобразование Фурье.
Вот часть кода,
// Carry out the convolution in Fourier space
compleximage fftkernelimg:=realFFT(kernelimg) (-> FFT of Gaussian-kernel image)
compleximage FFTSource:=realfft(warpimg) (-> FFT of source image)
compleximage FFTProduct:=FFTSource*fftkernelimg.modulus().sqrt()
realimage invFFT:=realIFFT(FFTProduct)
Вопрос, который я хочу спросить, состоит в следующем: FFTProduct:=FFTSource*fftkernelimg.modulus(). Sqrt()
Почему БПФ с ядром Гаусса нуждается в '.modulus(). Sqrt()' для свертки?
Это связано с тем, что преобразование Фурье гауссовской функции становится другой гауссовской функцией? Или это связано с неким ограничением дискретного преобразования Фурье?
Пожалуйста, ответьте мне Спасибо
1 ответ
Это связано с общим ограничением точности любых числовых вычислений с плавающей запятой. (см. здесь или более подробно здесь)
Вращательный (действительный) гауссиан stand.dev. Сигма должна быть преобразована в гауссианское вращение 100% реальных значений 1 / сигма. Тем не менее, выполнение этого в цифровом виде покажет вам отклонения: Просто попробуйте следующее:
number sigma = 30
number A0 = 1
realimage first := RealImage( "First", 8, 256, 256 )
first = A0 * exp( - (iradius**2/(2*sigma*sigma) ))
first.showimage()
complexImage second := FFT(first)
second.Showimage()
image nonZeroImaginaryMask = ( 0 != second.Imaginary() )
nonZeroImaginaryMask.Showimage()
nonZeroImaginaryMask.SetLimits(0,1)
Когда вы затем умножаете эти сложные изображения (до обратной передачи), вы вносите еще больше ошибок. Используя модуль, можно гарантировать, что преобразованное вперед ядро является чисто вещественным и, следовательно, лучше "демпфирующей" кривой.
Лучшая реализация кода фильтрации FFT фактически создала бы FFT(Gaussian) напрямую с std.dev 1/sigma, поскольку это аналитически правильный результат. Выполнение БПФ ядра имеет смысл, только если ядро (или его БПФ) не известно аналитически.
В целом: при внедрении любых "математических" в программный код может оказаться очень дорого обдумать это с помощью ограничений числовых вычислений в затылке. Сокращайте фактические вычисления всякий раз, когда это возможно (т. Е. Вычисляйте аналитически и используйте результат вместо того, чтобы полагаться на численные вычисления методом грубой силы) и старайтесь по возможности "преобразовывать" уравнения, например, избегайте больших сумм по многим маленьким числам, будьте осторожны при проверке точных числовых значений, старайтесь избегать выражений, которые очень чувствительны к небольшим ошибкам в числах и т. д.