web-dev-qa-db-ja.com

Pythonを使用した画像のFFT

PythonでのFFTの実装に問題があります。まったく奇妙な結果が出ました。 Okなので、画像を開き、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)。 1つのピクセル(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]

では、1つの画像を撮りましょう。 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

どうすればそれを処理できますか?

8
Tatarinho

ここにはいくつかの問題があります。

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の範囲に収める必要があります。

これらの3つのポイントに対処する私のコードは次のとおりです。

_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はコントラストを調整し、情報チャネル以外のチャネルを縮小することでこれを克服しているようです(この場合、赤を除くすべてのチャネルは空です)。画像を参照してください:

enter image description here

2
Vovanrock2002