python - 使用 Python 对图像进行 FFT

标签 python image fft dft

我在 Python 中的 FFT 实现有问题。我有完全奇怪的结果。
好的,我想打开图像,获取RGB中每个像素的值,然后我需要对其使用fft,然后再次转换为图像。

我的步骤:

1)我像这样在Python中用PIL库打开图像

from PIL import Image
im = Image.open("test.png")

2)我得到像素
pixels = list(im.getdata())

3)我将每个像素分离到 r,g,b 值
for x in range(width):
    for y in range(height):
        r,g,b = pixels[x*width+y]
        red[x][y] = r
        green[x][y] = g
        blue[x][y] = b

4)。假设我有一个像素 (111,111,111)。并像这样对所有红色值使用 fft
red = np.fft.fft(red)

然后:
print (red[0][0], green[0][0], blue[0][0])

我的输出是:
(53866+0j) 111 111

我认为这是完全错误的。我的图像是 64x64,而 gimp 的 FFT 完全不同。实际上,我的 FFT 只给我具有巨大值的数组,这就是为什么我的输出图像是黑色的。

你知道问题出在哪里吗?

[编辑]

我已按照建议更改为
red= np.fft.fft2(red)

之后我缩放它
scale = 1/(width*height)
red= abs(red* scale)

而且,我只得到黑色图像。

[编辑2]

好的,让我们拍一张照片。 test.png

假设我不想打开它并保存为灰度图像。所以我就是这样做的。
def getGray(pixel):
    r,g,b = pixel
    return (r+g+b)/3  

im = Image.open("test.png")
im.load()

pixels = list(im.getdata())
width, height = im.size
for x in range(width):
    for y in range(height):
        greyscale[x][y] = getGray(pixels[x*width+y])  

data = []
for x in range(width):
     for y in range(height):
         pix = greyscale[x][y]
         data.append(pix)

img = Image.new("L", (width,height), "white")
img.putdata(data)
img.save('out.png')

在此之后,我得到了这张图片 greyscale ,没关系。所以现在,我想在我的图像上制作fft,然后再将它保存到新的,所以我这样做
scale = 1/(width*height)
greyscale = np.fft.fft2(greyscale)
greyscale = abs(greyscale * scale)

加载后。将其保存到文件后,我有 bad FFT .所以现在让我们尝试用 gimp 打开 test.png 并使用 FFT 过滤器插件。我得到这张图片,这是正确的 good FFT

我该如何处理?

最佳答案

很好的问题。我从未听说过,但 Gimp Fourier插件看起来很整洁:

A simple plug-in to do fourier transform on you image. The major advantage of this plugin is to be able to work with the transformed image inside GIMP. You can so draw or apply filters in fourier space, and get the modified image with an inverse FFT.



这个想法——对频域数据进行 Gimp 风格的操作并转换回图像——非常酷!尽管使用 FFT 多年,但我从未想过要这样做。与其搞乱 Gimp 插件、C 可执行文件和丑陋之处,不如用 Python 来做这件事!

警告。 我尝试了多种方法来做到这一点,试图从原始输入图像中获得接近输出 Gimp Fourier 图像(带有莫尔条纹的灰色)的东西,但我就是做不到。 Gimp 图像在图像中间看起来有些对称,但它没有垂直或水平翻转,也不是转置对称。我希望该插件使用真正的 2D FFT 将 H×W 图像转换为频域中实值数据的 H×W 数组,在这种情况下将不存在对称性(它只是到-复数 FFT,对于像图像这样的实值输入是共轭对称的)。所以我放弃了对 Gimp 插件正在做的事情进行逆向工程的尝试,而是从头开始研究如何做到这一点。

代码。 很简单:读取图片,应用 scipy.fftpack.rfft 在前导二维得到“频率-图像”,rescale到0-255,保存。

请注意这与其他答案有何不同!无灰度——二维实对实 FFT 在所有三个 channel 上独立发生。否 abs需要:频域图像可以合法地具有负值,如果将它们设为正值,则无法恢复原始图像。 (还有一个不错的功能:不影响图像大小。无论宽度/高度是偶数还是奇数,FFT 前后数组的大小都保持不变。)
from PIL import Image
import numpy as np
import scipy.fftpack as fp

## Functions to go from image to frequency-image and back
im2freq = lambda data: fp.rfft(fp.rfft(data, axis=0),
                               axis=1)
freq2im = lambda f: fp.irfft(fp.irfft(f, axis=1),
                             axis=0)

## Read in data file and transform
data = np.array(Image.open('test.png'))

freq = im2freq(data)
back = freq2im(freq)
# Make sure the forward and backward transforms work!
assert(np.allclose(data, back))

## Helper functions to rescale a frequency-image to [0, 255] and save
remmax = lambda x: x/x.max()
remmin = lambda x: x - np.amin(x, axis=(0,1), keepdims=True)
touint8 = lambda x: (remmax(remmin(x))*(256-1e-4)).astype(int)

def arr2im(data, fname):
    out = Image.new('RGB', data.shape[1::-1])
    out.putdata(map(tuple, data.reshape(-1, 3)))
    out.save(fname)

arr2im(touint8(freq), 'freq.png')

( 旁白:FFT 爱好者极客笔记。 查看 rfft 的文档了解详细信息,但我使用了 Scipy 的 FFTPACK 模块,因为它的 rfft 将单个像素的实部和虚部交错为两个相邻的实部值,保证任何大小的 2D 图像(偶数与奇数,宽度与高度)的输出将被保留。这与 Numpy 的 numpy.fft.rfft2 形成对比,后者返回大小为 width/2+1 的复杂数据 height/2+1 , 迫使您处理一个额外的行/列,并自己处理复杂到真实的去交错。谁需要这个应用程序的麻烦。)

结果。 给定名为 test.png 的输入:

test input

此代码段产生以下输出(全局最小值/最大值已重新缩放并量化为 0-255):

test output, frequency domain

并升级:

frequency, upscaled

在此频率图像中,DC(0 Hz 频率)分量位于左上角,随着您向右和向下移动,频率会更高。

现在,让我们看看当您以几种方式处理此图像时会发生什么。代替这个测试图像,让我们使用 cat photo .

original cat

我在 Gimp 中制作了一些蒙版图像,然后将其加载到 Python 中并将频率图像乘以查看蒙版对图像的影响。

这是代码:
# Make frequency-image of cat photo
freq = im2freq(np.array(Image.open('cat.jpg')))

# Load three frequency-domain masks (DSP "filters")
bpfMask = np.array(Image.open('cat-mask-bpfcorner.png')).astype(float) / 255
hpfMask = np.array(Image.open('cat-mask-hpfcorner.png')).astype(float) / 255
lpfMask = np.array(Image.open('cat-mask-corner.png')).astype(float) / 255

# Apply each filter and save the output
arr2im(touint8(freq2im(freq * bpfMask)), 'cat-bpf.png')
arr2im(touint8(freq2im(freq * hpfMask)), 'cat-hpf.png')
arr2im(touint8(freq2im(freq * lpfMask)), 'cat-lpf.png')

这是一个 低通滤波器 左边是 mask ,右边是结果——点击查看全分辨率图像:

low-passed cat

在蒙版中,黑色 = 0.0,白色 = 1.0。所以最低频率被保留在这里(白色),而高频率被阻止(黑色)。这通过衰减高频来模糊图像。低通滤波器无处不在,包括在抽取(“下采样”)图像时(尽管它们的形状会比我在 Gimp 中绘制的更仔细 😜)。

这是一个 带通滤波器 ,其中保留了最低频率(看到左上角的那一点白色?)和高频,但中频被阻止。很奇怪!

band-passed cat

这是一个 高通滤波器 ,在上面蒙版中左上角留白的地方被涂黑了:

high-passed filter

这就是边缘检测的工作原理。

后记。 有人,使用这种技术制作一个网络应用程序,让您可以绘制蒙版并将它们实时应用于图像!!!

关于python - 使用 Python 对图像进行 FFT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38476359/

相关文章:

python - 提高在二维 numpy 数组中查找最小元素的速度,该数组有许多条目设置为 np.inf

javascript - Javascript 对悬停在图像上的影响

javascript - JavaScript 中的图像链接

python - python 中的 fft 带通滤波器

Python套接字发送在多次调用recv后不起作用

python - 属性错误: 'slice' object has no attribute 'flags' Error

html - 由具有绝对定位的图像定义的 Div 高度?

c++ - 二维图像上的 FFTW 错误反向变换 [with Qt]

c++ - Windows 上的 FFT 库编译

python - anaconda中安装了多个mkl包