【Java】アフィン変換で画像などを回転させる

2018年3月11日

本稿はJavaで画像や図形描画の回転を実現する方法を紹介します。

JavaにはAffineTransformクラスという、アフィン変換を簡単に実装できるクラスが用意されています。

このクラスを利用することで、平行移動、回転、拡大縮小、傾きの制御ができます。

平行移動、拡大縮小はdrawImageの引数で実現できますが、回転はこちらのクラスを使用しなければならないため、回転だけは使用できるようになりましょう。

傾き変換に関してはほぼ使用することはないと思います。

サンプルは画像に対して処理を実行していますが、普通の図形描画にも適用されます。

画像や図形の回転

回転はAffineTransformクラスのsetToRotationメソッドやrotateメソッドを使用します。

メソッドの引数には回転角度を表すラジアンを指定しましょう。

それではサンプルを実行します。

テストで使う画像はこれ

sample.png

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test{
	public static void main(String[] args) {
		GameWindow gw = new GameWindow("テストウィンドウ",400,300);
		DrawCanvas dc = new DrawCanvas();
		gw.add(dc);
		gw.setVisible(true);
	}
}
class GameWindow extends JFrame{

	public GameWindow(String title, int width, int height) {
		super(title);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize(width,height);
		setLocationRelativeTo(null);
		setResizable(false);
	}
}
class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		super.paintComponent(g);

		Graphics2D g2 = (Graphics2D)g;
		AffineTransform at = g2.getTransform();

		//50度回転させます。
		at.setToRotation(Math.toRadians(50));
		g2.setTransform(at);

		g2.drawImage(img, 0, 0, this);
	}
}
実行結果

setToRotationメソッドの回転はX座標、Y座標が0のポイントを中点として回転します。

でも、普通は画像の中央で回転させたいですよね?

その場合は中点を指定するメソッドも用意されているので、それを使用してみましょう。

setToRotation(回転角度のラジアン, 中心点X座標, 中心点Y座標)と指定します。

それではDrawCanvasクラスを修正して画像の中央を中心点として回転させましょう。

class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
		
		AffineTransform at = g2.getTransform();

		//回転角度と画像の中心点を指定する
		at.setToRotation(Math.toRadians(50), img.getWidth(this)/2, img.getHeight(this)/2);
		g2.setTransform(at);

		g2.drawImage(img, 0, 0, this);
	}
}
実行結果

アフィン変換を利用した平行移動

平行移動を利用すると画像や図形の描画位置を移動できます。

普通は描画座標の指定は直接指定するのでそんなに使いませんが、画像の中心点を軸に拡大縮小したい場合や傾斜変換したい場合はtranslateメソッドと併用することで実現できます。

平行移動をするにはsetToTranslation(X座標,Y座標)等と指定します。

それではDrawCanvasクラスのサンプルです。

class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
		AffineTransform at = g2.getTransform();

		//Xに100,Yに100の平行移動
		at.setToTranslation(100,100);
		g2.setTransform(at);

		g2.drawImage(img, 0, 0, this);
	}
}
実行結果

drawImageメソッドの描画座標に0を指定していますが、左上に表示されず、少し右下に移動した状態で描画されました。平行移動が機能していますね。

アフィン変換を利用した拡大縮小

拡大縮小もアフィン変換クラスで実現できます。

setToScaleやscaleメソッドを利用しましょう。

setToScale(横の引き伸ばし倍率,縦の引き伸ばし倍率)と指定します。

class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		Graphics2D g2 = (Graphics2D)g;

		AffineTransform at = g2.getTransform();

		//縦に縮め、横に引き延ばす。
		at.setToScale(1.2, 0.9);
		g2.setTransform(at);

		g2.drawImage(img, 0, 0, this);
	}
}
実行結果

傾斜変換

最も使わないであろう傾斜変換です。

setToShaerやshearメソッドを利用します。

setToShaer(横の傾斜量,縦の傾斜量)と指定します。

class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		Graphics2D g2 = (Graphics2D)g;

		AffineTransform at = g2.getTransform();
		
		//横に大きめに傾斜させ縦にも少しさせる
		at.shear(0.6, 0.1);
		g2.setTransform(at);

		g2.drawImage(img, 0, 0, this);
	}
}
実行結果

変換行列を初期状態にする

一度アフィン変換をかけると以降の全ての描画に設定した内容が適用されるのですが、この変換を適用せず元の状態に戻したいときがあります。

その場合はsetToIdentityメソッドを使用しましょう。

class DrawCanvas extends JPanel{
	Image img = Toolkit.getDefaultToolkit().getImage("sample.png");
	public void paintComponent(Graphics g){
		Graphics2D g2 = (Graphics2D)g;

		AffineTransform at = g2.getTransform();
		at.scale(0.5,0.5);
		at.translate(150, 100);
		at.rotate(Math.toRadians(45));
		at.translate(-150, -100);
		g2.setTransform(at);

		//アフィン変換適用後の描画(左上の画像)
		g2.drawImage(img, 0, 0, this);

		//元の設定に戻す
		at.setToIdentity();
		g2.setTransform(at);

		//元の設定に戻した後の描画(右下の画像)
		g2.drawImage(img, 100, 100, this);
	}
}
実行結果

左上の画像が縮小回転のアフィン変換適用時の画像で、右下の画像が元の変換行列に戻して描画した画像です。

Java

Posted by nompor