読者です 読者をやめる 読者になる 読者になる

デジタル・デザイン・ラボラトリーな日々

アラフィフプログラマーが数学と物理を基礎からやり直す

射影変換(ホモグラフィ)について理解してみる その2

前回の続きです。

ただ、私としては台形に変形させたいので、8次元連立一次方程式を解いた方式をさらに模索していた中で、下記サイトを見つけました。
ホモグラフィ(CSS3 Transform 3D Test)- Shogo Computing Laboratory
内容的には私が目指していたものですが、残念なのは中身はCSSなんですよね。

射影変換(ホモグラフィ)について理解してみる - デジタル・デザイン・ラボラトリーな日々

先ず下記の8次元連立一次方程式を解く方法ですが、これには行列を使えばいいことが分かりました。
変換前の座標 左上から時計回り
(x1,y1),(x2,y2)
(x4,y4),(x3,y3)
変換後の座標 左上から時計回り
(X1,Y1),(X2,Y2)
(X4,Y4),(X3,Y3)

8次元連立一次方程式
X1 = x1 \times a + y1 \times b + c - x1 \times g \times X1 - y1 \times h \times X1
Y1 = x1 \times d + y1 \times e + f - x1 \times g \times Y1 - y1 \times h \times Y1
X2 = x2 \times a + y2 \times b + c - x2 \times g \times X2 - y2 \times h \times X2
Y2 = x2 \times d + y2 \times e + f - x2 \times g \times Y2 - y2 \times h \times Y2
X3 = x3 \times a + y3 \times b + c - x3 \times g \times X3 - y3 \times h \times X3
Y3 = x3 \times d + y3 \times e + f - x3 \times g \times Y3 - y3 \times h \times Y3
X4 = x4 \times a + y4 \times b + c - x4 \times g \times X4 - y4 \times h \times X4
Y4 = x4 \times d + y4 \times e + f - x4 \times g \times Y4 - y4 \times h \times Y4

これを行列式q=APに変換します。
f:id:Yaju3D:20130805022542j:plain

CSSを使用したホモグラフィのソースリストを見ても、変換元座標(origin)と変換先座標(markers)で4点分ループして行列式を作成していますね。

var i, M = [], V = [];
var x, y, X, Y;
for(i=0;i<4;i++) {
	x = origin[i][0];
	y = origin[i][1];
	X = markers[i].x() - imgx;
	Y = markers[i].y() - imgy;
	M.push([x, y, 1, 0, 0, 0, -x*X, -y*X]);
	M.push([0, 0, 0, x, y, 1, -x*Y, -y*Y]);
	V.push(X);
	V.push(Y);
}

変換元座標(origin)と変換先座標(markers)から8個のパラメータを求める必要があります。
それには逆行列(inverse)を使います。

q=APからパラメータPを求めるにはA逆行列A^{-1}を掛ければいいので、P=A^{-1}qとなります。
逆行列については、「逆行列を理解してみる」を参照
f:id:Yaju3D:20130810190523j:plain

Javascriptには標準では行列ライブラリがありませんが、このプログラムでは"sylvester"の"sylvester-min.js"という代数ライブラリを使用しております。これは記法も凄く短くて、 $V() でベクトル生成、$M() でマトリクス(行列)生成となっております。

行列計算によって、8個のパラメータ(a,b,c,d,e,f,g,h)は、ans.e(1)~ans.e(8)として値が求まりました。

var ans = $M(M).inv().x($V(V));
console.log($M(M).inspect());
console.log($V(V).inspect());
console.log(ans.inspect());       

8個のパラメータから台形等に変形した画像にしているのが下記の部分です。
上記まではCSSではなくJavascriptであるため、Canvasに移植する上では問題ないのですが、Canvasではmatrix3dのような画像変形は自前で処理する必要があります。

var transform = "perspective(1px)scaleZ(-1)translateZ(-1px)matrix3d(" +
				ans.e(1) + ',' + ans.e(4) + ',' + ans.e(7) + ',0,' +
				ans.e(2) + ',' + ans.e(5) + ',' + ans.e(8) + ',0,' +
				ans.e(3) + ',' + ans.e(6) + ',1,0,' +
				'0,0,0,1)translateZ(1px)';
}

次回は、画像変形処理について解析していきます。