射影変換(とその一部であるアフィン変換)は直線が直線になる変
換ですから、魚眼レンズの変換や逆変換には使えませんよ。ごく一
部なら近似できるかもしれませんが。
で、まずは教科書的に。
広角を含む普通のレンズは、視野の一部を視点からDだけ離れた平
面に投影します。これに対して魚眼レンズは、まず視点を中心とし
た半径rの球面に視野全体を投影して、次にその投影した結果を平
面に垂直に投影しなおすものです。
# ただし、本物のレンズが完全にこの数学モデルどおりに働いてい
# るかどうかは、レンズの設計にもよると思うのでわかりません。
さて、この原理がわかれば、魚眼レンズと普通のレンズの間の変換
をするための式を立てることができます。
普通のレンズの画像で中心からLだけ離れた点と、魚眼レンズの画
像の中心からlだけ離れた点が対応しているとします。そうすると、
l/r = L/sqrt(D^2+L^2)
になります。つまり、
l = rL/sqrt(D^2+L^2)
ですね。同じように、普通の画像上の点P(X,Y)と魚眼の画像
上の点p(x,y)を対応させると、
x = rX/sqrt(D^2+X^2+Y^2)
y = rY/sqrt(D^2+X^2+Y^2)
となります。これは、普通→魚眼の座標変換式ですが、画像の逆変
換には逆変換の式を作るのではなく、この式をそのまま使います。
なぜなら、逆変換後の座標(X,Y)の画素の値は、逆変換前の座標
(x,y)の画素の値になるわけですから、プログラム上は(X,Y)をぐる
ぐる回して、(x,y)を求めて、その位置の値を(X,Y)の値とすればい
いからです。
プログラムを書くなら、
for (X=0;X<W;X++) {
for (Y=0;Y<H;Y++) {
x = r*(X-W/2)/sqrt(D*D+(X-W/2)*(X-W/2)+(Y-H/2)*(Y-H/2)) + w/2;
y = r*(Y-H/2)/sqrt(D*D+(X-W/2)*(X-W/2)+(Y-H/2)*(Y-H/2)) + h/2;
if (x >= 0 && x < w && y >= 0 && y < h) {
futsuu[X][Y] = gyogan[x][y];
} else {
futsuu[X][Y] = black; /* or white or any */
}
}
}
て感じでしょうか。W,H, w,h は、それぞれの画像の幅と高さです。
ただし、x, y が画像の範囲をはみ出していないかチェックする必
要があります。
また、画質をよくするためには適当な補間法を適用します。補間法
については、
http://oshiete1.goo.ne.jp/kotaeru.php3?q=15511
で答えているので参考にしてください。
rには魚眼の画像の半径を設定します。
D/rが中心付近の倍率になります。
お礼
ご回答ありがとうございます。 うっ。た、確かに・・ レンズを通した画像は、すべて行列変換ですよね。 (基本でした) ってことは、魚眼レンズの変換用行列(パラメータ)を 実測(か、計算)して、フィルタを作らなくちゃいけないんですね。 ん~、見えてきたような気がします。 また、3DGameの方面は、よく知らなかったので、 調べてみることにします。 URLは、NotFoundでしたけど、 たぶんDirectX6(?)のような気がするので DirectX8とOpenGL関係も見てみます。 ありがとうございました~