射影変換の計算方法を求める
長方形の頂点が、カメラの相対的な移動によって、別の4点に移動することを考える
https://gyazo.com/901e7c1933780c02e568ebede417c2d2
このときの変換の計算方法を求める
画像の上では、これらはすべて二次元の平面上の移動である
しかし、計算する上では3次元を考える必要がある
x,yとは別の一つ上の次元zも含めた3次元上で、線形変換と平行移動
そのあと、z=1の平面へ、原点方向の射影
の2段階に分けられる
これは、「カメラを動かしたときに長方形がカメラに対して相対的にどのように動くのか」という考えを、素朴に数学的な表現にしたものである
補足
ところで、射影変換行列というと前者の変換のみを指すような気がするが、どうだったっけか
既存のライブラリを確認しようmiyamonz.icon
2つ合わせたら行列では表せないので、射影変換行列と言うなら前者を指すのだろう
以上の2段階の変換を
(x,y,0) -> (u,v,w) -> (X,Y,1)とする
https://gyazo.com/11fe0539495c2c6f6807bd7da28d2b6f
条件1 線形変換と平行移動
y = Ax+B
条件2 原点に向けて、z=1上に射影
後者の射影の方は、ただ単にz成分で割ることで、z=1の平面に落とすこと
X = u/w
Y = v/w
---.icon
条件1
(u,v,w) = M (x,y,0) + C
補足
z=0なのでMの左2列だけが有効
Cは平行移動
これを書き換えると
$ u = ax+by+c
$ v = dx+ey + f
$ w = gx+hy+i
Mは線形変換としていて、それ以上の仮定をしていない。
上記で述べている前者の変換を、現実のカメラの相対的な配置とみなすなら、
Mは任意回転のみであり、
せん断とスケールが無いことを仮定として数式に反映されていない
しかし、今回は未知数が(上記のa~iの9でなく)8つとなり、4点の座標のx,yで、定まる
一つ消えるのは、後述の条件2を合わせることで消える
これだけで十分ということ
なので行列Mに対して直接何らかの制約は与えていない
そもそもz=0で右1列が消えている
ここに条件2も合わせると
X = u/w = $ \frac{ax+by+c}{gx+hy+i}
Y = v/w = $ \frac{dx+ey+f}{gx+hy+i}
$ i = 1として一般性を失わない
なぜなら
全体を$ iで割り、
$ a^{\prime} = a / i を新たに$ aとすればいいから
これは図形的には、u,v,wを定数倍することにあたり、
前者の変換結果を原点方向に拡大縮小することに当たる
この拡大縮小は、後者の原点方向の射影で消えることを意味する
---.icon
以上より、全体の変換は
$ X = \frac{ax+by+c}{gx+hy + 1}
$ Y = \frac{dx+ey+f}{gx+hy+1}
となる
分母を払い整理すると
$ X = ax + by+ c - gx X - hy X
$ Y = dx + ey+ f - gx Y - hy Y
ここで、
変換前の点を$ (x_i,y_i)
変換後の点を $ (X_i,Y_i)
とする$ (i = 0...3)
以下の8つの式が得られる
$ X_0 = ax_0 + by_0+ c - gx_0 X_0 - hy_0 X_0
$ Y_0 = dx_0 + ey_0+ f - gx_0 Y_0 - hy_0 Y_0
$ X_1 = ax_1 + by_1+ c - gx_1 X_1 - hy_1 X_1
$ Y_1 = dx_1 + ey_1+ f - gx_1 Y_1 - hy_1 Y_1
$ X_2 = ax_2 + by_2+ c - gx_2 X_2 - hy_2 X_2
$ Y_2 = dx_2 + ey_2+ f - gx_2 Y_2 - hy_2 Y_2
$ X_3 = ax_3 + by_3+ c - gx_3 X_3 - hy_3 X_3
$ Y_3 = dx_3 + ey_3+ f - gx_3 Y_3 - hy_3 Y_3
これは$ x_i,y_i, X_i,Y_iを定数として、a~hを未知数とした、8元連立方程式である
これは、特定の条件下で解くことができる
4点が直線状に並んだりすると解けない
連立方程式を解く
まずは、変換元の点が(0,0)(1,0)(0,1)(1,1)の4点の場合を考える
この4点から任意の4点への計算方法がわかれば、任意の4点→任意の4点の場合も解ける
$ x_0=0, y_0=0,
$ x_1=1, y_1=0,
$ x_2=0, y_2=1,
$ x_3=1, y_3=1,
とする
このとき、上の連立方程式は
$ X_0 = c
$ Y_0 = f
$ X_1 = a + c - g X_1
$ Y_1 = d + f - g Y_1
$ X_2 = b + c - h X_2
$ Y_2 = e + f - h Y_2
$ X_3 = a + b+ c - g X_3 - h X_3
$ Y_3 = d + e+ f - g Y_3 - h Y_3
となる
最初の2行より、すでにc,fについては解けている
残りの式のc,fにこれを代入し
$ X_1 = a + X_0 - g X_1
$ Y_1 = d + Y_0 - g Y_1
$ X_2 = b + X_0 - h X_2
$ Y_2 = e + Y_0 - h Y_2
$ X_3 = a + b+ X_0 - g X_3 - h X_3
$ Y_3 = d + e+ Y_0 - g Y_3 - h Y_3
a,b,d,eについて消去して、
$ X_3 - X_1 - X_2
$ = (a + b+ X_0 - g X_3 - h X_3) - (a + X_0 - g X_1) - (b + X_0 - h X_2)
$ = g (X_1 -X_3) + h (X_2 - X_3) - X_0
$ Y_3 - Y_1 - Y_2
$ = (d + e+ Y_0 - g Y_3 - h Y_3) - (d + Y_0 - g Y_1) - (e + Y_0 - h Y_2)
$ = g (Y_1 -Y_3) + h (Y_2 - Y_3) - Y_0
よって
$ X_0 - X_1 - X_2 + X_3 = g (X_1 -X_3) + h (X_2 - X_3)
$ Y_0 - Y_1 - Y_2 + Y_3 = g (Y_1 -Y_3) + h (Y_2-Y_3)
<=>
$ \left( \begin{array} {c} { X_0 - X_1 - X_2 + X_3 } \\ { Y_0 - Y_1 - Y_2 + Y_3 } \end{array} \right) $ = \left( \begin{array} {cc} { X_1-X_3 } & { X_2-X_3 } \\ { Y_1-Y_3 } & { Y_2-Y_3 } \end{array} \right) \left( \begin{array} {cc} {g} \\ {h} \end{array} \right)
簡単のため、以下のように置くと (これはプログラムで計算する場合にも使える
$ s_x = X_0 - X_1 - X_2 + X_3
$ s_y = Y_0 - Y_1 - Y_2 + Y_3
$ dx_1 = X_1-X_3
$ dx_2 = X_2-X_3
$ dy_1 = Y_1-Y_3
$ dy_2 = Y_2-Y_3
すると上の式は簡単に以下のように書ける
$ \left( \begin{array} {c} { s_x } \\ { s_y } \end{array} \right) $ = \left( \begin{array} {cc} { dx_1 } & { dx_2 } \\ { dy_1 } & { dy_2 } \end{array} \right) \left( \begin{array} {cc} {g} \\ {h} \end{array} \right)
よって
$ z = dx_1dy_2 - dx_2dy_1として, g,hについて解くと
$ g= \frac{ dy_2 s_x - dx_2 s_y }{z}
$ h = \frac{dx_1 s_y - dy_1 s_x}{z}
あとはa,d,b,eについても
$ a = X_1-X_0 + g X_1
$ d = Y_1 - Y_0 + g Y_1
$ b = X_2 - X_0 + h X_2
$ e = Y_2 - Y_0 + h Y_2
となり、g,hを代入すればよい
(プログラムに置いては、先にg,hを計算し変数において、上の式をそのまま書いてadbeを求めればいい
以上より、a-hが全て、X_i,Y_iで表された
これは4点を時計回りにやっているので上で書いているものと、2,3が逆なのに注意
code:cs
var system:Array = new Array( 8 );
var sx:Number = (P0.x-P1.x)+(P2.x-P3.x); var sy:Number = (P0.y-P1.y)+(P2.y-P3.y); var dx1:Number = P1.x-P2.x; var dx2:Number = P3.x-P2.x; var dy1:Number = P1.y-P2.y; var dy2:Number = P3.y-P2.y; var z:Number = (dx1*dy2)-(dy1*dx2);
var g:Number = ((sx*dy2)-(sy*dx2))/z;
var h:Number = ((sy*dx1)-(sx*dy1))/z;
system0=P1.x-P0.x+g*P1.x; system1=P3.x-P0.x+h*P3.x; system3=P1.y-P0.y+g*P1.y; system4=P3.y-P0.y+h*P3.y; $ \left( \begin{array} { l } { u } \\ { v } \\ { w } \end{array} \right) = \left( \begin{array} { l l l } { a } & { b } & { c } \\ { d } & { e } & { f } \\ { g } & { h } & { 1 } \end{array} \right) \left( \begin{array} { l } { x } \\ { y } \\ { 1 } \end{array} \right)
$ X = u/w
$ Y = v/w
srcを0,1の四角形じゃない場合は、逆行列を前にあわせればいい
あとでかく?miyamonz.icon