Next: 課題
Up: 5 画像処理
Previous: スライダーイベント
以下に知能機械情報学専攻のTAの鈴木義久君による
画像処理プログラムの例を紹介する.
図 14:
フーリエ変換 ハイパスフィルタ領域とその処理結果
|
|
図 15:
フーリエ変換 ノイズ付加,ハイパスフィルタ処理,ローパスフィル
タ処理
|
|
画像のフーリエ変換プログラムの例を以下に紹介する.
// 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; // 青色
}
}
}
}
generated through LaTeX2HTML. M.Inaba 平成18年5月7日