サンプルプログラムの概要
サンプルプログラムは以下の内容から成っています(GUI関係は省略)。
準備(init()の内容)
- 画像ファイルを読み込み、
Image
クラスのimg_src
を用意する img_src
を、一次元のR、G、B別データに分解する(ただしSIZE
=WIDTH
xHEIGHT
)- R:
src_red[SIZE]
- G:
src_green[SIZE]
- B:
src_blue[SIZE]
- 一次元のR、G、B別データを二次元化する
- R:
data[0][HEIGHT][WIDTH]
- G:
data[1][HEIGHT][WIDTH]
- B:
data[2][HEIGHT][WIDTH]
実行(paint()の内容)
- 原画像
img_src
を回転し、拡大してimg_dest
を作成する img_dest
を描画する- その時の回転角
theta
を表示する
rotateImage(img_src, theta)
を使用するメソッドrotateImage(img_src, theta)
- スクロールバーで与えられた回転角
theta
から、拡大倍率zoom
を計算する - 回転と拡大を同時に行なうアフィン変換の係数
sint
、cost
を計算する - 補正画像の中心座標(
WIDTH/2
,HEIGHT/2
)を中心に、i
とj
をスキャンし、データを取得すべき原画像の座標xx
、yy
(一般的には整数値でない)を計算する xx
、yy
を整数部と小数部に分け、整数部はx
、y
、小数部はdx
、dy
とする- 整数部
x
、y
により原画像の4点のR、G、B別の二次元データを取得する - 4点のデータから、
dx
、dy
を用いて線形補間を行い、R、G、B別の補間値inter[0]
、inter[1]
、inter[2]
を計算する - R、G、B別の補間値から、一次元RGB値
rgb_dest[SIZE]
を得る rgb_dest[SIZE]
からImage
クラスの画像を作成する
プログラム
import java.applet.Applet;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class Rotate extends Applet
implements AdjustmentListener,ActionListener{
int WIDTH=640;
int HEIGHT=480;
int SIZE=307200;
double ALPHA=Math.atan((double)WIDTH/HEIGHT);
int X0=10;
int Y0=40;
int[] src_red=new int[SIZE];
int[] src_green=new int[SIZE];
int[] src_blue=new int[SIZE];
int[][][] data=new int[3][HEIGHT][WIDTH];
Label label0,label1,label2;
Scrollbar scroll;
Button button;
float theta;
Image img_src,img_dest;
public void init(){
setBackground(Color.yellow);
Panel panel=new Panel();
panel.setLayout(new GridLayout(1,7,0,10));
add(panel,"North");
scroll=new Scrollbar(Scrollbar.HORIZONTAL,0,5,-60,65);
scroll.addAdjustmentListener(this);
label0=new Label(" ");
label1=new Label(" 左下がり(Max 30°)");
label2=new Label(" 右下がり(Max 30°) ");
button=new Button("元に戻す");
button.addActionListener(this);
panel.add(label0);
panel.add(label1);
panel.add(scroll);
panel.add(label2);
panel.add(label0);
panel.add(button);
panel.add(label0);
//画像ファイルを読み込み、Image画像img_srcにする
img_src=readImageFile("trogir.jpg");
//Image画像を一次元R,G,Bに分解する
get1DRGBFromImage(img_src,src_red,src_green,src_blue);
//一次元R,G,Bを二次元化する
change1DRGBTo2D(src_red,data[0]);
change1DRGBTo2D(src_green,data[1]);
change1DRGBTo2D(src_blue,data[2]);
}
public void paint(Graphics g){
//画像を回転する
img_dest=rotateImage(img_src,theta);
//回転した補正画像を描画する
g.drawImage(img_dest,X0,Y0,null);
//回転角を表示する
g.drawString("回転角="+String.valueOf(theta)+"°",
X0,Y0+20+HEIGHT);
}
//画像ファイルを読み込みImage
クラスの画像にするメソッド
public Image readImageFile(String filename){
Image img=getImage(getDocumentBase(),filename);
MediaTracker mtracker=new MediaTracker(this);
mtracker.addImage(img,0);
try{
mtracker.waitForAll();
}catch(Exception e){}
return img;
}
//Image画像を一次元RGB値に分解するメソッド
private void get1DRGBFromImage(Image img,
int[] red, int[] green, int[] blue){
Color color;
int[] rgb=new int[SIZE];
//Image画像imgを一次元RGBデータrgbに変換する
PixelGrabber grabber=
new PixelGrabber(img,0,0,WIDTH,HEIGHT,rgb,0,WIDTH);
try{
grabber.grabPixels();
} catch(InterruptedException e){}
//一次元RGBデータrgbを一次元red、green、blueデータに分解する
for(int i=0;i<SIZE;i++){
color=new Color(rgb[i]);
red[i]=color.getRed();
green[i]=color.getGreen();
blue[i]=color.getBlue();
}
}
//一次元R,G,Bを二次元化するメソッド
public void change1DRGBTo2D(int[] oneD, int[][] twoD){
for(int j=0;j<HEIGHT;j++)
for(int i=0;i<WIDTH;i++)
twoD[j][i]=oneD[WIDTH*j+i];
}
//画像を回転し拡大するメソッド
public Image rotateImage(Image img, float theta){
float xx,yy,dx,dy;
int x,y;
Color color;
int[] rgb_dest=new int[SIZE];
int data_0,data_1,data_2,data_3;
int[] inter=new int[3];
float zoom=(float)(Math.cos(ALPHA-Math.abs(theta)
*Math.PI/180.0)/Math.cos(ALPHA)+0.01);
float sint=(float)Math.sin(theta*Math.PI/180.0)/zoom;
float cost=(float)Math.cos(theta*Math.PI/180.0)/zoom;
int height2=HEIGHT/2;
int width2=WIDTH/2;
for(int i=-width2;i<width2;i++)
for(int j=-height2;j<height2;j++){
//原画像の座標値(実数)を計算する
xx=i*cost+j*sint+width2;
yy=j*cost-i*sint+height2;
//負の無限大に近い整数を求める
x=(int)Math.floor(xx);
y=(int)Math.floor(yy);
//補間に必要な端数を求める
dx=xx-x;
dy=yy-y;
//原画像の4点のデータと端数から線形補間する
for(int k=0;k<3;k++){
data_0=data[k][y][x];
data_1=data[k][y][x+1];
data_2=data[k][y+1][x];
data_3=data[k][y+1][x+1];
inter[k]=(int)((data_0*(1.0f-dx)+data_1*dx)*
(1.0f-dy)+(data_2*(1.0f-dx)+data_3*dx)*dy+0.5f);
}
color=new Color(inter[0],inter[1],inter[2]);
rgb_dest[(height2+j)*WIDTH+width2+i]=color.getRGB();
}
return createImage(new MemoryImageSource(
WIDTH,HEIGHT,rgb_dest,0,WIDTH));
}
//スクロールバーを変化させた時のメソッド
public void adjustmentValueChanged(AdjustmentEvent ae){
theta=scroll.getValue()/2.0f;
repaint();
}
//「元に戻す」ボタンをクリックした時のメソッド
public void actionPerformed(ActionEvent ae){
if(ae.getSource()==button){
theta=0.0f;
scroll.setValue(0);
repaint();
}
}
}