ここでは、アフィン変換についてまとめています。
アフィン変換とは?
Wikipedia では、以下のように説明されています。
アフィン変換とは、線型変換(回転、拡大縮小、剪断(せん断))と平行移動の組み合わせである。
いくつかの線型変換の組合せは一つの線型変換として得られる。
なんのこっちゃ・・・って感じですよね(笑)
分かり易くするために、アフィン変換の簡単な例を以下の図に示します。
画像の拡大縮小、回転、平行移動などを「行列」を使って変換することをアフィン変換と呼びます。
x,y座標の2次元データをアフィン変換するには、変換前の座標を(x, y)、変換後の座標を(x', y')とすると、
回転や剪断変形用の 2行2列の行列と、平行移動用に 2行1列の行列を使って、次の式で表現されます。
この式は行列の項とベクトルの項に分かれていますが、線形変換を行列だけにまとめて表現することもできます。
拡大縮小、回転、剪断変形、平行移動を1つの3x3の行列にまとめると次のようになります。
この表現を同次座標系と言います。
同次座標系の3行目は無駄なようにも見えるのですが、この意味の無いような1行を追加する事で、
平行移動も同じ行列の積で表現できます。
また、逆行列を使う事で、アフィン変換後の座標からアフィン変換前の座標も求める事ができるようになります。
OpenCV では、この変換行列を定義してアフィン変換を行います。
それでは実際に Python を使ってアフィン変換を行ってみましょう。
ここでは最も簡単な画像の平行移動と回転を紹介いたします。
OpenCV でアフィン変換:平行移動
OpenCV でアフィン変換の平行移動を行う場合は、
warpAffine(<元画像データ>, <変換行列>, <サイズ>) 関数を使用します。
元画像データは、これまで通りの numpy 配列で指定し、
変換行列は同次座標系を使用します。今回は平行移動ですので、tx と ty を指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import cv2 import numpy as np img = cv2.imread("src/sample.jpg") h, w = img.shape[:2] dx, dy = 30, 30 afn_mat = np.float32([[1, 0, dx], [0, 1, dy]]) img_afn = cv2.warpAffine(img, afn_mat, (w, h)) cv2.imshow("trans", img_afn) cv2.waitKey(0) cv2.destroyAllWindows() |
- 1~2行目:必要なパッケージを読み込みます
- 4行目:元画像を読み込んでいます
- 5行目:元画像のサイズ(高さ、幅)を取得しています
- 6行目:平行移動させる画素数を指定しています。ここでは x軸で30画素、y軸で30画素移動させます
- 8行目:同次座標系の行列を定義します。今回は回転させないので、a,d=1、b,c=0 とします
- 9行目:OpenCV の warpAffine() を使って平行移動させます
- 11~13行目:平行移動した画像を表示させます
ポイント
同次座標系の行列(マトリクス)は、numpy を使って作成します。
参考
画像の表示(11~13行目)については、「画像の表示と保存」にまとめています。
OpenCV でアフィン変換:回転
次に、OpenCV を使って画像を回転させる方法を紹介いたします。
回転を行う場合も warpAffine() 関数を使いますが、与える行列の作成に
getRotationMatrix2D(<中心座標>, <回転角度>, <スケール>) を使用します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import cv2 import numpy as np img = cv2.imread("src/sample.jpg") h, w = img.shape[:2] rot_mat = cv2.getRotationMatrix2D((w/2, h/2), 40, 1) img_afn = cv2.warpAffine(img, rot_mat, (w, h)) cv2.imshow("rotation", img_afn) cv2.waitKey(0) cv2.destroyAllWindows() |
- 1~5行目は、平行移動の説明と同じです
- 7行目:getRotationMatrix2D() を使って、回転用の行列を生成します
中心座標は画像の幅・高さの半分、回転角度は40度、スケールは 1 (変更なし)を指定 - 8行目以降も、平行移動の説明と同じです
ポイント
回転角度を正の数で指定した場合、「反時計回り」の回転となります。
まとめ
OpenCV を使ってアフィン変換を行うには、以下の2ステップで完結します。
- 同次座標系で使用する行列を作成
- warpAffine() 関数に元画像データと行列を引数に渡して呼出す