画像を2次元FFTで処理したいのですが、結果が正しくない気がします……
スケーリングはパワースペクトルの平方根の対数を取ったのですが、ImageJなどのプログラムで二次元FFTした結果と見比べると何かが違う気がします。どこかコードに間違えているところがあるのでしょうか?
ちなみにFFT用のライブラリは、「大浦版FFTのJava移植」を使用しています。
例:
元画像(lena)→
このプログラムで処理した結果→
ImageJ→
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class show_resolution{
public static void main(String args[]){
if(args.length < 1) return;
try{
BufferedImage image = ImageIO.read(new File(args[0]));
int w = image.getWidth(), h = image.getHeight();
double[] image_data = new double[w * h * 2];
// データを配列に代入する
for(int y = 0; y < h; ++y){
for(int x = 0; x < w; ++x){
int color = image.getRGB(x, y);
int r = (color & 0xff0000) >> 16;
int g = (color & 0xff00) >> 8;
int b = color & 0xff;
image_data[(x + y * w) * 2] = 0.299 * r + 0.587 * g + 0.114 * b;
image_data[(x + y * w) * 2 + 1] = 0.0;
}
}
// 二次元FFT
fft2d(image_data, w, h);
// パワースペクトルに変換
power_spectral(image_data, w, h);
// 象限入れ替え
swap_quadrants(image_data, w, h);
// 正規化
normalization(image_data, w, h);
// 出力
for(int y = 0; y < h; ++y){
for(int x = 0; x < w; ++x){
int Y = (int)(image_data[(x + y * w)] * 255);
if(Y > 255) Y = 255;
if(Y < 0) Y = 0;
image.setRGB(x, y, 0x010101 * Y + 0xff000000);
}
}
String file_name = args[0].substring(0, args[0].lastIndexOf(".")) + "_FFT.png";
ImageIO.write(image, "png", new File(file_name));
}catch(Exception error){
error.printStackTrace();
}
}
// 正規化
static void normalization(double[] a, int w, int h){
double min = a[0], max = a[0];
for(int k = 1; k < w * h; ++k){
min = Math.min(min, a[k]);
max = Math.max(max, a[k]);
}
double diff = max - min;
for(int k = 0; k < w * h; ++k){
a[k] = (a[k] - min) / diff;
}
}
// 象限入れ替え
static void swap_quadrants(double[] a, int w, int h){
int hw = w / 2, hh = h / 2;
double[] b = new double[w * h];
for(int y = 0; y < hh; ++y){
for(int x = 0; x < hw; ++x){
b[(y + hh) * w + x] = a[y * w + (x + hw)]; //第1象限
b[(y + hh) * w + (x + hw)] = a[y * w + x]; //第2象限
b[y * w + (x + hw)] = a[(y + hh) * w + x]; //第3象限
b[y * w + x] = a[(y + hh) * w + (x + hw)]; //第4象限
}
}
for(int k = 0; k < w * h; ++k){
a[k] = b[k];
}
}
// パワースペクトルに変換
static void power_spectral(double[] a, int w, int h){
for(int y = 0; y < h; ++y){
for(int x = 0; x < w; ++x){
double re = a[(x + y * w) * 2];
double im = a[(x + y * w) * 2 + 1];
double norm = re * re + im * im;
if(norm != 0.0) norm = Math.log(norm) / 2;
a[x + y * w] = norm;
}
}
}
// 2次元FFT
static void fft2d(double[] a, int w, int h){
double[] b = new double[w * h * 2];
// 水平方向のFFT
for(int y = 0; y < h; ++y){
fft1d(a, w * 2, y * w * 2);
}
// 転置操作
transpose(a, b, w, h);
// 垂直方向のFFT
for(int x = 0; x < w; ++x){
fft1d(b, h * 2, x * h * 2);
}
// 転置操作
transpose(b, a, h, w);
}
// 1次元FFT
static void fft1d(double[] a, int n, int p){
double[] temp = new double[n];
for(int k = 0; k < n; ++k){
temp[k] = a[p + k];
}
FFT4g fft = new FFT4g(n);
fft.rdft(1, temp);
temp[1] = 0;
for(int k = 0; k < n; ++k){
a[p + k] = temp[k];
}
}
// 行列の転置
static void transpose(double[] src, double[] dst, int w, int h){
for(int y = 0; y < h; ++y){
for(int x = 0; x < w; ++x){
int p = x + y * w;
int q = y + x * h;
dst[q * 2 ] = src[p * 2];
dst[q * 2 + 1] = src[p * 2 + 1];
}
}
}
}