人工知能作っちゃう?

画像処理を中心に人工知能を作っていきます。

アフィン変換

アフィン変換とは二次元画像を回転させたり引き伸ばしたり、平行四辺形に変換(スキュー)する技術です。わからない方は複雑な計算式を思い浮かべるかもしれませんがとても簡単です。二つの二元一次方程式で表すことができるのですから。

概要

アフィン変換は二次元の場合3次元の行列をかけます。余分な一次元は平行移動の際に必要があります。
ですが行列を使わなくてもx',y'ともに前述した二元一次方程式で表現できるので今回はそちらで行います。式はこちらです。f:id:manato2cc:20161016202601g:plain
moveX,YはそれぞれXの移動、Yの移動を表しています。この式を使うと反時計回りにθ°回転させることができます。
今はまだ回転させた画像を保存するのを作っていないので早速コードを見ていきましょう。

package Imany.util.algorithm;

import java.awt.image.BufferedImage;
import Imany.util.ImagePanel;
import java.awt.Graphics;
import java.awt.Color;

public class Affine extends Algorithm
{
	/*
	x' = x*cosθ - y+sinθ + 0
	y' = x*sinθ + y*cosθ + 0
	*/
	//画像 回転するパネル 角度
	public static void algorithm(BufferedImage img, ImagePanel ip, double theta)
	{
		double rad = deg2rad(theta);
		ip.affine(img, rad);
	}

	public static void drawAffineImage(Graphics g, BufferedImage img, double rad)
	{
		int centerX = img.getWidth() / 2;
		int centerY = img.getHeight() / 2;
		for (double x = 0d; x < img.getWidth(); x++) {
			for (double y = img.getHeight()-1; y >= 0; y--) {
				g.setColor(new Color(img.getRGB((int)x,(int)y)));
				g.fillRect(
					(int) (getX_inc(x-centerX,y-centerY,rad)+CENTERX),
				 	(int) (getY_inc(x-centerX,y-centerY,rad)+CENTERY),
				 	1,
				 	1);
			}
		}
	}

	//各座標のx増加量
	private static double getX_inc(double x, double y, double rad)
	{
		return (Math.cos(rad) * x) - (Math.sin(rad) * y);
	}

	private static double getY_inc(double x, double y, double rad)
	{
		return (Math.sin(rad)*x) + (Math.cos(rad)*y);
	}

	public static double deg2rad(double degrees)
	{
		return degrees * (Math.PI / 180f);
	}
}

保存ができないと言ったのは今はJPanelのgetGraphicsで取得したGraphicsクラスでパネルにピクセルデータを直接描画しているからです。
ポイント1: getX_inc, getY_inc関数は上述の二元一次方程式の計算をしてそれぞれx', y'を返しています。

このAffine.javaには欠点があって回転させると無理やりint型に変換しているから隙間ができてしまうんです。
ガウシアンフィルタを通せばいいのですがまだBufferedImageクラスで描画していないので後日処理を考えます。

結果

f:id:manato2cc:20161016204421p:plainf:id:manato2cc:20161016204423p:plain
隙間はありますが好きな角度で回転させることができています。