移動座標の対応点からAffine変換の係数を求める
3組の対応点からAffine変換を求める方法について。opencvだとcv2.getAffineTransform()に対応します。なぜ3点なのでしょう。
理論
Affine変換によりがに変換される時次のように書けます。
(1)を書き換えます。
(2)は1対応点のみの場合ですが、N個の対応点がある場合は次のように拡張できます。
(3)を以下のように表記します。
これは最小二乗法の行列表現[1]ですね。が正則ならばは
と求めることが出来ます。の未知数は6つなので、対応点が3つあれば(5)の方法で求めることが出来ます。
また、対応点が4つ以上の場合はが正則でないので逆行列が求められませんが、以下の式で解くことが出来ます。
(6)はが正則な時の唯一つの解になるそうです。[1]
試してみた
時計回りに60度、x,y方向にそれぞれ5,3ずつ移動する変換Mを用意します。((1)の形式の変換行列です。)
theta = 60 tx, ty = 5, 3 M = np.array([[np.cos(np.deg2rad(theta)), -np.sin(np.deg2rad(theta)), tx], [np.sin(np.deg2rad(theta)), np.cos(np.deg2rad(theta)), ty]], float)
Mを出力。
M: [[ 0.5 -0.8660254 5. ] [ 0.8660254 0.5 3. ]]
3点の場合
座標変換前の点の集合。
X = np.array([[15, 5, 1], [25, 10, 1], [20, 15, 1]])
変換。
X_tfm = M.dot(X.T)
前後をプロット。赤:移動前、青:移動後。
(5)から変換行列を計算。Mと一致しています。
M_slv = np.linalg.inv(XX).dot(XX_tfm)
M_slv: [ 0.5 -0.8660254 5. 0.8660254 0.5 3. ]
4点の場合
座標変換前の点の集合。変換。
X = np.array([[15, 5, 1], [25, 10, 1], [20, 15, 1], [18, 18, 1]]) X_tfm = M.dot(X.T)
(6)から変換行列を計算。Mと一致しています。
M_slv = np.linalg.inv(XX.T.dot(XX)).dot(XX.T).dot(XX_tfm)
M_slv: [ 0.5 -0.8660254 5. 0.8660254 0.5 3. ]
参考
[1]最小二乗法の行列表現(単回帰,多変数,多項式),https://mathtrain.jp/leastsquarematrix