今を去ること半世紀以上前、中学の幾何の先生が「アフィン変換」なる言葉をつぶやいた強烈な記憶アリ。しかしその時もその後も理解できたような気もせぬままに生きてきた老人です。さて今回手習ひしてみるのはアフィン変換です。画像を平行移動、回転、拡大縮小、せん断変形させるものです。変換関数だけでなく、眷属どもが意外と便利。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※Windows11上の Scilab2024.0.0およびScilab上のScilab IPCVツールボックスを使用させていただいております。
アフィン変換
今回練習してみる関数どもは以下の3つです。
-
- imtransform
- imgettransform
- warpmatselect
Helpページ上では、アフィン変換が前面に押し出されている感じですが、実際には透視変換(perspective transformation)も処理可能みたいです。
上の「掛けてから足す」素のアフィン変換よりも、下の同次座標を使った「掛けるだけ」の表現の方があとあとご利益あるみたいです。数学素人の老人がブツクサいうのも何なので、『CVMLエキスパートガイド』様の以下のページなどご覧くだされや。
同次座標系 (homogeneous coordinates)
画像のアフィン変換 (Affine Transformation)
さて、上で列挙した関数どもの概要は以下のような感じです。
-
- imtransform、画像にアフィン変換、透視変換を適用した画像を求める
- imgettransform、対応する座標位置から、アフィン行列、透視行列を求める
- warpmatselect、画像上、インタラクティブに位置を指定、座標を得る
つまりimtransformを使って画像にアフィン変換かけられるのですが、変換かけるためにはアフィン行列(上の表現でいうと a b c d e fという係数ども)が必要。実際にアフィン行列を計算する一つの方法として変換前と変換後の座標から計算するのが imgettransform。画像上、座標を得るための対話的ツールがwarpmatselectであるようです。なお、この手の幾何変換をワープと呼ぶこともあるみたい。知らんけど。
warpmatselect
実際にwarpmatselect関数を使って、画像上の座標を求めたところが以下に。
imgettransform
Helpファイルに掲載されている座標を使って、アフィン行列、透視行列を計算しているところが以下に。
数学的なアフィン行列は、上記の行列表現の3行目のキメウチの00 1を除いて2行x3列で表現されるのが普通みたいです。しかし、ここでの結果は転置されているみたい(ベクトルは縦ベクトルでなく横ベクトルの方が書きやすいから転置されている方が便利なのかね?)
実際、平行移動の場合のアフィン行列をもとめてみると
src = [0 0; 10 10; 10 0]; tgt = [33 33; 43 43; 43 33]; mat = imgettransform(src,tgt,'affine')
imtransform
Helpファイルに掲載されている処理例をチョイ変したものが以下に。
S = imread(fullpath(getIPCVpath() + "/images/measure_gray.jpg")); src = [261 412; 170 348; 213 282]; tgt = [175 412; 170 308; 251 308]; mat = imgettransform(src,tgt,'affine') S2 = imtransform(S,mat,'affine'); scf(0); clf; subplot(121); title('Original'); imshow(S); subplot(122); title('Affine'); imshow(S2);
アフィン変換できたみたい。