読者です 読者をやめる 読者になる 読者になる

デジタル・デザイン・ラボラトリーな日々

アラフィフプログラマーが数学と物理を基礎からやり直す

射影変換(ホモグラフィ)について理解してみる その8

今まで射影変換するにしても、入力画像より小さくする方向しかパラメータを変更してませんでしたが、いざ、大きくしようとすると画像の位置が取れないために例外エラーになってしまいましたので、これを修正していきます。
また、入力画像の表示位置を原点(0,0)としていましたが、これも自由な位置に表示するようにしていきます。


■射影変換する際は左上を原点
画像を回転する上で、回転する点を回転中心座標が原点と一致するように点を移動させて回転移動後に元の位置に戻すのと同じく、射影変換では左上位置を原点と一致するように移動させ、射影変換後に元の位置に戻します。

例えば、画像の表示位置(offset)を左上(100,100)したとします。射影変換パラメータを求める上では画像データは左上(0,0)を基点としてデータを読む込む必要がありますので、左上を原点(0,0)にするように移動させます。

for (var i = 0; i < markers.length; i++) {
    markers[i][0] = marks[i].x - offset.x;
    markers[i][1] = marks[i].y - offset.y;
}

■画像サイズを求める
4角の点(アンカー)を自由に変形させた場合、画像データを生成する(createImageData)のサイズは、4点のいずれかの最大値 - 最小値となりますので、それを求めます。

var minX = 0.0, minY = 0.0;
var maxX = 0.0, maxY = 0.0;
for (var i = 0; i < markers.length; i++) {
    var x = markers[i][0];
    var y = markers[i][1];
    if (x > maxX) maxX = x;
    if (y > maxY) maxY = y;
    if (x < minX) minX = x;
    if (y < minY) minY = y;
}
var w = maxX - minX;
var h = maxY - minY;

■左上を原点に戻す
最小値を求まったら、最小値を左上の原点(0,0)に移動します。
これにより出力点の左上を原点(0,0)とすることができます。

for (var i = 0; i < markers.length; i++) {
    markers[i][0] -= minX;
    markers[i][1] -= minY;
}

■描画処理
描画処理に求めた画像サイズ(w,h)をパラメータとして渡します。
また、射影変換後の画像出力位置(sx,sy)として、画像の表示位置(offset) + 最小値をパラメータとして渡します。

draw(inv_param, offset.x + minX, offset.y + minY, w, h);

function draw(param, sx, sy, w, h) {
    var ctx = this.context;
    var imgW = this.image.width;
    var imgH = this.image.height;

    var output = ctx.createImageData(w, h);
    for(var i = 0; i < h; ++i){
        for(var j = 0; j < w; ++j){
            var tmp = j * param[6] + i * param[7] + param[8];
            var tmpX = (j * param[0] + i * param[1] + param[2]) / tmp;
            var tmpY = (j * param[3] + i * param[4] + param[5]) / tmp;
            var floorX = tmpX | 0;
            var floorY = tmpY | 0;

            if (floorX >= 0 && floorX < imgW && floorY >= 0 && floorY < imgH) {
                var pixelData = this.getPixel(texture.imageData, floorX, floorY);
                var R = pixelData.R;
                var G = pixelData.G;
                var B = pixelData.B;
                this.setPixel(output, j, i, R, G, B, 255);
            }
        }
    }
  //画像表示
    ctx.putImageData(output, sx, sy);
}

■表示結果
元サイズ
f:id:Yaju3D:20131007032644j:plain
4角の点(アンカー)を自由に変形して拡大
f:id:Yaju3D:20131007032705j:plain

次回は、画像補完の処理を加えた上でjsdo.itに投稿する予定です。