Python版OpenCVとNumPyを用いてフーリエ変換とローパスフィルタを実装し、画像から輪郭を取り出す方法をソースコード付きで解説します。
ローパスフィルタ
ローパスフィルタとは、その名の通り、信号の低周波数成分のみを通過させます。
画像データの場合は、画素値の変化が小さい部分が低周波成分となります。(ノイズは高周波成分)
つまり、画像処理においてはローパスフィルタでノイズ除去などに利用できます。原理の詳細は以下ページで解説しています。
【画像処理】フーリエ変換の原理・実装例
この記事では、画像処理におけるフーリエ変換について解説します。
今回は、Python+OpenCVを用いて画像のノイズ除去を行うためのローパスフィルタを作成します。
処理手順は以下のようになります。
①高速フーリエ変換で画像データを空間領域から空間周波数領域に変換します。
②零周波数成分を中心に移動します。(空間周波数領域の中心ほど低周波数成分)
③ハイパスフィルタで高周波成分のみを取り出します。(空間周波数領域の中心のデータは0に置換)
③高速逆フーリエ変換でデータを空間領域に戻します。
サンプルコード
サンプルプログラムのソースコードです。
実行結果
サンプルプログラムの実行結果です。
■入力画像(左)と出力画像(右)
一部分を拡大すると以下のとおりです。ノイズが低減(平滑化)されていることがわかります。
■入力画像(左)と出力画像(右)
サンプルコードの詳細解説
上記サンプルコードの詳細解説を行います。
インポートと初期設定
# -*- coding: utf-8 -*-
import numpy as np
import cv2
numpy
とcv2
(OpenCV)ライブラリをインポートします。# -*- coding: utf-8 -*-
は、ファイルのエンコーディングを指定しています。
ローパスフィルタ関数
def lowpass_filter(src, param = 0.5):
# 高速フーリエ変換(2次元)
src = np.fft.fft2(src)
# 画像サイズ
height, width = src.shape
# 画像の中心座標
cy, cx = int(height/2), int(width/2)
# フィルタのサイズ(矩形の高さと幅)
rh, rw = int(param*cy), int(param*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)
- 高速フーリエ変換:
np.fft.fft2(src)
で画像を周波数領域に変換します。 - 画像サイズと中心座標の取得: 画像の高さと幅を取得し、その中心座標を計算します。
- フィルタサイズの計算: フィルタのサイズを指定されたパラメータに基づいて計算します。
- フーリエ変換のシフト:
np.fft.fftshift(src)
でフーリエ変換結果をシフトし、低周波成分を中心に移動します。 - フィルタの適用: 中心部分の値を保持し、他の部分をゼロにします。
- 逆シフトと逆フーリエ変換: フィルタ適用後のデータを元に戻し、逆フーリエ変換を行います。
- 実部の取り出し: 結果の実部を取り出し、符号なし整数型に変換して返します。
メイン関数
def main():
# フィルタのサイズ(倍率)、小さいほどフィルタの影響が強くなる
param = 0.3
# 入力画像を読み込み
img = cv2.imread("C:/github/sample/python/opencv/fft/sample.jpg")
# RGB画像をRed, Green, Blueの1チャンネル画像に分割
img_blue, img_green, img_red = cv2.split(img)
# ローパスフィルタ処理
himg_blue = lowpass_filter(img_blue, param)
himg_green = lowpass_filter(img_green, param)
himg_red = lowpass_filter(img_red, param)
# RGB画像に戻す
himg = cv2.merge((himg_blue, himg_green, himg_red))
# 処理結果を出力
cv2.imwrite("C:/github/sample/python/opencv/fft/lowpass_filter.jpg", himg)
if __name__ == "__main__":
main()
- フィルタのサイズ設定:
param = 0.3
でフィルタの影響範囲を設定します。 - 画像の読み込み:
cv2.imread
で画像を読み込みます。 - RGBチャンネルの分割:
cv2.split
で画像をRGBの各チャンネルに分割します。 - ローパスフィルタの適用: 各チャンネルに対してローパスフィルタを適用します。
- RGB画像の再構成:
cv2.merge
でフィルタ処理後の各チャンネルを再度結合します。 - 結果の保存:
cv2.imwrite
で処理結果を保存します。
おすすめ記事
【Python版OpenCV超入門】使い方とサンプルコードを解説
Python版OpenCVで画像処理プログラミングを行う方法を入門者向けにソースコード付きで解説するページです。
【画像処理入門】アルゴリズム&プログラミング
画像処理における基本的なアルゴリズムとその実装例(プログラム)についてまとめました。
コメント