// グレイスケール画像に対して畳み込み演算によるフィルタリングを行った画像を生成するプログラム
// プログラム名:fft_convolution.cpp

#include "eps-header.hh"
#include "fft-header.hh"

// 元画像(src)に対してフィルタリング用画像(flt)を畳み込み演算処理し処理済画像(dst)に入れる関数
void convolution(
	class image& src,		// 元画像クラス(入力)
	class image& flt,		// フィルタリング画像クラス(入力)
	class image& dst)		// 処理済画像クラス(出力)
{
	if (src.p == NULL) {
		printf("元画像がありません。");
		return;
	}
	if (flt.p == NULL) {
		printf("フィルタリング用画像がありません。");
		return;
	}

	if (src.get_nr_lines() != flt.get_nr_lines()) {
		printf("元画像とフィルタリング画像のライン数が異なります。\n");
		return;
	}
	if (src.get_nr_pixels() != flt.get_nr_pixels()) {
		printf("元画像とフィルタリング画像のピクセル数が異なります。\n");
		return;
	}

	printf("\nグレイスケール画像に対して畳み込み演算によるフィルタリングをします。\n");

	int src_nr_lines  = src.get_nr_lines();		// 元画像とフィルタリング画像のライン数   (縦の画素数)
	int src_nr_pixels = src.get_nr_pixels();	// 元画像とフィルタリング画像のピクセル数 (横の画素数)

	int dst_nr_lines  = src_nr_lines;			// 処理済画像のライン数
	int dst_nr_pixels = src_nr_pixels;			// 処理済画像のピクセル数
	dst.gmake(dst_nr_lines, dst_nr_pixels);		// 処理済画像の配列を確保

	class fourier src_ft(src_nr_lines, src_nr_pixels);	// 元画像用高速フーリエ変換クラスの宣言
	class fourier flt_ft(src_nr_lines, src_nr_pixels);	// フィルタリング画像用高速フーリエ変換クラスの宣言

	// 実数部を元画像とフィルタリング画像の輝度値,虚数部を0.0とする複素数を2次元配列に入れる。
	for (int iy = 0; iy < src_nr_lines; iy ++) {
		for (int ix = 0; ix < src_nr_pixels; ix ++) {
			src_ft.p[iy][ix] = creal8((double)src.p[iy][ix], 0.0);
			flt_ft.p[iy][ix] = creal8((double)flt.p[iy][ix], 0.0);
		}
	}

	src_ft.Forward_FFT();		// 元画像を2次元高速フーリエ変換
	flt_ft.Forward_FFT();		// フィルタリング画像を2次元高速フーリエ変換

	for (int iy = 0; iy < src_nr_lines; iy ++) {
		for (int ix = 0; ix < src_nr_pixels; ix ++) {
			src_ft.p[iy][ix] *= flt_ft.p[iy][ix];	// 周波数空間の複素数乗算
		}
	}

	src_ft.Backward_FFT();		// 2次元高速フーリエ逆変換し処理済画像とする。

	src_ft.MakeImage(
		OUTPUT_AMP,
		FREQ_SPACE_SHUFFLING_ON,
		OUTPUT_SCALE_ON,
		dst.p);
}

// プログラムの開始位置
int main()
{
	class image src;	// 元画像クラスを宣言
	class image flt;	// フィルタリング画像クラスを宣言
	class image dst;	// 処理済画像クラスを宣言

	printf("\n元画像を読み込みます。\n");
	src.gload();		// 元画像をBMPファイルから読み込む
						// BMPファイルを指定したい場合は,
						//   src.gload("パス付きBMPファイル名");
						// とする。
	printf("\nフィルタリング画像を読み込みます。\n");
	flt.gload();		// フィルタリング画像をBMPファイルから読み込む
						// BMPファイルを指定したい場合は,
						//   flt.gload("パス付きBMPファイル名");
						// とする。

	// 元画像(src)に対してフィルタリング用画像(flt)を畳み込み演算処理し処理済画像(dst)に入れる
	convolution(
		src,		// 元画像クラス(入力)
		flt,		// フィルタリング画像クラス(入力)
		dst);		// 処理済画像クラス(出力)

	printf("\n畳み込み演算によるフィルタリングされた画像を保存します。\n");
	dst.gsave();		// 処理済画像をBMPファイルに保存する
						// BMPファイルを指定したい場合は,
						//   dst.gsave("パス付きBMPファイル名");
						// とする。
}