[英]FFT on image with Python
我在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)
而且,我只得到黑色圖像。
[EDIT2]
假設我不想打開它並保存為灰度圖像。 所以我這樣做。
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')
在此之后,我得到了這張照片 ,沒關系。 所以現在,我想在我將它保存到新圖像之前對我的圖像進行fft,所以我就是這樣做的
scale = 1/(width*height)
greyscale = np.fft.fft2(greyscale)
greyscale = abs(greyscale * scale)
加載后。 保存到文件后,我有 。 所以讓我們現在嘗試使用gimp打開test.png並使用FFT過濾器插件。 我收到這張圖片,這是正確的
我該怎么辦呢?
好問題。 我從來沒有聽說過它,但Gimp Fourier插件似乎很整潔:
一個簡單的插件,可以對您的圖像進行傅立葉變換。 這個插件的主要優點是能夠在GIMP中使用轉換后的圖像。 您可以在傅立葉空間中繪制或應用濾波器,並使用逆FFT獲得修改后的圖像。
這個想法 - 對頻域數據進行Gimp風格的操作並轉換回圖像 - 非常酷! 盡管多年來使用FFT,但我從未考慮過這樣做。 不要亂用Gimp插件和C可執行文件和丑陋,讓我們用Python做到這一點!
警告。 我嘗試了很多方法來做到這一點,試圖從原始輸入圖像中獲得接近輸出Gimp Fourier圖像(帶有莫爾圖案的灰色)的東西,但我根本不能。 Gimp圖像在圖像中間看起來有些對稱,但它不是垂直或水平翻轉,也不是轉置對稱的。 我希望插件能夠使用真正的2D FFT將H×W圖像轉換為頻域中的實數值數據的H×W陣列,在這種情況下,不存在對稱性(它只是 - 對於像圖像這樣的實值輸入,它是共軛對稱的復數FFT。 所以我放棄了嘗試逆向工程Gimp插件正在做什么,看看我是如何從頭做的。
編碼。 非常簡單:讀取圖像, scipy.fftpack.rfft
兩個維度中應用scipy.fftpack.rfft
以獲得“頻率圖像”,重新縮放到0-255,然后保存。
請注意這與其他答案有何不同! 沒有灰度 - 2D實際到FFT在所有三個通道上獨立發生。 不需要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')
( rfft
:FFT-lover geek note。有關詳細信息,請查看rfft
的文檔,但我使用了Scipy的FFTPACK模塊,因為它的rfft
將單個像素的實部和虛部交錯為兩個相鄰的實數值,保證了任意大小的輸出將保留2D圖像(偶數與奇數,寬度與高度)。這與Numpy的numpy.fft.rfft2
形成對比,因為它返回大小為width/2+1
height/2+1
復雜數據,迫使您處理一個額外的行/列並處理自己復雜到真實的解交織。誰需要為這個應用程序麻煩。)
結果。 給定名為test.png
輸入:
此代碼段產生以下輸出(全局最小值/最大值已重新調整並量化為0-255):
並升級:
在此頻率圖像中,DC(0 Hz頻率)分量位於左上角,頻率隨着向右和向下移動而變高。
現在,讓我們看看當您以幾種方式操作此圖像時會發生什么。 而不是這個測試圖像,讓我們使用貓照片 。
我在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')
這是左側的低通濾鏡掩碼,右側是結果單擊以查看完整分辨率圖像:
在掩模中,黑色= 0.0,白色= 1.0。 所以最低頻率保持在這里(白色),而高頻率被阻擋(黑色)。 這通過衰減高頻來模糊圖像。 低通濾波器遍布整個地方,包括對圖像進行抽取(“下采樣”)時(雖然它們的形狀比我在Gimp中繪制的要小得多)。
這是一個帶通濾波器 ,其中保留了最低頻率(見左上角的白色位?)和高頻,但中頻頻率被阻擋。 相當奇怪!
這是一個高通濾波器 ,上面掩模中左上角的左上角被塗黑:
這就是邊緣檢測的工作原理。
后記。 有人,使用這種技術制作一個webapp,讓你繪制蒙版並將它們實時應用到圖像中!
這里有幾個問題。
1)手動轉換為灰度並不好。 使用Image.open("test.png").convert('L')
2)很可能存在類型問題。 您不應該將np.ndarray
從fft2
傳遞到PIL圖像,而不確定它們的類型是否兼容。 abs(np.fft.fft2(something))
將返回一個類型為np.float32
的數組或類似的數組,而PIL圖像將接收類似np.uint8
類型的數組。
3)評論中建議的縮放看起來不對。 實際上你需要你的值適合0..255范圍。
這是我的代碼,解決了這三點:
import numpy as np
from PIL import Image
def fft(channel):
fft = np.fft.fft2(channel)
fft *= 255.0 / fft.max() # proper scaling into 0..255 range
return np.absolute(fft)
input_image = Image.open("test.png")
channels = input_image.split() # splits an image into R, G, B channels
result_array = np.zeros_like(input_image) # make sure data types,
# sizes and numbers of channels of input and output numpy arrays are the save
if len(channels) > 1: # grayscale images have only one channel
for i, channel in enumerate(channels):
result_array[..., i] = fft(channel)
else:
result_array[...] = fft(channels[0])
result_image = Image.fromarray(result_array)
result_image.save('out.png')
我必須承認,我沒有設法獲得與GIMP FFT插件相同的結果。 據我所知,它做了一些后期處理。 我的結果都是非常低對比度的混亂,GIMP似乎通過調整對比度和縮小非信息渠道來克服這個問題(在你的情況下,除Red之外的所有chanel都是空的)。 參考圖片:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.