アフィン変換の場合、OpenCV に変換前の点群と変換後の点群を与えると、その対応関係を満たすアフィン変換行列を求める関数があります。
求めるには対応する点群が3点以上あればよいです。
サンプルコード
- 3点及び変換行列を作成する。
- 行列を適用し、3点を変換する。
- 変換前と変換後の点群を cv2.getAffineTransform() に与えて、その対応関係を満たす点群を計算する。
- OpenCV は画像処理ライブラリなので、返してくるアフィン変換行列は画像座標系 (左上) のものとなっている。なので、(2, 1) 成分と (1, 2) 成分を入れ替えて、標準座標系でのアフィン変換行列にする。
- 原点回転ならアフィン変換行列の平行移動成分 (1, 3), (2, 3) はともに0なので、捨てる。
- 以上の手順で最初に作成した変換行列を求められた。
- 変換行列からスケール、角度を計算する。
python
1import cv2
2import numpy as np
3
4def get_rotation_matrix_2d(angle, sx, sy):
5 angle = np.deg2rad(angle)
6 return np.array([[sx * np.cos(angle), -sx * np.sin(angle)],
7 [sy * np.sin(angle), sy * np.cos(angle)]],
8 dtype=np.float32)
9
10# 行列を作成する。
11mat1 = get_rotation_matrix_2d(angle=20, sx=1.2, sy=1.5)
12
13# 点1
14pts1 = np.array([[1, 1],
15 [2, 3],
16 [4, 3]], dtype=np.float32)
17
18# 変換を適用する。
19pts2 = np.dot(pts1, mat1)
20
21# 2つの点の対応関係から変換行列を求める。
22mat2 = cv2.getAffineTransform(pts1, pts2)
23
24# 画像座標系 (左上原点) なので、標準座標系 (左下原点) の行列にする。
25mat2[0, 1], mat2[1, 0] = mat2[1, 0], mat2[0, 1]
26# 原点中心の回転なら平行移動はないので、3列目は0
27mat2 = mat2[:, :2]
28
29# 求めた行列が元の行列と一致するか
30print(np.allclose(mat1, mat2)) # True
31
32# 行列からスケール係数及び角度を計算する。
33sx = np.sign(mat1[0, 0]) * np.sqrt(mat1[0, 0] ** 2 + mat1[0, 1] ** 2)
34sy = np.sign(mat1[1, 1]) * np.sqrt(mat1[1, 0] ** 2 + mat1[1, 1] ** 2)
35angle = np.rad2deg(np.arctan2(-mat1[0, 1], mat1[0, 0]))
36print('sx: {:.2f}, sy: {:.2f}, angle: {:.2f}'.format(sx, sy, angle))
37# sx: 1.20, sy: 1.50, angle: 20.00
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。