フーリエ変換を使った画像解析

工学部に在籍している学生の方は、大学の授業でフーリエ解析の授業を履修している方が多いと思います。今回はそのフーリエ解析を使って画像解析を行っていきます!プログラムのみ見たい方は下のほうに乗せていますので是非参考にしてください。

フーリエ解析とは?

フーリエ解析とは簡単に言うと

ある時間領域にある関数を周波数領域の関数に変換する手法

です。例えば、高校の物理の授業などで「波の重ね合わせ」といった言葉を耳にしたことがあると思います。これは

$$\downarrow \quad それぞれの波を足し合わせると?$$

上の図のように、いくつかの波を足し合わせたものは上のような波形になります。

このことから、ある周波数の波を足し合わせていくとどのような関数でも表せそうですよね。実際、すべての関数(例:1次関数やステップ関数など・・・)は波の重ね合わせで表現することができます。

では逆に、すべての関数はそれぞれ別の周波数の波に分割もできそうですよね。

このように時間領域の関数を周波数領域の関数に変換する手法をフーリエ解析といいます。

フーリエ解析とはつまり

このように、ある時間関数は周波数領域の関数に変換でき、その変換手法をフーリエ解析といいます。このフーリエ解析は情報通信分野などで重要な役割を果たしています。今回はこのフーリエ解析の知識を使って画像処理を行っていきます!

フーリエ解析を使ってノイズ除去

上の画像を見ると、周期的なノイズが入っていていることがわかると思います。今回はこの画像の解析を行い、ノイズを除去していきましょう。

今回使うライブラリの紹介

今回使っていくライブラリは

  • 行列演算をするためのnumpy
  • グラフ表示するためのmatplotlib
  • 科学技術演算(今回はフーリエ変換)のためのscipy
  • 画像の読み込みをするためのcv2
  • (任意)ディレクトリ移動のためのos

となります。プログラムは下のようにして呼び出し名を簡略化してあげると楽にコードが書けます。

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack as sfft
import cv2
import os

画像の読み込み

まず、画像を読み込みましょう。

前回と同様に、cv2.imread()を使って画像情報を読み込みます。ここで読み込んだデータを.shapeを使ってサイズを確認します。

G=cv2.imread("moonlanding.png",0) #1画像を読み込む
print(G.shape)      #Gのサイズをいったん確認

データ解析や画像処理などの行列処理を行うプログラムを書く際は行列のサイズを間違えることでバグが起こりやすいので初心者の方は逐次確認していきましょう。

画像のフーリエ変換

次に、画像データGにフーリエ変換を行っていきます。まず初めに、フーリエ変換を行うときの行列のサイズを決めましょう。

行列の処理を行う際は同じサイズ同士のもののほうが計算が行いやすいため、fftsizeは画像データの最大サイズにしておきます。

つぎに、実際にフーリエ変換を行っていきます。このとき、画像データは2次元なので2次元のフーリエ変換を行っていきます。この時注意してほしいのが、画像のフーリエ変換をそのまま行うと、高周波成分が内側、低周波成分が外側に表示されグラフ化したときにとても見にくくなります。なのでfftshiftを使ってデータを見やすいようにしましょう。

画像表示する際は、より変化がわかりやすいように対数で表示させてみましょう。

赤の丸の地点が中心で、矢印方向に進むほど高周波成分となる。

この図は軸の値の関係で見にくいですが、中心となる軸は横軸の値が315となるところです。

この図では中心軸である315付近から離れれば離れるほど高周波のものとなることを示しています。

画像の周波数成分は

  • 低周波・・・画像の大まかな情報
  • 高周波・・・画像のエッジ(輪郭)情報

となっています。ノイズというのは高周波のものなので、高周波成分をなくすようなフィルタを作っていきます。

この図から、だいたい0~250、350~640までの周波数成分を0にしてあげればノイズが消えそうだなという考察ができると思います。

フィルタの作成

では、実際にフィルタを作っていきましょう!

A=np.ones((fftsize,fftsize))  #ノイズ成分を除去するためのフィルタを作成
A[350:,:]=0#スペクトルより(350~, )成分を除去
A[:250,:]=0  #スペクトルより(~250, )成分を除去
A[:,:250]=0  #スペクトルより( ,~250)成分を除去
A[:,350:]=0  #スペクトルより( ,350~)成分を除去

フィルタAfftsizeと同じサイズで、各値が1の行列を代入しましょう。

次に、図から高周波成分であると思われる範囲の値を0にしていきます。

この作成したフィルタAzを掛け合わせてあげると、ノイズ成分を除去した画像データが手に入ります。

データの再画像化

では、最後にノイズ除去したものを再度画像化してみましょう。

画像化する際は、ifft2()を使って逆フーリエ変換を行うことで画像化をしていきます。

この時注意しないといけないのが、z*Afftshiftをつかったデータなので、元の画像データに変換するにはもう一度fftshiftを使ってあげる必要があります。

逆フーリエ変換を行ってあげたら、元の画像と同じ画像サイズとなるようにいらない部分をスライスして表示させましょう。

最終的に画像化したものが下の画像になります。

ノイズ除去後
ノイズ除去前

この画像から、きちんとノイズ除去されていることがわかります。

このように、ノイズ除去を行う際は、ノイズが高周波という性質からフーリエ解析を行うことで簡単に除去できます。

是非ほかの画像を使って再度ノイズ除去に挑戦してみて下さい!

今回用いたプログラムコードは下に乗せておきます。

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack as sfft
import cv2
import os

G=cv2.imread("moonlanding.png",0) #1画像を読み込む
print(G.shape)      #Gのサイズをいったん確認

h,w=G.shape  #h、wにGのサイズを代入
fftsize=max(h,w)  #フーリエ変換を行う際の行列のサイズを決定
print(fftsize)   #サイズを確認

z=sfft.fftshift(sfft.fft2(G,(fftsize,fftsize)))#Gを高速フーリエ変換
plt.plot(np.log(np.abs(z))    #zの絶対値にlogをとってっ表示
plt.show()
print(z.shape)  #一応zのサイズを確認

A=np.ones((fftsize,fftsize))  #ノイズ成分を除去するためのフィルタを作成
A[350:,:]=0#スペクトルより(350~, )成分を除去
A[:250,:]=0  #スペクトルより(~250, )成分を除去
A[:,:250]=0  #スペクトルより( ,~250)成分を除去
A[:,350:]=0  #スペクトルより( ,350~)成分を除去

G2=np.uint8(np.abs(sfft.ifft2(sfft.fftshift(z*A))))
plt.imshow(G2[:h,:w],cmap='gray')
plt.show()

まとめ

今回は、フーリエ解析を使って画像のノイズ除去を行ってみました。このように大学で学ぶ内容は様々なものに応用されていることがわかると思います。また、pythonでは学術的な内容に使えるライブラリが豊富にそろっているのでぜひ試してみて下さい!

東京農工大電気電子工学科所属の大学生 趣味:ショッピング、スノボ、映画鑑賞 大学の情報と学んだ知識をアウトプットしていきます!
投稿を作成しました 13

フーリエ変換を使った画像解析” に1件のコメント

  1. 今回の記事もめちゃめちゃわかりやすかったです!
    農工大についての情報ももっとたくさん載せてほしいです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連する投稿

検索語を上に入力し、 Enter キーを押して検索します。キャンセルするには ESC を押してください。

トップに戻る
%d人のブロガーが「いいね」をつけました。