周波数フィルタリング(ローパス、ハイパス)

Python

はじめに

今回研究で画像処理の勉強をする機会があったので、メモがてらここに記録しておこうと思いました。よかったら他の記事も見てください。https://florisryo.com/

周波数フィルタリングとは画像を二次元フーリエ変換を用いて、座標空間から周波数空間へ移動させ、その周波数空間に対してフィルタリング処理を行うことです。今回扱うのは周波数の低い成分を取り出すローパスフィルタと周波数の高い成分を取り出すハイパスフィルタをPythonで作成していこうと思います。
この画像処理の原理は、画像の圧縮やノイズ削減、コントラスト強調などにも用いられています。

画像のフーリエ変換

import numpy as np
import matplotlib.pyplot as plt
import cv2

img = cv2.imread("test2.jpg",0)
fft_img = np.fft.fft2(img)
shift_fft_img = np.fft.fftshift(fft_img)
amp_spe = (20*np.log(np.abs(shift_fft_img)))

画像をOpenCVのライブラリを用いて取り込みます。>>cv2

その後画像をnp.fft.fft2を用いて二次元フーリエ変換を行います。その後fft.fftshiftを用いて象限を移動させます。

これは二次元フーリエ変換では、変換後の周波数軸に対して2πの周期性を仮定している。そのため2πを超えたときに範囲内にとどまるように0から再び循環した周波数の値となるため、画像(a)のようになります。しかし、この後の操作において(a)のまま処理するのは扱いづらいことから多くの画像処理において右の画像(b)のように象限の移動を行います。また、この画像を見てわかる通りローパスフィルタの場合は中心成分だけを取り出せばローパスフィルタとして機能することがわかると思います。逆にハイパスフィルタは外側の成分だけを切り出せば機能します。この後の実装ではこの思想の下、フィルタを作成していきます。

最後に実際にフーリエ変換が行えているかを確認するために、パワースペクトルの計算を行っています。これは確認のためであって、実際の操作では必要ありません。

ローパスフィルタ

def lowpassfilter(shift_fft_img,pas):
    h,w = shift_fft_img.shape
    cy = int(h/2)
    cx = int(w/2)
    rh = int(pas*cy)
    rw = int(pas*cx)
    fdst = np.zeros(shift_fft_img.shape, dtype=complex)
    fdst[cy-rh:cy+rh, cx-rw:cx+rw] = shift_fft_img[cy-rh:cy+rh, cx-rw:cx+rw]
    fds = np.fft.fftshift(fdst)
    ds = np.fft.ifft2(fds)
    ds = np.uint8(ds)
    return fdst,ds 

まず、h,wに高さと横幅の情報を保存し、cx,cyに中心座標の情報を保存します。
その後rh,rwにマスク処理のための係数をかけて、マスクの用意を行います。
fdstで、0の配列を作成し、次の行で0配列の中心部分に代入することで中心は成分を持ち、外側は0の配列を作成するというローパスの作用を実現しています。

その後fft.shiftで配列をもとに戻し、逆フーリエ変換を行っています。

このとき、画像左から「元画像→画像のフーリエ変換像→ローパスフィルタ→処理後画像」となっています。

ハイパスフィルタ

def highpassfilter(shift_fft_img,pas):
    h,w = shift_fft_img.shape
    cy = int(h/2)
    cx = int(w/2)
    rh = int(pas*cy)
    rw = int(pas*cx)
    fdst = np.zeros(shift_fft_img.shape, dtype=complex)
    shift_fft_img[cy-rh:cy+rh, cx-rw:cx+rw] = fdst[cy-rh:cy+rh, cx-rw:cx+rw]
    fds = np.fft.fftshift(shift_fft_img)
   ds = np.fft.ifft2(fds)
   ds = np.uint8(ds)
   return shift_fft_img,ds

次にハイパスフィルタとなっています。ハイパスフィルタでは、先ほどのローパスフィルタの説明とほとんど同じですが、先ほどとは異なり、中心部分に0成分を代入することでハイパスフィルタを実現しています。

全体のコード

import numpy as np
import matplotlib.pyplot as plt
import cv2

img = cv2.imread("test2.jpg",0)
fft_img = np.fft.fft2(img)
shift_fft_img = np.fft.fftshift(fft_img)
amp_spe = (20*np.log(np.abs(shift_fft_img)))

def lowpassfilter(shift_fft_img,pas):
    h,w = shift_fft_img.shape
    cy = int(h/2)
    cx = int(w/2)
    rh = int(pas*cy)
    rw = int(pas*cx)
    fdst = np.zeros(shift_fft_img.shape, dtype=complex)
    fdst[cy-rh:cy+rh, cx-rw:cx+rw] = shift_fft_img[cy-rh:cy+rh, cx-rw:cx+rw]
    fds =  np.fft.fftshift(fdst)
    ds = np.fft.ifft2(fds)
    ds = np.uint8(ds)
    return fdst,ds

def highpassfilter(shift_fft_img,pas):
    h,w = shift_fft_img.shape
    cy = int(h/2)
    cx = int(w/2)
    rh = int(pas*cy)
    rw = int(pas*cx)
    fdst = np.zeros(shift_fft_img.shape, dtype=complex)
    shift_fft_img[cy-rh:cy+rh, cx-rw:cx+rw] = fdst[cy-rh:cy+rh, cx-rw:cx+rw]
    fds =  np.fft.fftshift(shift_fft_img)
    ds = np.fft.ifft2(fds)
    ds = np.uint8(ds)
    return shift_fft_img,ds

def plot(img,am,fdst,ds):
    fig = plt.figure()
    ax1 = fig.add_subplot(1,4,1)
    ax2 = fig.add_subplot(1,4,2)
    ax3 = fig.add_subplot(1,4,3)
    ax4 = fig.add_subplot(1,4,4)
    ax1.imshow(img, cmap = 'gray')
    ax2.imshow(am,cmap='gray')
    ax3.imshow((20*np.log(np.abs(fdst))),cmap='gray')
    ax4.imshow(ds,cmap='gray')
    plt.show()

#fdst,ds = lowpassfilter(shift_fft_img,0.5)
fdst,ds = highpassfilter(shift_fft_img,0.5)

plot(img,amp_spe,fdst,ds)

参考文献

周波数フィルタリング (Spectral Filtering)【画像フィルタリング その2】 | CVMLエキスパートガイド
画像の周波数フィルタリング (Spectral Filtering) の基本的な内容をこの記事では紹介する.画像の周波数フィルタリングでの使用手順(二次元フーリエ変換による前処理と,逆二次元フーリエ変換による後処理)と応用例(周波数帯域マスク画像を用いたバンドパスフィルタリング)について紹介する.

コメント

タイトルとURLをコピーしました