// FourieTest.java import java.applet.Applet; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.awt.event.*; import java.awt.image.*; import com.sun.image.codec.jpeg.*; import com.sun.image.codec.*; import java.lang.Math.*; /*<applet code="FourieTest.class" width="512" height="290"> <param name="input_img" value="h6_gray.jpg"> </applet>*/ //width="391" height="294" public class FourieTest extends Applet{ Image input_img; Image img1; Image img2; boolean fourie_flag=false; MediaTracker mt; int input_w=410,input_h=307; int w=512,h=256; int[][] input_color= new int[input_w*input_h][3]; int[][] color= new int[w*h][3]; double[][] fourie_r= new double[h][w]; double[][] fourie_i= new double[h][w]; Button btn_fourie = new Button("フーリエ変換/逆変換"); Button btn_low = new Button("ローパスフィルタ"); Button btn_high = new Button("ハイパスフィルタ"); Button btn_noise = new Button("ノイズ付加"); Button btn_reset = new Button("リセット"); public void init(){ mt=new MediaTracker(this); int tmp; setBackground(Color.white); input_img = getImage(getDocumentBase(), getParameter("input_img")); getColor(input_img, input_color, input_w, input_h); double rate =(double)input_w / (double)w; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ /* if(j>=(w-input_w)/2 && j<input_w+(w-input_w)/2){ tmp=input_color[(j-(w-input_w)/2)+i*input_w][0]; } else{ tmp=0; } if(j<w/2){ tmp=128; } else{ tmp=0; } */ tmp=input_color[(int)(rate*j)+ (int)(rate*i)*input_w][0]; for(int k=0;k<3;k++){ color[j+i*w][k]= tmp; } } } img1=makeImage(color,w,h); getColor(img1, color, w, h); img2=img1; setLayout(new BorderLayout()); Panel p = new Panel(); p.setBackground(Color.white); add("South",p); p.add(btn_fourie); p.add(btn_low); p.add(btn_high); p.add(btn_noise); p.add(btn_reset); // フーリエ変換 btn_fourie.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(fourie_flag==false){ img1 = fourie(color, fourie_r, fourie_i, w, h); } else{ img1 = r_fourie(color, fourie_r, fourie_i, w, h); } repaint(); getColor(img1, color, w, h); } }); // ローパスフィルタ btn_low.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(fourie_flag==true){ img1 = lowPass(fourie_r, fourie_i, w, h); repaint(); getColor(img1, color, w, h); } } }); // ハイパスフィルタ btn_high.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(fourie_flag==true){ img1 = highPass(fourie_r, fourie_i, w, h); repaint(); getColor(img1, color, w, h); } } }); // ノイズ付加 btn_noise.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(fourie_flag==false){ img1 = noise(color, w, h); repaint(); getColor(img1, color, w, h); } else{ img1 = f_noise(fourie_r, fourie_i, w, h); repaint(); } } }); // リセット btn_reset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { img1 = reset(); fourie_flag=false; repaint(); getColor(img1, color, w, h); } }); } public void paint(Graphics g) { g.drawImage(img1,0,0,this); } public double distance(double d1, double d2 ){ return Math.sqrt(d1*d1+d2*d2); } // フーリエ変換でえたスペクトラムを画像化する。 // スペクトラムの実数部fr // スペクトラムの虚数部fi public Image spectrumImage(double fr[][], double fi[][], int w, // 画像の幅 int h // 画像の高さ ){ int w2=w/2; int h2=h/2; int[][] out = new int[w*h][3]; double[][] r = new double[h2+1][w2+1]; double ave=0; double rate; r[0][0]=distance(fr[0][0],fi[0][0]); ave+=r[0][0]; r[h2][w2]=distance(fr[h2][w2],fi[h2][w2]); ave+=r[h2][w2]; for(int i=1;i<h2;i++){ r[i][0]=2*distance(fr[i][0],fi[i][0]); ave+=r[i][0]; r[i][w2]=2*distance(fr[i][w2],fi[i][w2]); ave+=r[i][w2]; } for(int j=1;j<w2;j++){ r[0][j]=2*distance(fr[0][j],fi[0][j]); ave+=r[0][j]; r[h2][j]=2*distance(fr[h2][j],fi[h2][j]); ave+=r[h2][j]; } for(int i=1;i<h2;i++){ for(int j=1;j<w2;j++){ r[i][j]=4*distance(fr[i][j],fi[i][j]); ave+=r[i][j]; } } ave/=(h2+1)*(w2+1); if(ave!=0){ rate=128/ave; } else{ rate=0; } int tmp=0; double pix_h=(double)(h2)/(double)(h-1); double pix_w=(double)(w2)/(double)(w-1); for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ tmp=(int)(rate*r[(int)(pix_h*i)][(int)(pix_w*j)]); if(tmp<0) tmp=0; if(tmp>255) tmp=255; for(int k=0;k<3;k++){ out[j+i*w][k]=tmp; } } } return makeImage(out,w,h); } // フーリエ変換 // 色情報(0~255)をしまう配列 color[h*w][3] public Image fourie(int color[][], // スペクトラムの実数部 double fr[][], // スペクトラムの虚数部 double fi[][], int w, // 画像の幅 int h // 画像の高さ ){ int w2=w/2; int h2=h/2; double[][] fr2= new double[h][w]; double[][] fi2= new double[h][w]; double[][] a= new double[h2][w2]; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fr[i][j]=(double)color[j+i*w][0]; /* fr[i][j]= 255.0*Math.cos(2.0*K*(Math.PI/h)*(double)i)* 255.0*Math.cos(2.0*K*(Math.PI/h)*(double)j); */ } } for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fi[i][j]=0; } } for(int i=0;i<h;i++){ fft(fr,fi,fr2,fi2,-2.0*(Math.PI/(double)w),i,0,w); } for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fr[i][j]/=w; fi[i][j]/=w; } } for(int i=0;i<w;i++){ fft2(fr,fi,fr2,fi2,-2.0*(Math.PI/(double)h),i,0,h); } for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fr[i][j]/=h; fi[i][j]/=h; } } fourie_flag=true; return spectrumImage(fr,fi,w,h); } // フーリエ逆変換 // 色情報(0~255)をしまう配列 color[h*w][3] public Image r_fourie(int color[][], double r_fr[][], double r_fi[][], int w, // 画像の幅 int h // 画像の高さ ){ int[][] out = new int[w*h][3]; int w2=w/2; int h2=h/2; double[][] r_fr2= new double[h][w]; double[][] r_fi2= new double[h][w]; for(int i=0;i<h;i++){ fft(r_fr,r_fi,r_fr2,r_fi2, 2.0*(Math.PI/(double)w),i,0,w); } for(int i=0;i<w;i++){ fft2(r_fr,r_fi,r_fr2,r_fi2, 2.0*(Math.PI/(double)h),i,0,h); } int tmp=0; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ tmp=(int)r_fr[i][j]; if(tmp<0) tmp=0; if(tmp>255) tmp=255; for(int k=0;k<3;k++){ out[j+w*i][k]=tmp; } } } fourie_flag=false; return makeImage(out,w,h); } // fft public void fft(double fr[][], double fi[][], double fr2[][], double fi2[][], double theta, int y, int p, int N ) { if(N!=1){ int N2 = N/2; double c,s; double xr,xi; for(int i=0;i<N2;i++){ fr2[y][p+i]=fr[y][p+i]+fr[y][p+N2+i]; fi2[y][p+i]=fi[y][p+i]+fi[y][p+N2+i]; c=Math.cos(theta*(double)i); s=Math.sin(theta*(double)i); xr=fr[y][p+i]-fr[y][p+N2+i]; xi=fi[y][p+i]-fi[y][p+N2+i]; fr2[y][p+N2+i]=c*xr-s*xi; fi2[y][p+N2+i]=c*xi+s*xr; } fft(fr2,fi2,fr,fi,2.0*theta,y,p,N2); fft(fr2,fi2,fr,fi,2.0*theta,y,p+N2,N2); for(int i=0;i<N2;i++){ fr[y][p+2*i]=fr2[y][p+i]; fi[y][p+2*i]=fi2[y][p+i]; fr[y][p+2*i+1]=fr2[y][p+N2+i]; fi[y][p+2*i+1]=fi2[y][p+N2+i]; } } } public void fft2(double fr[][], double fi[][], double fr2[][], double fi2[][], double theta, int x, int p, int N ) { if(N!=1){ int N2 = N/2; double c,s; double xr,xi; for(int i=0;i<N2;i++){ fr2[p+i][x]=fr[p+i][x]+fr[p+N2+i][x]; fi2[p+i][x]=fi[p+i][x]+fi[p+N2+i][x]; c=Math.cos(theta*(double)i); s=Math.sin(theta*(double)i); xr=fr[p+i][x]-fr[p+N2+i][x]; xi=fi[p+i][x]-fi[p+N2+i][x]; fr2[p+N2+i][x]=c*xr-s*xi; fi2[p+N2+i][x]=c*xi+s*xr; } fft2(fr2,fi2,fr,fi,2.0*theta,x,p,N2); fft2(fr2,fi2,fr,fi,2.0*theta,x,p+N2,N2); for(int i=0;i<N2;i++){ fr[p+2*i][x]=fr2[p+i][x]; fi[p+2*i][x]=fi2[p+i][x]; fr[p+2*i+1][x]=fr2[p+N2+i][x]; fi[p+2*i+1][x]=fi2[p+N2+i][x]; } } } //ハイパスフィルタ public Image highPass(double fr[][], double fi[][], int w, int h ){ int[][] out = new int[w*h][3]; int h2=h/2; int w2=w/2; double l=1.0/4.0; double sum=0,pass=0; double rate; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ sum+=Math.abs( Math.sqrt(fr[i][j]*fr[i][j] +fi[i][j]*fi[i][j])); if((i<l*h2 || i>(1.0-l)*h2+h2) && (j<l*w2 || j>(1.0-l)*w2+w2)) { pass+=Math.abs( Math.sqrt(fr[i][j]*fr[i][j] +fi[i][j]*fi[i][j])); fr[i][j]=0; fi[i][j]=0; } } } if(pass!=0) { rate=sum/pass; } else{ rate=0; } for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fr[i][j]*=rate; fi[i][j]*=rate; } } return spectrumImage(fr,fi,w,h); } //ローパスフィルタ public Image lowPass(double fr[][], double fi[][], int w, int h ){ int[][] out = new int[w*h][3]; int h2=h/2; int w2=w/2; double l=1.0/4.0; double sum=0,pass=0; double rate; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ sum+=Math.abs(Math.sqrt(fr[i][j]*fr[i][j] +fi[i][j]*fi[i][j])); if((i>l*h2 && i<(1.0-l)*h2+h2) || (j>l*w2 && j<(1.0-l)*w2+w2)) { pass+=Math.abs( Math.sqrt(fr[i][j]*fr[i][j] +fi[i][j]*fi[i][j])); fr[i][j]=0; fi[i][j]=0; } } } if(pass!=0) { rate=sum/pass; } else{ rate=0; } for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ fr[i][j]*=rate; fi[i][j]*=rate; } } return spectrumImage(fr,fi,w,h); } // リセットボタン public Image reset() { return img2; } // ノイズ付加ボタン // 色情報(0~255)をしまう配列 color[h*w][3] public Image noise(int color[][], int w, // 画像の幅 int h // 画像の高さ ){ double rand; int[] pix2= new int[w*h]; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ rand = Math.random(); if(rand<0.03){ rand = Math.random(); for(int k=0;k<3;k++){ color[j+i*w][k]= (int)(rand*255); } } } } return makeImage(color, w , h); } public Image f_noise(double fr[][], // スペクトラムの実数部 double fi[][], // スペクトラムの虚数部 int w, // 画像の幅 int h // 画像の高さ ){ double rand; int[] pix2= new int[w*h]; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ rand = Math.random(); if(rand<0.03){ rand = Math.random(); if(rand<0.5){ rand = Math.random(); fr[i][j]*=(double)rand; } else{ rand = Math.random(); fr[i][j]*=-1.0*(double)rand; } rand = Math.random(); if(rand<0.5){ rand = Math.random(); fi[i][j]*=(double)rand; } else{ rand = Math.random(); fi[i][j]*=-1.0*(double)rand; } } } } return spectrumImage(fr,fi,w,h); } // 色情報から画像をつくる。 // 色情報(0~255)をしまう配列 color[h*w][3] Image makeImage(int color[][], int w, // 画像の幅 int h // 画像の高さ ){ int[] pix = new int[w*h]; for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ pix[j+i*w]=(255<<24)| (color[j+i*w][0]<<16)| (color[j+i*w][1]<<8)| (color[j+i*w][2]); } } return createImage( new MemoryImageSource(w,h,pix,0,w)); } // 画像から色情報を取り出す。 void getColor(Image img, // 元の画像 // 色情報(0~255)をしまう配列 color[h*w][3] int color[][], int w, // 画像の幅 int h // 画像の高さ ) { int[] pix= new int[w*h]; PixelGrabber pg= new PixelGrabber(img,0,0,w,h,pix,0,w); try{pg.grabPixels();}catch(Exception e){} for(int i=0;i<h;i++){ for(int j=0;j<w;j++){ color[j+i*w][0]= (pix[j+i*w] & 0xff0000)>>16; // 赤色 color[j+i*w][1]= (pix[j+i*w] & 0xff00)>>8; // 緑色 color[j+i*w][2]= pix[j+i*w] & 0xff; // 青色 } } } }