円錐アナモルフォーズは,原画を極座標で表すとき偏角を一定の比率で縮小したもので,変換した絵を円錐の側面に貼り付けて円錐の軸方向(無限遠方)から見たとき,元画像となるものです。
プログラム例
元画像を配列に保持しておきます。描画領域の各画素についてその点に移される元の点の座標を求め(逆変換),それに対応する元画像の色を配列から取得して変換先の点の色を決定しています。
120行の定数alphaで円錐の頂角を指定します。
100 OPTION ARITHMETIC NATIVE 120 LET alpha=1/2*PI ! 円錐の頂角 130 SET COLOR MODE "NATIVE" ! 24ビットの色(true color)が使えるようにする。 140 GLOAD "zenkouji.jpg" ! 元画像(BMP,GIF,JPEGが指定可能) 150 ASK PIXEL SIZE (1,0;0,1)a,b ! 図の縦横の長さ(ピクセル単位)を調べる 160 DIM c(a,b) ! 図の大きさに対応する配列要素を用意する。 170 ASK PIXEL ARRAY (0,1) c ! 図の各点の色情報を配列に格納する。 180 ! c(1,1)に左上端,c(a,b)に右下端の画素が入る。 190 CLEAR ! 図を消去 200 SET bitmap SIZE 801, 801 ! ウィンドウの大きさを変更 210 SET WINDOW -400,400,-400,400 ! 座標系を再設定 220 SET POINT STYLE 1 230 FOR y=-400 TO 400 240 FOR x=-400 TO 400 250 LET r=SQR(x^2+y^2)*SIN(alpha/2) 260 IF r<>0 THEN LET t=ANGLE(x,y)/SIN(alpha/2) 270 IF ABS(t)<=PI THEN 280 LET i=ROUND(1/2 + a/2 + r*COS(t), 0) ! 左端 1, 右端 a 290 LET j=ROUND(1/2 + b/2 - r*SIN(t), 0) ! 上端 1,下端 b 300 IF 1<=i AND i<=a AND 1<=j AND j<=b THEN 310 SET POINT COLOR c(i,j) 320 PLOT POINTS:x,y 330 END IF 340 END IF 350 NEXT x 360 NEXT y 370 END
次のプログラムは頂角60°専用です。円錐の切り口を-90°の位置においています。
100 OPTION ARITHMETIC NATIVE 130 SET COLOR MODE "NATIVE" 140 GLOAD "tokeidai.JPG" 150 ASK PIXEL SIZE (1,0;0,1)a,b 160 DIM c(a,b) 170 ASK PIXEL ARRAY (0,1) c 180 ! c(1,1)に左上端,c(a,b)に右下端の画素が入る。 190 CLEAR 200 SET bitmap SIZE 801, 801 210 SET WINDOW -400,400,-400,400 220 SET POINT STYLE 1 230 FOR y=0 TO 400 240 FOR x=-400 TO 400 250 LET r=SQR(x^2+y^2)/2 260 IF r<>0 THEN LET t=ANGLE(x,y)*2-PI/2 280 LET i=ROUND(1/2 + a/2 + r*COS(t), 0) ! 左端 1, 右端 a 290 LET j=ROUND(1/2 + b/2 - r*SIN(t), 0) ! 上端 1,下端 b 300 IF 1<=i AND i<=a AND 1<=j AND j<=b THEN 310 SET POINT COLOR c(i,j) 320 PLOT POINTS:x,y 330 END IF 350 NEXT x 360 NEXT y 370 END
元画像(1/2倍) 変換後(1/2倍に縮小)
元画像は,こちらからいただきました。
円筒アナモルフォーズは,おおまかにいうと,原画の垂直方向を極座標の動径に,原画の水平方向を極座標の偏角に置き換えて描画したもので,変換した絵を円筒形の鏡に写すと元の絵が現れます。ただし,それぞれを単純に線形で変換したのでは正しい絵になりません。
極座標が(r,θ)の点Pから出た光が半径r0の円筒の側面で反射して,x軸上,原点からdだけ離れた視点に届くものとします。このとき,入射角・反射角をα,入射光が動径OPとなす角をψ,反射光がx軸となす角をφとすると,
2つの三角形に関する内角と外角の関係から,2α=θ+ψ+φ,
正弦定理から,
r:r0:r'=sinα:sinψ:sin(α−ψ)
d:r0:d'=sinα:sinφ:sin(α−φ)
の関係が成立して,
sinψ=(r0/r)sinα
sinφ=(r0/d)sinα
これらの関係を利用して,r,θからφを求めます。
d,rが大きいときはα=θ/2の近似が成立するので,このαからψ,φを求め,このψ,φからαを求めて,再度,ψ,φを計算すればよい近似値が得られるはずです。
次に示すプログラムでは,直前に計算した点のψ,φを近似計算の初期値に利用することで近似計算のための繰り返し回数を低減しています(410〜450行)。
また,r',d'から反射点の鉛直方向の位置が定まります。
なお,θ,r',d'は,プログラムでは,それぞれ,t,rr,ddと記述しています。
プログラム例
元画像の指定は120行です。
視点の高さ,視点から円筒までの距離を170行,180行で指定します。
230行,240行,250行の定数width,height,topは完成画像が収まるように調整して
ください。
円筒の半径は220行で設定します。末尾の定数1.00を1より小さくする場合は,下部
マージン(190行のm)を変更しないと画像の一部が欠けます。
虚像は円筒の最前端から円筒の半径のk倍だけ後方にできると仮定しています。この
仮定が実際に成立するのは円筒の最前端から円筒の半径のe倍だけ手前の点に対して
のみです。eの値を200行で定めています。kの値はeの値から導かれます(210行)。eの
値は人間の知覚に関係するので,実験的に適切な値を探してください。
100 OPTION ARITHMETIC NATIVE 110 SET COLOR MODE "NATIVE" 120 GLOAD "tokeidai.JPG" ! 元画像 130 ASK PIXEL SIZE (0,0; 1,1) a,b 140 DIM c(a,b) 150 ASK PIXEL ARRAY (0,1) c ! 元画像の色情報を配列に取り込む 160 CLEAR 170 LET h = b * 5 ! 視点の高さ 180 LET d = h * 1.2 ! 円筒から視点までの水平距離 190 LET m = 0 ! 下部マージン(画像の下部に履かせる下駄) 200 LET e=((b+m)/a)*(d/h)*2.0 ! 正しい虚像に写る点の位置(鏡面の前方,半径に対する比率) 210 LET k=1/(2+1/e) ! 虚像を生成する位置(鏡面の前端から後方,半径に対する比率) 220 LET r0 =SQR(1/(2*k-k^2))*(a/2)*1.00 ! 円筒の半径 230 LET width=1200 ! 描画域の幅(大きめに確保) 240 LET height=900 ! 描画域の高さ(大きめに確保) 250 LET top=200 ! 円柱の中心を置く位置 260 SET BITMAP SIZE width+1,height+1 270 LET bottom=-height+top 280 SET WINDOW -width/2, width/2, bottom , top 290 DRAW grid(100,100) 300 DRAW circle WITH SCALE(r0) ! 円筒 305 PLOT POINTS: 0, -r0*(1*e) ! 正しい虚像に写る点 310 LET d2=d-r0+r0*k ! 虚像面までの距離 320 SET POINT STYLE 1 330 FOR x=-width/2 TO width/2 340 LET phi=0 350 LET psi=0 360 FOR y=bottom TO top 370 LET r=SQR(x^2+y^2) ! 描画する点の絶対値 380 IF r>r0 THEN 390 LET t=ANGLE(x,y) +PI/2 400 IF t>PI THEN LET t=t-2*PI ! 描画する点の偏角(-π〜π)下向きが0 410 FOR i=1 TO 2 420 LET alpha=(t+psi+phi)/2 430 LET phi=ASIN(r0*SIN(alpha)/d) 440 LET psi=ASIN(r0*SIN(alpha)/r) 450 NEXT i 460 IF ABS(alpha)<=PI/2 THEN 470 WHEN EXCEPTION IN 480 LET rr=r*SIN(alpha-psi)/SIN(alpha) 490 LET dd=d*SIN(alpha-phi)/SIN(alpha) 500 USE 510 LET rr=r-r0 520 LET dd=d-r0 530 END WHEN 540 LET y0=h/(1+dd/rr) 550 LET x0=d2*TAN(phi) ! 元画像のx座標 560 LET y0=h-d2*(h-y0)/(d-r0*COS(alpha-phi)) ! 元画像のy座標 570 LET i=ROUND(x0+ (a+1)/2,0) ! x0に対応する配列添字 580 LET j=b-ROUND(y0-m) ! y0に対応する配列添字 590 IF i>0 AND i<=a AND j>0 AND j<=b THEN 600 SET POINT COLOR c(i,j) 610 PLOT POINTS : x,y 620 END IF 630 END if 640 END if 650 NEXT y 660 NEXT x 670 END
元画像(1/4倍)
変換後(1/4倍)
変換後の図は,260行を
260 SET BITMAP SIZE width/4+1,height/4+1
に変え,290行,320行のFOR文に STEP 4 を追加して描いたものです。
使い方
完成した歪絵は,MS-Wordなどに貼り付け,円筒の大きさが実際に用いる円筒鏡と同じになるように拡大・縮小して印刷してください。