tata色々な備忘録

データ解析、画像解析、化学分析などなど

python+Opencvによる画像処理7(二次元フーリエ変換)

画像のフーリエ変換。 (Opencvのデモを少し修正して翻訳)

二次元フーリエ変換

全行方向にフーリエ変換した結果に対し、
さらに列方向でフーリエ変換をする。

4隅に低波数が出て見づらいので、
四隅が中央に来るよう加工する。

出た模様は一般にパワースペクトルと呼ばれる。

詳細は離散フーリエ変換wikiを参照

import cv2
import numpy as np

"""
四隅に低周波数があるため、
切り抜いた四隅を合成し、中央を低周波数にする
"""
def shift_dft(src, dst=None):
    if dst is None:
        dst = np.empty(src.shape, src.dtype)
    elif src.shape != dst.shape:
        raise ValueError("src and dst must have equal sizes")
    elif src.dtype != dst.dtype:
        raise TypeError("src and dst must have equal types")

    if src is dst:
        ret = np.empty(src.shape, src.dtype)
    else:
        ret = dst

    h, w = src.shape[:2]

    cx1 = cx2 = w/2
    cy1 = cy2 = h/2

    # 
    if w % 2 != 0:
        cx2 += 1
    if h % 2 != 0:
        cy2 += 1

    # 左上と右下の入れ替え
    ret[h-cy1:, w-cx1:] = src[0:cy1 , 0:cx1 ]   # 左上を右下に
    ret[0:cy2 , 0:cx2 ] = src[h-cy2:, w-cx2:]   # 右下を右上に
    # 左下と右上の入れ替え
    ret[0:cy2 , w-cx2:] = src[h-cy2:, 0:cx2 ]   # 左下を右上に
    ret[h-cy1:, 0:cx1 ] = src[0:cy1 , w-cx1:]   # 右上を左下に

    if src is dst:
        dst[:,:] = ret

    return dst

if __name__ == "__main__":
    im = cv2.imread('lena.jpg')

    # グレースケール変換
    im2 = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    h, w = im2.shape[:2]

    realInput = im2.astype(np.float64)

    # DFT変換のサイズを計算
    dft_M = cv2.getOptimalDFTSize(w)
    dft_N = cv2.getOptimalDFTSize(h)

    # Aをdft_Aにコピーし、 pad dft_Aはゼロ
    dft_A = np.zeros((dft_N, dft_M, 2), dtype=np.float64)
    dft_A[:h, :w, 0] = realInput

    # no need to pad bottom part of dft_A with zeros because of
    # use of nonzeroRows parameter in cv2.dft()
    cv2.dft(dft_A, dst=dft_A, nonzeroRows=h)

    cv2.imshow("win", im)

    # 実数と虚数分解
    image_Re, image_Im = cv2.split(dft_A)

    # 二乗和して根を取り正にへ
    magnitude = cv2.sqrt(image_Re**2.0 + image_Im**2.0)

    # 対数を取る
    log_spectrum = cv2.log(1.0 + magnitude)

    # 四隅が低波数⇒中央が低波数になるよう組み換え
    shift_dft(log_spectrum, log_spectrum)

    # 正規化して可視化
    cv2.normalize(log_spectrum, log_spectrum, 0.0, 1.0, cv2.NORM_MINMAX)
    
    log_spectrum2=np.float32(log_spectrum)

    cv2.imshow("magnitude", log_spectrum2)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

f:id:tatabox2000:20130720202631g:plain

カラーバージョンも作る予定。