werry-chanの日記.料理とエンジニアリング

料理!コーディング!研究!日常!飯!うんち!睡眠!人間の全て!

pythonで画像のフーリエ変換2

よくわからないですが,以前にあげた画像のフーリエ変換のページがアクセス多いので,その続きを書きましょう.

以前のページ
werry-chan.hatenablog.com

以前のページでは,具体的な画像に対して二次元フーリエ変換(2DFFT)を行っていました.

さらに,2DFFTの後にハイパスorローパスフィルタをかけることで成分分析を行いました.

応用編↓画像のフーリエ変換でSTM像を鮮明化
画像のフーリエ変換3: 走査トンネル顕微鏡(STM)でグラファイト(HOPG)を撮像し,FFTで鮮明化する. - werry-chanの日記.料理とエンジニアリング



さて,今回は2DFFTについて更なる理解を深めるために,単純なsin波画像を2DFFTしてみましょう.

今回使う画像はこちらです.

f:id:werry-chan:20200815122633j:plain
波数1のsin波画像

横向きにsin波が輝度で表されていますね.

画像の縦方向に関しては変化がなく,横方向に波が生じています.


これを2DFFTし,象限を入れ替え,パワースペクトル画像にするとこのようになります.

f:id:werry-chan:20200815122904j:plain
周波数1のsin波fft画像

よーく見てもらうと真ん中あたりに線があります.

線は横方向に伸びていますね.

このように横方向の変化を持つ波画像を2DFFTすると,波の方向に応じた成分が表示されます.


詳しくは後に語るとして,その他の方向に関しても試してみましょう.

次は縦方向の波画像とその2DFFTパワースペクトル画像がこうなります.↓.

f:id:werry-chan:20200815123514j:plainf:id:werry-chan:20200815123446j:plain
周波数1のsin波画像_縦とその2DFFTパワースペクトル画像

よーく見ると縦方向の線が見えます.


次に斜め方向の波画像(傾き30°)です.

画像の生成過程でアフィン変換という回転方法を使ったため,少し画像が劣化しましたが,まぁ良いでしょう.

斜め方向の波画像(傾き30°)と2DFFTパワースペクトル画像がこうなります.↓

f:id:werry-chan:20200815124016j:plainf:id:werry-chan:20200815124142j:plain
周波数1のsin波画像_傾き30°とその2DFFTパワースペクトル画像

アフィン変換による劣化の影響は,2DFFTで顕著に現れましたが,斜め30°方向に線が見えるかと思います.


このように,2DFFTによって画像中に含まれる単調な波の成分の方向が分かります.


さて,次に波の周波数を変えてみると,どのように2DFFTの結果が変わるか確認しましょう.

周波数1, 10, 100の横波画像を見てみます.

f:id:werry-chan:20200815125324j:plainf:id:werry-chan:20200815125915j:plainf:id:werry-chan:20200815125339j:plain
周波数1,10,100のsin波画像

これらの2DFFTパワースペクト画像が以下のようになります.

f:id:werry-chan:20200815130045j:plainf:id:werry-chan:20200815130055j:plainf:id:werry-chan:20200815130102j:plain
波数1,50,100のsin波画像の2DFFTパワースペクトル画像

かなり細い線なので,違いが分かりにくいですね.


30°傾いた画像で見てみると,画像の劣化のおかげか少し見やすくなっていますので,そちらも見てみましょう.

f:id:werry-chan:20200815131022j:plainf:id:werry-chan:20200815131030j:plainf:id:werry-chan:20200815131044j:plainf:id:werry-chan:20200815131059j:plain
周波数1,10,50,100のsin波画像_傾き30°

f:id:werry-chan:20200815131226j:plainf:id:werry-chan:20200815131232j:plainf:id:werry-chan:20200815134151j:plainf:id:werry-chan:20200815131304j:plain
周波数1,10,50,100のsin波画像_傾き30°の2DFFTパワースペクトル画像


原点から傾き30°の線上にある輝度に注目しましょう.

まず基本として,象限入れ替えを行ったパワースペクトル画像は,原点周辺が低周波成分,辺縁部にかけて次第に高周波成分を示しています.
画像のフーリエ変換 - werry-chanの日記.料理とエンジニアリング
こちらでも図で説明がありますので参考に↑

ということは周波数1は,原点周辺が明るく,周波数が高くなるにつれて辺縁部が明るくなると予想できます.

しかながら,出力されたパワースペクトル画像からはこのような傾向は顕著ではありません.

その理由として,高調波(主成分の周波数の整数倍の波)の影響が存在します.

具体的に説明しましょう.

周波数50の画像をみてみましょう.

f:id:werry-chan:20200815134151j:plainf:id:werry-chan:20200815134652j:plain
周波数50の波_傾き30°の2DFFTパワースペクトル画像と強調画像

最も中央に近い白マークが周波数50の斜め波成分になります.

次にその隣に存在する白マークは周波数100,さらにその隣が周波数150と,次第に輝度が減少しながら高調波が表れます.

周波数100の2DFFTパワースペクトル画像の場合は,主成分が十分に大きいため,高調波が見えません.

周波数10の2DFFTパワースペクトル画像の場合は,拡大して確認すると,周波数10とその高調波の成分(20,30,...)が確認できます.

周波数1の2DFFTパワースペクトル画像の場合は,主成分と高調波の間隔が狭すぎるため,見た目上は直線になっています.


同様のことが横方向・縦方向の波でも拡大することで確認できます.

しかしながら縦方向・横方向の波は,ノイズのない画像のため,2 px幅の線で表されています.

かなり拡大しないと確認は難しいでしょう.



以上のようにして,2DFFTパワースペクトル画像の各点の表す意味が理解できたかと思います.

・中央からの方向は,波の進行方向を表す.
・輝度は,波の強度(振幅)を表している.
FFTは,高調波成分も検出する.


簡単に試せるソースコードを置いておきますね.

import cv2
import numpy as np


width,length = 800,800 #画像のサイズ
img = np.zeros((width,length),dtype = np.uint8) #画像の生成
wave_number = 100 #周波数
sin_row = np.sin(np.linspace(-wave_number*np.pi, wave_number*np.pi, 800)) #sin波の生成
sin_row = np.array(np.abs(sin_row*200), dtype = np.uint8) #輝度値に変換(max200とした)

#横波画像の生成
for i in range(len(img)):
    img[i] = sin_row

#img = np.transpose(img) #縦波に変換

#アフィン変換
degree = 30 #回転角度(°)
scale = 2 #拡大縮尺
trans = cv2.getRotationMatrix2D((int(width/2),int(length/2)), degree, scale)
img = cv2.warpAffine(img, trans, (width,length))
cv2.imwrite("sin.jpg",img)


#画像の二次元フーリエ変換
fimg=np.fft.fft2(img)
fimg = np.fft.fftshift(fimg)

#パワースペクトル化する
fimg= np.array(10*np.log(np.abs(fimg)+1),dtype = np.uint8)
print(np.where(fimg == np.max(fimg)))

cv2.imwrite("fft.jpg",fimg)