affineCopyのピクセルの扱い
なぜ affineCopy がズレて描画され、なぜ出力座標を -0.5 するとズレなくなるのか。
ヒントは affineCopy の仕様にある。
仕様の確認
吉里吉里のマニュアルには次のように書かれている。
affineCopy アフィン変換においては、ピクセルは 1.0 × 1.0 のサイズを持っていると見なされます。 つまり、(0, 0) の位置にあるピクセルは (-0.5, -0.5) – (0.5, 0.5) の範囲にあると見なされます。 |
一般的には、整数座標上で (0, 0) のピクセルは、
実数座標上では (0.0, 0.0) – (1.0, 1.0) の範囲を覆っていると見なすのが普通である。
それに対して、-0.5 ずれた範囲を覆っているものとして扱われると書かれている。
なるほど -0.5 というあたりからして、ズレの原因はこれっぽいが
(-0.5, -0.5) – (0.5, 0.5) の範囲にあると見なされるとは、
いったいどういう意味だろうか。
入力領域の扱い
まずこの仕様が関係してくるのが
”affine=trueの時に出力領域の計算をする際の入力領域の扱い”
である。
affine=true の時、入力領域全体を -0.5 移動させてから、
アフィン変換行列による変形計算を行い、出力領域が決定される。
これがどういうことかは、次のようにしてみるとわかる。
var x = 50;
var y = 50;
primaryLayer.affineCopy(image, 0, 0, w, h
, true, 100, 0, 0, 100, x, y, stNearest);
画像を(50, 50)の位置に100倍に拡大して描画しているが、
左上に大きくズレこんで描画されてしまっている。
これは (-0.5, -0.5) – (0.5, 0.5) の範囲にあるとみなされる入力ピクセルが100倍になり
(-50.0, -50.0) – (50.0, 50.0) の範囲に出力されているからである。
この仕様は正直、あまり直感的ではなく扱いづらく思える。
ちょっと不思議な仕様だ。
affine=true 時のズレ
affineCopy を affine=true で使い、画像を無変形で描画する時
出力座標を -0.5 しなくても描画はズレないように見える。
しかし実は affine=true の場合でも、ズレ自体は起きている。
ではなぜズレがないように見えるのか。
先の仕様を思い出して欲しい。
入力領域全体を -0.5 移動させて、それを出力領域にするということは…
出力領域全体を -0.5 移動させることと同義である。
そう、先の仕様によってズレが補正されているのだ。
ただしこれが同義なのは無変形の場合だけであることに注意が必要だ。
画像を変形させると隠れ潜んでいたズレが姿を現す。
ここでのまとめ
affine=true 時のズレを補正するのは不可能ではないが、ちょっと難しい。
入力座標を +0.5 し、出力座標を -0.5 すれば
仕様を打ち消し、ズレもなくせそうな気がするが…
affineCopy は入力座標に整数しか指定できないため、それはできない。
行列計算で補正する必要がある。
厳密にズレを補正しようと思うなら、affine=false にして
出力座標計算は自力で行った方が簡単だろう。
つづく!