【Python/OpenCV】フーリエ変換+ローパスフィルタでノイズ除去

この記事では、Python版OpenCVとNumPyを用いてフーリエ変換とローパスフィルタを実装し、画像から輪郭を取り出す方法をソースコード付きで解説します。

ローパスフィルタ

ローパスフィルタとは、その名の通り、信号の低周波数成分のみを通過させます。
画像データの場合は、画素値の変化が小さい部分が低周波成分となります。(ノイズは高周波成分)
つまり、画像処理においてはローパスフィルタでノイズ除去などに利用できます。

関連記事
原理の詳細 【画像処理】フーリエ変換(DFT、FFT)
画像のフーリエ変換 【Python/OpenCV】高速フーリエ変換で周波数領域に変換

今回は、Python+OpenCVを用いて画像をローパスフィルタに通しました。

処理手順
高速フーリエ変換で画像データを空間領域から空間周波数領域に変換します。
零周波数成分を中心に移動します。(空間周波数領域の中心ほど低周波数成分)
ハイパスフィルタで高周波成分のみを取り出します。(空間周波数領域の中心のデータは0に置換)
高速逆フーリエ変換で空間領域に戻します。

ソースコード(Python3+OpenCV3)

サンプルプログラムのソースコードです。

# -*- coding: utf-8 -*-
import numpy as np
import cv2

def lowpass_filter(src, a = 0.5):
    # 高速フーリエ変換(2次元)
    src = np.fft.fft2(src)

    # 画像サイズ
    h, w = src.shape

    # 画像の中心座標
    cy, cx =  int(h/2), int(w/2)

    # フィルタのサイズ(矩形の高さと幅)
    rh, rw = int(a*cy), int(a*cx)

    # 第1象限と第3象限、第1象限と第4象限を入れ替え
    fsrc =  np.fft.fftshift(src)

    # 入力画像と同じサイズで値0の配列を生成
    fdst = np.zeros(src.shape, dtype=complex)

    # 中心部分の値だけ代入(中心部分以外は0のまま)
    fdst[cy-rh:cy+rh, cx-rw:cx+rw] = fsrc[cy-rh:cy+rh, cx-rw:cx+rw]

    # 第1象限と第3象限、第1象限と第4象限を入れ替え(元に戻す)
    fdst =  np.fft.fftshift(fdst)

    # 高速逆フーリエ変換
    dst = np.fft.ifft2(fdst)

    # 実部の値のみを取り出し、符号なし整数型に変換して返す
    return  np.uint8(dst.real)


def main():
    # 入力画像を読み込み
    img = cv2.imread("input.png")

    # グレースケール変換
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

    # ローパスフィルタ処理
    himg = lowpass_filter(gray, 0.3)

    # 処理結果を出力
    cv2.imwrite("output.png", himg)

if __name__ == "__main__":
    main()

実行結果

サンプルプログラムの実行結果です。

■入力画像(左)と出力画像(右)

おすすめ記事

PythonでOpenCV入門 サンプル集
【Python】画像処理プログラミング入門
【画像処理入門】アルゴリズム&プログラミング

コメント