使用したライブラリ
【画像処理100本ノック】独自の画像入出力クラスを作る
【画像処理100本ノックに挑戦】独自の離散フーリエ変換クラスを作る
Q.32. フーリエ変換
二次元離散フーリエ変換(DFT)を実装し、imori.jpgをグレースケール化したものの周波数のパワースペクトルを表示せよ。 また、逆二次元離散フーリエ変換(IDFT)で画像を復元せよ。
画像のパワースペクトルは直流付近の値が大きいため、原点付近だけ真っ白になって全体の分布がよくわからない場合がよくあります。このため、しばしばlog表示されます。今回は数値データとして出力してGnuplotでlog表示します。
int main()
{
PPM ppm("imori.pnm");
int width = ppm.Get_width();
int height = ppm.Get_height();
std::vector<std::vector<std::complex<double>>> f(width, std::vector<std::complex<double>>(height));
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
int r = ppm(i, j, 'r');
int g = ppm(i, j, 'g');
int b = ppm(i, j, 'b');
int y = (std::round)(0.2126 * r + 0.7152 * g + 0.0722 * b);
f[i][j] = y;
}
DFT2D dft2d(width, height);
auto F = dft2d.forward(f);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
std::cout << i << " " << j << " " << std::abs(F[i][j]) << std::endl;
}
std::cout << std::endl;
}
f = dft2d.backward(F);
PPM ppm2(width, height);
for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
{
int val = f[i][j].real();
if (val >= 256) val = 255;
if (val < 0)val = 0;
ppm2(i, j, 'r') = val;
ppm2(i, j, 'g') = val;
ppm2(i, j, 'b') = val;
}
ppm2.Flush("out.ppm");
return 0;
}
gnuplot> set log z
gnuplot> splot "fourier.txt" using 1:2:3 with pm3d
微妙・・・。