情報学部 菅沼ホーム Java 目次 基礎技術目次 索引

移動,回転,縮小・拡大

  1. アフィン変換

      オブジェクトを移動回転縮小拡大させる最も簡単な方法は,AffineTransform クラスAffineTransforOp クラスを利用する方法です.AffineTransform クラスは,右図に示すような行列(アフィン変換行列と呼ぶ)をベクトルに掛けることによって座標変換を行います.下に示すのは,移動(座標軸を x 軸方向に tx,y 軸方向に ty だけ移動),拡大・縮小(座標軸を x 軸方向に sx 倍,y 軸方向に sy 倍拡大),及び,回転(座標軸を q ラジアン回転)を単独に行う場合における行列の値を示しています.なお,これらの操作は座標軸を対象として行われることに注意してください.
      この例は,読み込んだ画像を左右反転,及び,回転させた例です.左側が元の画像,中央が左右反転した画像,及び,右側が座標軸を反時計方向に 45 度回転した場合を表しています.例えば回転の場合,一見,画像を時計方向に 45 度( -45 度)回転した結果のように見えますが,反時計方向に 45 度回転した座標軸が水平方向及び垂直方向になり,その座標軸から見た結果が表示されています.例えば,現在の座標系における点 p(0, 1) は,座標軸を反時計方向に 45 度回転させたとき,その座標系から点 p を見るとどのように見えるかを考えてみてください.点 p の座標は,(cos(45°), -sin(45°)) = (0.707, -0.707) のように見えるはずです.同様に,他の変換についても,座標軸に対する変換であることに注意してください.
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import java.awt.geom.*;
    04	import java.awt.image.*;
    05	import javax.swing.*;
    06	import javax.imageio.*;
    07	
    08	public class Test {
    09		public static void main (String[] args)
    10		{
    11			Win win = new Win("アフィン変換1");
    12		}
    13	}
    14	
    15	class Win extends JFrame
    16	{
    17		/******************/
    18		/* コンストラクタ */
    19		/******************/
    20		Win(String name)
    21		{
    22						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    23			super(name);
    24						// Windowの大きさ
    25			setSize(840, 370);   // +40, +70
    26						// 画像の読み込み
    27			Image im = getToolkit().getImage("hana.gif");
    28						// 画像が完全に読み込まれるまで待つ
    29			MediaTracker trk = new MediaTracker(this);
    30			trk.addImage(im, 0);
    31			try {
    32				trk.waitForID(0);
    33			}
    34			catch (InterruptedException e) {}
    35						// MainPanel オブジェクト
    36			MainPanel pn = new MainPanel(im);
    37			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    38						// ウィンドウを表示
    39			setVisible(true);
    40						// イベントアダプタ
    41			addWindowListener(new WinEnd());
    42		}
    43	
    44		/******************************/
    45		/* 上,左,下,右の余白の設定 */
    46		/******************************/
    47		public Insets getInsets()
    48		{
    49			return new Insets(50, 20, 20, 20);
    50		}
    51	
    52		/************/
    53		/* 終了処理 */
    54		/************/
    55		class WinEnd extends WindowAdapter
    56		{
    57			public void windowClosing(WindowEvent e) {
    58				System.exit(0);
    59			}
    60		}
    61	}
    62	
    63	class MainPanel extends JPanel
    64	{
    65		Image im1;
    66		BufferedImage im0, im2;
    67		MainPanel(Image im)
    68		{
    69			im1 = im;
    70			setBackground(new Color(238, 255, 238));   // 背景色の設定
    71						// BufferedImageに変換
    72			int w = im1.getWidth(null);
    73			int h = im1.getHeight(null);
    74			im0 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    75			Graphics g = im0.getGraphics();
    76			g.drawImage(im1, 0, 0, null);
    77			g.dispose();
    78						// 左右反転
    79			AffineTransform at1 = AffineTransform.getScaleInstance(-1.0, 1.0);
    80			at1.translate(-w, 0);
    81			AffineTransformOp op1 = new AffineTransformOp(at1, null);
    82			im2 = op1.filter(im0, null);
    83		}
    84						// 描画
    85		public void paintComponent(Graphics g)
    86		{
    87			super.paintComponent(g);   // 親クラスの描画
    88								// 基の画像
    89			g.drawImage(im1, 50, 50, this);
    90								// 左右反転
    91			g.drawImage(im2, 300, 50, this);
    92								// 45度回転
    93			Graphics2D g2 = (Graphics2D)g;
    94			AffineTransform affin = new AffineTransform();
    95			affin.translate(670, 20);   //イメージの移動
    96			affin.rotate(45 * Math.PI / 180, 0, 0);   //イメージを画像の左上を中心に回転
    97			g2.drawImage(im1, affin, null);   //イメージの描画
    98		}
    99	}
    			
    72 行目~ 77 行目

      反転操作を行うため,読み込んだ画像を BufferedImage クラスのオブジェクトに変換しています.

    79 行目

      AffineTransform クラスのメソッド getScaleInstance を使用して,横軸を -1 倍,縦軸を 1 倍にしています(つまり,y 軸に対して反転).

    80 行目

      上の変換により,画像が y 軸の左側に表示されるようになりますので,座標軸を画像の幅だけ左側に移動しています.

    81 行目

      アフィン変換に基づき,新しい座標系を構築します.

    82 行目

      72 行目~ 77 行目で作成した BufferedImage を,新しい座標系に基づいた BufferedImage に変換します.この BufferedImage を表示すると,左右反転した画像が表示されます( 91 行目).

    95 行目

      座標軸の原点を (670, 20) に移動します.

    96 行目

      移動した座標軸を,反時計方向に 45 度回転します.

    97 行目

      回転した座標軸上に画像を表示します.

      この例では,描画する際に移動,回転,縮小等の処理を行っています.
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import java.awt.geom.*;
    04	import javax.swing.*;
    05	
    06	public class Test {
    07		public static void main (String[] args)
    08		{
    09			Win win = new Win("アフィン変換2");
    10		}
    11	}
    12	
    13	class Win extends JFrame
    14	{
    15		/******************/
    16		/* コンストラクタ */
    17		/******************/
    18		Win(String name)
    19		{
    20						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    21			super(name);
    22						// Windowの大きさ
    23			setSize(340, 320);   // +40, +70
    24						// ContentPane の取得と MainPanel の追加
    25			MainPanel pn = new MainPanel();   // MainPanel オブジェクトの生成
    26			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    27			pn.setSize(300, 250);
    28						// ウィンドウを表示
    29			setVisible(true);
    30						// イベントアダプタ
    31			addWindowListener(new WinEnd());
    32		}
    33	
    34		/******************************/
    35		/* 上,左,下,右の余白の設定 */
    36		/******************************/
    37		public Insets getInsets()
    38		{
    39			return new Insets(50, 20, 20, 20);
    40		}
    41	
    42		/************/
    43		/* 終了処理 */
    44		/************/
    45		class WinEnd extends WindowAdapter
    46		{
    47			public void windowClosing(WindowEvent e) {
    48				System.exit(0);
    49			}
    50		}
    51	}
    52	
    53	class MainPanel extends JPanel
    54	{
    55		MainPanel()
    56		{
    57			setBackground(new Color(238, 255, 238));   // 背景色の設定
    58		}
    59						// 描画
    60		public void paintComponent(Graphics g)
    61		{
    62			super.paintComponent(g);   // 親クラスの描画
    63								// Graphics2Dの取得
    64			Graphics2D g2 = (Graphics2D)g;
    65								// 線幅が5ピクセルの矩形(左上)
    66			g2.setStroke(new BasicStroke(5.0f));
    67			g2.draw(new Rectangle(20, 20, 100, 50));
    68								// 塗りつぶした矩形(赤)(左中)
    69			g2.setColor(Color.red);
    70			g2.fill(new Rectangle(20, 90, 100, 50));
    71								// 塗りつぶした矩形(グラデーション)(左下)
    72			g2.setPaint(new GradientPaint(20f, 160f, Color.yellow, 120f, 160f, Color.red));
    73			g2.fill(new Rectangle(20, 160, 100, 50));
    74								// 移動(右上)
    75			g2.setColor(Color.green);
    76			g2.setStroke(new BasicStroke(5.0f));
    77			g2.transform(new AffineTransform());
    78			g2.translate(140.0, 0.0);
    79			g2.draw(new Rectangle(20, 20, 100, 50));
    80								// 回転(右中)
    81			g2.translate(30, 70);
    82			g2.rotate(45.0 * Math.PI / 180.0);
    83			g2.draw(new Rectangle(30, 0, 100, 50));
    84								// 縮小(右下)
    85			g2.rotate(-45.0 * Math.PI / 180.0);
    86			g2.scale(0.7, 0.7);
    87			g2.draw(new Rectangle(0, 150, 100, 50));
    88		}
    89	}
    			
    65 行目~ 73 行目

      元の座標系の上に,3 種類の矩形を描いています.

    77 行目

      以後の描画に,アフィン変換を適用します.

    78 行目

      座標軸を (140.0, 0.0) に移動します.

    79 行目

      移動した座標軸に基づき,矩形を描画します.

    81 行目

      座標軸を (30, 70) に移動します.

    82 行目

      移動した座標軸を,反時計方向に 45 度回転します.

    83 行目

      移動,回転した座標軸に基づき,矩形を描画します.

    85 行目

      座標軸を,時計方向に 45 度回転します(回転されない状態に戻る).

    86 行目

      両方の座標軸を 0.7 倍に縮小します.

    87 行目

      矩形を描画します(原点は (30, 70) )

  2. もう一つの例

      この例では,画面上でマウスをクリックすると,拡大(縮小)及び移動を行い,再びクリックすると元に戻ります(左から右へ,右から左へ).
    import java.awt.*;
    import java.awt.geom.*;
    import javax.swing.*;
    import java.awt.event.*;
    
    public class Test {
    	public static void main (String[] args)
    	{
    		Win win = new Win("アフィン変換3");
    	}
    }
    
    class Win extends JFrame
    {
    	/******************/
    	/* コンストラクタ */
    	/******************/
    	Win(String name)
    	{
    					// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    		super(name);
    					// Windowの大きさ
    		setSize(310, 220);   // +40, +70
    					// ContentPane の取得と MainPanel の追加
    		MainPanel pn = new MainPanel();   // MainPanel オブジェクトの生成
    		getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    		pn.setSize(270, 150);
    					// ウィンドウを表示
    		setVisible(true);
    					// イベントアダプタ
    		addWindowListener(new WinEnd());
    	}
    
    	/******************************/
    	/* 上,左,下,右の余白の設定 */
    	/******************************/
    	public Insets getInsets()
    	{
    		return new Insets(50, 20, 20, 20);
    	}
    
    	/************/
    	/* 終了処理 */
    	/************/
    	class WinEnd extends WindowAdapter
    	{
    		public void windowClosing(WindowEvent e) {
    			System.exit(0);
    		}
    	}
    }
    
    class MainPanel extends JPanel
    {
    	private int state = 0;   //マウスによるクリック状態
    
    	MainPanel()
    	{
    		setBackground(new Color(238, 255, 238));   // 背景色の設定
    		addMouseListener(new ClickMouse());
    	}
    					// 描画
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);   // 親クラスの描画
    							// Graphics2Dの取得
    		Graphics2D g2 = (Graphics2D)g;
    		g2.setColor(Color.green);
    		g2.setStroke(new BasicStroke(5.0f));
    							// 線幅が5ピクセルの矩形
    		if (state % 2 == 0)
    			g2.draw(new Rectangle(20, 20, 100, 50));
    							// 拡大と移動
    		else {
    			g2.transform(new AffineTransform());
    			g2.translate(70.0, 30.0);
    			g2.scale(1.5, 1.5);
    			g2.draw(new Rectangle(20, 20, 100, 50));
    		}
    	}
    	/******************************/
    	/* クリック押されたときの処理 */
    	/******************************/
    	class ClickMouse extends MouseAdapter {
    		public void mouseClicked(MouseEvent e)
    		{
    			state++;
    			repaint();
    		}
    	}
    }
    			

情報学部 菅沼ホーム Java 目次 基礎技術目次 索引