1347662738 imagemagickで先日いろいろと教えて頂いた-fxオプションを使って、

添付のような魚眼加工ができないか試しているのですが、どうもうまくいきません。imagemagickでどのようなconvert文を実行すれば良いか教えてもらえないでしょうか?
また、計算式が複雑な場合、簡単な解説もつけて頂けると助かります。
何らかの中間画像が必要なのかもしれないですが・・・。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/09/15 07:45:38
  • 終了:2012/09/16 09:44:07

ベストアンサー

id:quintia No.3

quintia回答回数558ベストアンサー獲得回数672012/09/16 00:39:58

ポイント200pt

まず小手調べ、というか画像の確認。
画像の中心から短辺で接する円を変換対象にすることにします。

convert -fx "kk=w*0.5;ll=h*0.5;sr=min(kk, ll);dx=i-kk;dy=j-ll;rr=hypot(dx,dy);rr < sr ? p{dx+kk,dy+ll} : 0"  in out

変換式はこんな感じ。

convert -fx "kk=w*0.5;ll=h*0.5;sr=min(kk, ll);dx=i-kk;dy=j-ll;rr=hypot(dx,dy);pr=1-2*acos(rr/sr)/pi;px=(rr==0.0 ? 0.0 : pr*dx*sr/rr);py=(rr==0.0 ? 0.0 : pr*dy*sr/rr); rr < sr ? p{px+kk,py+ll} : 0" in out

計算……全部自分でやりました。
f:id:quintia:20120915222725j:image:medium

http://www.nikon-image.com/enjoy/interview/historynikkor/2000/0010/
正射影の説明はここで読みました

変換の感じをイメージするには、まず半円柱を使った射影を考えた方がいいのかなぁ、と思いました。
画像を半円柱にペッタリとくっつけたときに、変換先の画素から見て《真上》の変換元の画素を求めればよい、と。(左上の図)

これを半球に拡張すると、画像をペッタリと半球にくっつけることはできないので、極座標的な考え方をした方がよさそうです。

さて、画像の座標は左上が0,0です。これだと不便なので、画像の真ん中を0,0にした座標にして考えます。
これが計算中に出てくるdx,dyですね。
でも紙に書いていたときはまだxx,yyって書いてますね。実際の式ではdx,dyです。
あと紙とここの回答にrと書いているのは、実際の式でsrにしてます。
のちのち¥sqrt{dx^2+dy^2}は頻繁に出てくるので式ではrrに代入してます。

変換先の点(dx,dy)に射影される点をさがすのに、(dx,dy)から見て真上に射影した球面上の点と、半球面の中心、そして中心の直上の点を通る断面を考えます。
いや、z軸と点(dx,dy)を通る断面、と言った方がわかりやすいでしょうか。
点(dx,dy)の直上の球面上の点Sは(dx, dy, ¥sqrt{r^2-(dx^2+dy^2)})で表せます。(右上の図)

断面を持ってきます。(右側上から2番目)
cos¥theta=¥frac{¥sqrt{dx^2+dy^2}}{r}になりますから、
¥theta=acos(¥frac{¥sqrt{dx^2+dy^2}}{r})です。式中のacosがcosの逆関数acosです(ていうかtex記法でacosって書くとcos^(-1)の記号になる。なんでww)。

この4分円の弧を、ぐいっ、と引き延ばします。
¥frac{¥pi}{2}rの直線です。おっと、-fxで扱う角度がラジアンなのでここでもラジアンで書きますよ。
点Sの右側が¥theta rですので、左側は(¥frac{¥pi}{2}-¥theta)rです。

この線分を変換元画像に持ってきます。
左側を中心に、点(dx,dy)を通る角度での射影を考えます。長さは違うので同じ比で分割したときに点Sにあたる点を探します。(右下の円)
変換元画像の外周上の点は、(¥frac{dx}{¥sqrt{dx^2+dy^2}}r, ¥frac{dy}{¥sqrt{dx^2+dy^2}}r)です。
比率¥frac{(¥frac{¥pi}{2}-¥theta)r}{¥frac{¥pi}{2}r}=1-¥frac{2}{¥pi}¥thetaをかけることで変換元の対応する画素を計算しました。

原点(dx=0,dy=0)付近で0割りが発生するので、rr==0.0 かどうかをチェックしています。

id:MrB

完璧な回答ありがとうございました。
知りたいことがすべてかかれてました。
長らく数学をやってないと駄目ですね。
円周=2πr、180度=2πなどもすっかり忘れてました。
計算もありがとうございました。
また機会があればお願いします。

2012/09/16 09:41:53

その他の回答(2件)

id:oil999 No.1

oil999回答回数1728ベストアンサー獲得回数3202012/09/15 14:30:24

ポイント10pt

こんな感じでしょうか。

convert hoge.jpg -fx 'kk=w*0.5;ll=h*0.5;dx=(i-kk);dy=(j-ll);aa=atan2(dy,dx);rr=hypot(dy,dx);rs=rr*rr/hypot(kk,ll);px=kk+rs*cos(aa);py=ll+rs*sin(aa);p{px,py}'
id:MrB

回答ありがとうございます。
これが先日教えて頂いたものなのですが、画像が丸くならないので、どうしたら丸くなるかを知りたいと思っています。

2012/09/15 18:55:44
id:TransFreeBSD No.2

TransFreeBSD回答回数659ベストアンサー獲得回数2642012/09/15 15:33:59

ポイント30pt

先日の式は、描画点を一旦極座標系に変換し、描画点の距離rrを、「rs=rr*rr/hypot(kk,ll)」で読取点の距離rsに変換し、XY座標に戻す、ということをやっているようです。
さて、魚眼レンズへの変換ですが、原理については下記がわかりやすかったです。
http://odabouta.blog115.fc2.com/blog-entry-10.html
いくつかありますが、等距離射影の「r*θ」がわかりやすいのでこれを採用します。
あと、通常の写真にあたる透視投影がないのですが、これは焦点距離をrとすると「r*tanθ」になるかと思います。

いま、透視投影の写真から点を読取り、等距離投影で描画することを、極座標の距離についてのみ考えます。
読取点rsは透視投影ですので「rs=r1*tanθ」となります。
また、描画点rrは等距離投影ですので「rr=r2*θ」となり「θ=rr/r」となります。
したがって「rs=r1*tan(rr/r2)」が変換式になります。
f:id:TransFreeBSD:20120915153856j:image
さて、r1,r2について考えます。
「rs=r1*tanθ」より透視投影の元画像でθ=45°(視野角でいうと倍の90°)の時に「rs=r1」となります。
つまり視野角90°の半径に相当するピクセル数がr1になります。
この視野角90°(π/4)のときの描画半径が「rr=r2*(π/4)」となります。
このあたりは適当に調整してみることになるんじゃないでしょうか。

ちなみに、どうあがいても、元の画像は視野角が180°よりかなり狭いので、魚眼レンズ風にしても、周辺部分はカットするかごまかすことになると思います。

 

と、ここまで書いてあれですが、たぶんあっていると思う。

id:MrB

回答ありがとうございます。
頂いたURLの「正射影」を実現したいのですが、
具体的にどのような計算式で変換後の座標を
求めればいいかわからず苦戦しています。
x、y座標での計算式をお教えいただければ幸いです。

2012/09/15 19:00:50
id:MrB

質問者から

MrB2012/09/15 23:17:52

質問が分かりずらくて、すみません。
一番知りたいのは、
添付のbeforeからafterの画像を作る場合
imagemagickのconvertの-fxオプションで
どのように記述すれば良いかということです。

id:quintia No.3

quintia回答回数558ベストアンサー獲得回数672012/09/16 00:39:58ここでベストアンサー

ポイント200pt

まず小手調べ、というか画像の確認。
画像の中心から短辺で接する円を変換対象にすることにします。

convert -fx "kk=w*0.5;ll=h*0.5;sr=min(kk, ll);dx=i-kk;dy=j-ll;rr=hypot(dx,dy);rr < sr ? p{dx+kk,dy+ll} : 0"  in out

変換式はこんな感じ。

convert -fx "kk=w*0.5;ll=h*0.5;sr=min(kk, ll);dx=i-kk;dy=j-ll;rr=hypot(dx,dy);pr=1-2*acos(rr/sr)/pi;px=(rr==0.0 ? 0.0 : pr*dx*sr/rr);py=(rr==0.0 ? 0.0 : pr*dy*sr/rr); rr < sr ? p{px+kk,py+ll} : 0" in out

計算……全部自分でやりました。
f:id:quintia:20120915222725j:image:medium

http://www.nikon-image.com/enjoy/interview/historynikkor/2000/0010/
正射影の説明はここで読みました

変換の感じをイメージするには、まず半円柱を使った射影を考えた方がいいのかなぁ、と思いました。
画像を半円柱にペッタリとくっつけたときに、変換先の画素から見て《真上》の変換元の画素を求めればよい、と。(左上の図)

これを半球に拡張すると、画像をペッタリと半球にくっつけることはできないので、極座標的な考え方をした方がよさそうです。

さて、画像の座標は左上が0,0です。これだと不便なので、画像の真ん中を0,0にした座標にして考えます。
これが計算中に出てくるdx,dyですね。
でも紙に書いていたときはまだxx,yyって書いてますね。実際の式ではdx,dyです。
あと紙とここの回答にrと書いているのは、実際の式でsrにしてます。
のちのち¥sqrt{dx^2+dy^2}は頻繁に出てくるので式ではrrに代入してます。

変換先の点(dx,dy)に射影される点をさがすのに、(dx,dy)から見て真上に射影した球面上の点と、半球面の中心、そして中心の直上の点を通る断面を考えます。
いや、z軸と点(dx,dy)を通る断面、と言った方がわかりやすいでしょうか。
点(dx,dy)の直上の球面上の点Sは(dx, dy, ¥sqrt{r^2-(dx^2+dy^2)})で表せます。(右上の図)

断面を持ってきます。(右側上から2番目)
cos¥theta=¥frac{¥sqrt{dx^2+dy^2}}{r}になりますから、
¥theta=acos(¥frac{¥sqrt{dx^2+dy^2}}{r})です。式中のacosがcosの逆関数acosです(ていうかtex記法でacosって書くとcos^(-1)の記号になる。なんでww)。

この4分円の弧を、ぐいっ、と引き延ばします。
¥frac{¥pi}{2}rの直線です。おっと、-fxで扱う角度がラジアンなのでここでもラジアンで書きますよ。
点Sの右側が¥theta rですので、左側は(¥frac{¥pi}{2}-¥theta)rです。

この線分を変換元画像に持ってきます。
左側を中心に、点(dx,dy)を通る角度での射影を考えます。長さは違うので同じ比で分割したときに点Sにあたる点を探します。(右下の円)
変換元画像の外周上の点は、(¥frac{dx}{¥sqrt{dx^2+dy^2}}r, ¥frac{dy}{¥sqrt{dx^2+dy^2}}r)です。
比率¥frac{(¥frac{¥pi}{2}-¥theta)r}{¥frac{¥pi}{2}r}=1-¥frac{2}{¥pi}¥thetaをかけることで変換元の対応する画素を計算しました。

原点(dx=0,dy=0)付近で0割りが発生するので、rr==0.0 かどうかをチェックしています。

id:MrB

完璧な回答ありがとうございました。
知りたいことがすべてかかれてました。
長らく数学をやってないと駄目ですね。
円周=2πr、180度=2πなどもすっかり忘れてました。
計算もありがとうございました。
また機会があればお願いします。

2012/09/16 09:41:53
  • id:TransFreeBSD
    >画像を半円柱にペッタリとくっつけたとき
    それすると等距離投影が混じってくる気がします。
    元は透視投影なのでタンジェントで変換すると
    http://www.wolframalpha.com/input/?i=tan%28Pi%2F2-acos%280.8x%29%29%2Ftan%28Pi%2F2-acos%280.8%29%29%2C+x+from+0+to1
    となる気がします。で、これは下記と等価です。
    http://www.wolframalpha.com/input/?i=0.6x%2Fsqrt%281-0.64x%5E2%29%2C+x+from+0+to+1
    実際の式で書くと
    pr=1-2*acos(rr/sr)/pi

    pr=0.6/sqrt(1-0.64*(rr/ll)^2)
    になるかと。
    0.64は0.8^2、0.6はsqrt(1-0.8^2)で、0.8は半周180度に対する画角の比にあたります。

    ただ、実際は写した段階で周辺部に歪みが出ているので細かい所は気にしなくてもいいのかもしれません。
    あと、本当は2次方程式に近似してやるとimagemagicの機能でもっと効率よく計算出来るのかもしれません。
    ただ、その辺は良く分かってないのでポインタだけ...
    http://www.imagemagick.org/Usage/lens/
    元はレンズによる歪みを補正する機能だと思うけど、うまく使えば逆変換できるんじゃないかと。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません