フーリエ変換・逆フーリエ変換後に値が振り切って画像に戻せません

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,539
退会済みユーザー

退会済みユーザー

前提・実現したいこと

Python+OpenCVで、カラー画像にフーリエ変換を行ってマスク処理をしたいと考えています。昨日からこちらの説明(鳥取大)を参考に、とりあえず動くところまでこぎつけました。

動かし方:   D:\>python fftmask.py 画像のファイル名

発生している問題・エラーメッセージ

FFT-->IFFTで画像が元に戻ることを確認するために、FFTとIFFT処理だけを実装してテストしましたが、以下のように画像が元に戻らない(ほぼ二値化し、色合いも異常になる)状態です。

生画像 加工後画像
生画像 処理後

(6/12 A.M 追記: pltを使って中身を確認しました)
・二値化?
IFFT後のプロット画像を見ると値に"*e^+7"がくっついており、このせいで画像がほぼ二値化してしまっているようです
・色合いが異常
上記の二値化の影響で緑だけが突出してしまっているようです

(6/12 P.M 追記: stackoverflowで似た様な事例を発見しました)
・IDFT(IFFT)の結果が255を振り切っている件
stackoverflow

(6/13 A.M 追記1: stackoverflowの事例を参考にe^6~7を外すところまで来ました)
・255を振り切っている部分を0~255までに収めることができました
・ただし、string,plt上では元の値に戻せていますが、openCV上では真っ暗になります

(6/13 A.M 追記2)
・intが64ではだめですよね

該当のソースコード

# -*- coding: utf-8 -*-
print ("* Now initializing... import")
import sys
import os
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Global variables
current_working_directory = os.getcwd()
args = sys.argv

# --------------------------------------
def DFT_IDFT_core(img_ch):
    # ------------------------
    # DFT method with OpenCV
    # ------------------------
    # Get image size
    row,col = img_ch.shape
    row_center, col_center = int(row/2), int(col/2)

    # Calclate optimized size for FFT
    fft_row = cv2.getOptimalDFTSize(row)
    fft_col = cv2.getOptimalDFTSize(col)

    # Generate optimized image
    img_merged = np.zeros((fft_row, fft_col), np.uint8)
    img_merged[0:row,0:col] = img_ch

    # Calc DFT(IMPORTANT: CALL "cv2.DFT_SCALE" TO REMOVE "*e^x")
    dft = cv2.dft(np.float32(img_merged),flags=cv2.DFT_COMPLEX_OUTPUT|cv2.DFT_SCALE )

    # Shift DFT
    dft_shift = np.fft.fftshift(dft)

    # MASK process
    # mask = np.zeros((fft_row,fft_col,2),np.uint8)
    # mask[row_center-200:row_center+200, col_center-200:col_center+200] = 1
    # masked = dft_shift*mask
    masked = dft_shift

    # Calc IDFT
    f_ishift = np.fft.ifftshift(masked)
    img_back = cv2.idft(f_ishift)

    # Calc magnitude
    img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

    # Crop raw area
    img_back = img_back[0:row, 0:col]

    # Float to ingeter
    img_back = np.round(img_back).astype(np.int64)

    # Debug with string
    print("INPUT:  %s\n"%(img_ch))
    print("OUTPUT: %s\n\n"%(img_back))

    # Debug
    plt.subplot(121),plt.imshow(img_ch, cmap = 'gray')
    plt.title('Input Image'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
    plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
    plt.show()

    # Debug with openCV
    cv2.imshow("img_ch",img_ch)
    cv2.imshow("img_back",img_back)
    cv2.waitKey(0)

    return img_back

# --------------------------------------
def MASK_PROCESS_BY_FFT(img_col):

    # Split image by color channels
    if len(img_col.shape)== 3:
        channels = 3
        img_b, img_g, img_r = cv2.split(img_col)
        # cv2.imshow("img_b",img_b)
        # cv2.imshow("img_g",img_g)
        # cv2.imshow("img_r",img_r)
    else:
        # Grayscale
        channels = 1
        img_gs = img_col
        # cv2.imshow("img_grayscale",img_grayscale)

    # FFT process
    if channels == 3:
        # Combine BGR
        img_b_fft = DFT_IDFT_core(img_b)
        img_g_fft = DFT_IDFT_core(img_g)
        img_r_fft = DFT_IDFT_core(img_r)
        # cv2.imshow("img_b_fft",img_b_fft)
        # cv2.imshow("img_g_fft",img_g_fft)
        # cv2.imshow("img_r_fft",img_r_fft)

        img_merge = np.dstack((img_b_fft, img_g_fft, img_r_fft))
        # cv2.imshow("img_merge",img_merge)
        # cv2.imwrite("img_merge.jpg",img_merge)

        return img_merge
    else:
        img_g_fft = FFT_IFFT_FFT_core(img_gs)
        # cv2.imshow("img_gs_fft",img_gs_fft)
        # cv2.imwrite("img_merge.jpg",img_g_fft)

        return img_g_fft

# Main
if __name__ == '__main__':
    # Just one argument
    if  len(sys.argv) == 2:

        picture_file = args[1]
        img_col = cv2.imread(picture_file , cv2.IMREAD_COLOR)

        # Failed to load an image
        if img_col is None:
            print("** ----------------------------------------------------------------------------------------------")
            print("** Failed to load image file, invalid file. It may not image file or, may contain 2 byte letters, or run python on wrong directory.")
            print("** See below to refer argument.")
            print("** Image file: %s"%(args[1]))
            print("** ----------------------------------------------------------------------------------------------")
            sys.exit()


        cv2.imshow("MASKED",MASK_PROCESS_BY_FFT(img_col))

        cv2.waitKey(0)

    # Failed to call argument
    else:
        print ("* Invalid command line syntax.")
        print ("  To evaluate image file -----> Usage:  python %s %s" %(args[0], "[Picture file]"))
        sys.exit()

試したこと

カラー画像の場合、RGBに分割してそれぞれのチャンネルに対してFTT-->IFFTをしています。それぞれのチャンネルに対してIFFT後のを確認しましたが、IFFT後にほぼ二値化されている(?)ようで、そこに問題があるように感じています。

補足情報(言語/FW/ツール等のバージョンなど)

Python 3.5

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

+1

import部分にfrom PIL import Imageを追加した上で、関数を以下のように挿げ替えるとちゃんと動きます。

def DFT_IDFT_core(img_ch):
    # ------------------------
    # DFT method with OpenCV
    # ------------------------

    # Get image size
    row,col = img_ch.shape
    row_center, col_center = int(row/2), int(col/2)

    # Calclate optimized size for FFT
    fft_row = cv2.getOptimalDFTSize(row)
    fft_col = cv2.getOptimalDFTSize(col)

    # Generate optimized image
    img_merged = np.zeros((fft_row, fft_col), np.uint8)
    img_merged[0:row,0:col] = img_ch

    # Calc DFT(IMPORTANT: CALL "cv2.DFT_SCALE" TO REMOVE "*e^x")
    dft = cv2.dft(np.float32(img_merged),flags=cv2.DFT_COMPLEX_OUTPUT|cv2.DFT_SCALE )

    # Shift DFT
    dft_shift = np.fft.fftshift(dft)

    # MASK process
    # mask = np.zeros((fft_row,fft_col,2),np.uint8)
    # mask[row_center-200:row_center+200, col_center-200:col_center+200] = 1
    # masked = dft_shift*mask
    masked = dft_shift

    # Calc IDFT
    f_ishift = np.fft.ifftshift(masked)
    img_back = cv2.idft(f_ishift)

    # Calc magnitude
    img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

    # Crop raw area
    img_back = img_back[0:row, 0:col]

    # Float to ingeter
    #img_back = np.round(img_back).astype(np.int64)
    img_back = np.uint8(np.round(img_back))

    # Debug with openCV
    cv2.imshow("img_ch",img_ch)
    cv2.imshow("img_back",img_back)
    cv2.waitKey(0)

    # Debug with plt
    plt.subplot(121),plt.imshow(img_ch, cmap = 'gray')
    plt.title('Input Image'), plt.xticks([]), plt.yticks([])
    plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
    plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
    plt.show()

    return img_back

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/14 06:43

    >import部分にfrom PIL import Imageを追加した上で
    今更ですが、PILは呼び出していないのでこの部分は不要でした!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる