2016/04/06(水) [n年前の日記]
#1 [gimp] GIMPのMathMapについて分かったことをメモ
GIMP(フリーで使える画像編集ツール)に追加できるプラグインの中に、MathMap というものがあって。簡単なスクリプトを書くとフィルタ処理ができるプラグインなのだけど。
_「MathMap」
_The MathMap Image Processing Application
その、MathMap用のスクリプトの書き方が、ちょっとだけ分かってきたのでメモ。
英語が読める人は、公式サイトのドキュメントを読んだほうが早いだろうけど。
_The MathMap Language Tutorial
_The MathMap Language Reference Manual
sin()、cos()、tan() に与える値は、単位が度なのかラジアンなのか、ちょっとよく分からず。 _The MathMap Language Reference Manual 内で、単位が明記されてる場所が見つからなくて。関数として、rad2deg() (ラジアンから度への変換)と、deg2rad() (度からラジアンへの変換)が用意されてるあたり、ラジアンを渡しそうな気もするのだけど…。
_「MathMap」
_The MathMap Image Processing Application
その、MathMap用のスクリプトの書き方が、ちょっとだけ分かってきたのでメモ。
英語が読める人は、公式サイトのドキュメントを読んだほうが早いだろうけど。
_The MathMap Language Tutorial
_The MathMap Language Reference Manual
◎ MathMapのタブの種類。 :
GIMPを起動して MathMap を開くと(フィルタ → 汎用 → MathMap)、プレビューウインドウの右に、5つのタブが並んでる。
とりあえず、Epressionタブの中でスクリプトを書いて、Save As... で保存して、次回使う時は Filtersタブから選ぶ、みたいな感じになるのだと思う。
スクリプトを保存すると、拡張子が .mm になって保存される。
Windows環境だと、保存した際に改行コードがおかしくなるっぽい。ちゃんと書けたはずなのに、saveボタンを押したら「parseできねーよ」とエラーが出たら、大体は改行コードが妙なことになってる。その場合は、別途エディタを使ってスクリプトを書いて、改行コードを LF にして保存して、MathMap で Load したほうがトラブルが起きにくいかもしれない。
- Expression ... スクリプトを書いていく場所。
- Setting ... MathMapの処理に関わってくるオプション指定。アンチエイリアスや、画像の端を繰り返す、等。
- User Values ... フィルタによっては入力パラメータを必要とするものがある。その入力項目が表示される場所。
- Filters ... 登録済みのフィルタ(MathMapのスクリプト)が並んでる。フィルタ名をクリックすると、スクリプトが Load されて、Expressionタブに開かれる。
- Composer ... 複数のフィルタを組み合わせて実行する際に使う。左側でフィルタ名をクリックすると右側に追加されて、フィルタの「out」から、別フィルタの「in」にドラッグすると、フィルタを組み合わせることができるらしい。
とりあえず、Epressionタブの中でスクリプトを書いて、Save As... で保存して、次回使う時は Filtersタブから選ぶ、みたいな感じになるのだと思う。
スクリプトを保存すると、拡張子が .mm になって保存される。
Windows環境だと、保存した際に改行コードがおかしくなるっぽい。ちゃんと書けたはずなのに、saveボタンを押したら「parseできねーよ」とエラーが出たら、大体は改行コードが妙なことになってる。その場合は、別途エディタを使ってスクリプトを書いて、改行コードを LF にして保存して、MathMap で Load したほうがトラブルが起きにくいかもしれない。
◎ スクリプトの基本。 :
画像に対するフィルタ処理のスクリプトは、以下のような感じ。
例えば、前述の in(xy:[x, y * 2]) で処理をした場合、y方向が半分になった画像が得られる。y を2倍してるのに、どうして半分に縮小されるのか、ちょっと分かりづらいだろうか…。
とりあえず、[x, y] のあたりを好きなように書き換えて、Preview を押してみればなんとなく分かってくるかも。
filter hogefugapiyo(image in) in(xy:[x, y * 2]) end
- filter フィルタ名(image in) 〜 end で、フィルタを定義。
- (image in) は、画像を入力して処理しますよ、という記述。
- in(xy:[x, y]) は、(x,y)座標の位置にドットを書く際、[x, y]の位置を参照せよ、てな関係を書いていく。
例えば、前述の in(xy:[x, y * 2]) で処理をした場合、y方向が半分になった画像が得られる。y を2倍してるのに、どうして半分に縮小されるのか、ちょっと分かりづらいだろうか…。
- y=2 の位置にドットを描くなら、y * 2 = 4 の位置からドットの色を拾ってきて描く。
- y=4 なら、y * 2 = 8 の位置から拾ってくる。
- y = 100 なら、 y * 2 = 200 の位置から拾ってくる。
とりあえず、[x, y] のあたりを好きなように書き換えて、Preview を押してみればなんとなく分かってくるかも。
◎ 座標系。 :
横が x軸、縦が y軸。画像の真ん中が(0,0)で、左下が (-1, -1)、右上が (+1, +1)、らしい。たぶん。
_The MathMap Language Tutorial に座標の解説図が載ってるので、ソレを見たほうが分かりやすいかも。
_The MathMap Language Tutorial に座標の解説図が載ってるので、ソレを見たほうが分かりやすいかも。
◎ 画像サイズの取得その他。 :
- 画像サイズは、大文字の「W」「H」で取得できる。W が画像の横幅。H が画像の縦幅。だと思う。たぶん。もっとも、画像サイズ(ドット数)に関わらず、x や y は -1.0 〜 +1.0 の値を取るはずなので、W も H も使わずに処理できる場合が多いかも。
- 円周率は pi と書く。
sin()、cos()、tan() に与える値は、単位が度なのかラジアンなのか、ちょっとよく分からず。 _The MathMap Language Reference Manual 内で、単位が明記されてる場所が見つからなくて。関数として、rad2deg() (ラジアンから度への変換)と、deg2rad() (度からラジアンへの変換)が用意されてるあたり、ラジアンを渡しそうな気もするのだけど…。
[ ツッコむ ]
#2 [cg_tools] Vue 5 Easelのパノラマ画像でまだ悩んでたり
Vue 5 Easel で、縦横の比率を変更しながらパノラマ画像をレンダリングして、それぞれ比較しながら眺めてたのだけど。
比率を変えても内容が変わらない・トリミングしてるに等しい状態だなと…。それと、1:1どころか、縦長の画像にしても、まだ天井と真下をレンダリングし切れてないあたりが気になるなと。
眺めてるうちに、もしかしてこの画像は、Central cylindrical projection (心射円筒図法) ではないのかと思えてきた。
_地図投影法 / 投影法カタログ / 心射円筒図法
_Cylindrical Projection - PanoTools.org Wiki
_Central cylindrical projection
_Cylindrical Projection -- from Wolfram MathWorld
上や下に行くにしたがって、メルカトル図法どころではなく、面積がグングン大きくなるうえに、天井と真下がレンダリングできてないあたり、どうもソレっぽい気がする…。心射円筒図法は、天井(+90度)と真下(-90度)を投影しようとしても、無限に遠いところに投影する羽目になっちゃうので表現できないわけで。
だとすれば、心射円筒図法から、正距円筒図法に変換することができれば、Vue 5 Easel で出力したパノラマ画像も、そこそこ使えたりするかもしれない、と。
_地図投影法 / 投影法カタログ / 正距円筒図法
_Equirectangular Projection - PanoTools.org Wiki
_Cylindrical Equidistant Projection -- from Wolfram MathWorld
_Equirectangular projection - Wikipedia, the free encyclopedia
てなわけで、GIMP の MathMap を使って、変換できないか試してたのだけど。これがどうも思った通りの結果にならない…。
比率を変えても内容が変わらない・トリミングしてるに等しい状態だなと…。それと、1:1どころか、縦長の画像にしても、まだ天井と真下をレンダリングし切れてないあたりが気になるなと。
眺めてるうちに、もしかしてこの画像は、Central cylindrical projection (心射円筒図法) ではないのかと思えてきた。
_地図投影法 / 投影法カタログ / 心射円筒図法
_Cylindrical Projection - PanoTools.org Wiki
_Central cylindrical projection
_Cylindrical Projection -- from Wolfram MathWorld
上や下に行くにしたがって、メルカトル図法どころではなく、面積がグングン大きくなるうえに、天井と真下がレンダリングできてないあたり、どうもソレっぽい気がする…。心射円筒図法は、天井(+90度)と真下(-90度)を投影しようとしても、無限に遠いところに投影する羽目になっちゃうので表現できないわけで。
だとすれば、心射円筒図法から、正距円筒図法に変換することができれば、Vue 5 Easel で出力したパノラマ画像も、そこそこ使えたりするかもしれない、と。
_地図投影法 / 投影法カタログ / 正距円筒図法
_Equirectangular Projection - PanoTools.org Wiki
_Cylindrical Equidistant Projection -- from Wolfram MathWorld
_Equirectangular projection - Wikipedia, the free encyclopedia
てなわけで、GIMP の MathMap を使って、変換できないか試してたのだけど。これがどうも思った通りの結果にならない…。
◎ 過程をメモ。 :
例えば、Vue から、24:36の比率で、1024x1536のパノラマ画像を得たとする。そして、コレは心射円筒図法だと仮定する。
横方向は球の円周と対応してるはずだから…。円周 2πr = 1024 dot。r = 1024 / 2π になるかなと。
心射円筒図法の場合、y = r * tanθ らしいから…。θ = atan(y / r)、かなと。
1:1の比率で、1024x1024のパノラマ画像を得た場合はどうなるだろう。atan( (1024 / 2) / (1024 / 2π)) = 72度ぐらい? つまり144度ぐらいはレンダリングしている、という状態になるのかな。
_GeoGebra で図を描いて確認してみた。
合ってるような気がする…。
コレを、GIMP の MathMap に反映させないと。
MathMap の場合、横方向の長さは、-1.0から+1.0になるのだから、横の長さは 2.0 ってことになるよなと。円周 2πr = 2、なのだから、r = 2 / 2π = 1/π になるのかな。
y も、-1.0 から +1.0 を取るわけだから…。正距円筒図法の場合、y = θ のはずなので、1.0 が 90度相当になるようにしないといけない。三角関数に与える値の単位がラジアンと仮定して、180度 = πラジアンなのだから、90度 = π/2 ラジアン。y値に π/2 を掛けてやれば、三角関数に与える値になりそう。
心射円筒図法の場合、y = r * tanθ だから…。MathMap では、in(xy:[x, (1 / pi) * tan(y * (pi / 2))])、になる?
そのままだと、縦に引き延ばされたような画像になってしまう。画像サイズを使って、縦方向に縮めてやらないといかん気がする。(H / W) を掛けてやればいいのかな。と思ったけど、コレをしちゃうと、ドットを拾ってくる y の位置が変わってくるから、ちゃんと変換できなくなる、のかな…。
面倒だから、縦方向の縮小は、MathMap でフィルタをかけた後、GIMP の「画像の拡大・縮小」でやってしまおう…。画像横幅の半分のサイズになるように、画像縦幅を指定して縮小すればいいはず。
とりあえず現時点では、MathMap用のスクリプトは以下のような感じに。
_cylindrical2equirectangular.mm
結果画像を比較。
一見すると上手くいったように見え…
あー。ダメだ。360度パノラマ画像のソレは、変換処理は上手くいってるっぽいけど、レンズフレアがとんでもない形になってる。コレ、元の画像が… Vue がレンダリングした時点でダメなんじゃないか?
それと、縦:横 = 1:1 になってないパノラマ画像を MathMap のソレで処理するとおかしなことになる。画像の比率に関係なく、y方向を -1.0 〜 +1.0 として処理してしまうから、だろうけど。補正しないと。
ちなみに「背景コンバータ」は、Cubemap用の6枚の画像から正距円筒図法の画像を生成できるツール。DoGA公式サイトの、 _背景コンバータ から入手できる。ありがたや。
横方向は球の円周と対応してるはずだから…。円周 2πr = 1024 dot。r = 1024 / 2π になるかなと。
心射円筒図法の場合、y = r * tanθ らしいから…。θ = atan(y / r)、かなと。
- y は、画像の縦幅 / 2 = 1536 / 2。
- r = 1024 / 2π。
1:1の比率で、1024x1024のパノラマ画像を得た場合はどうなるだろう。atan( (1024 / 2) / (1024 / 2π)) = 72度ぐらい? つまり144度ぐらいはレンダリングしている、という状態になるのかな。
_GeoGebra で図を描いて確認してみた。
合ってるような気がする…。
コレを、GIMP の MathMap に反映させないと。
MathMap の場合、横方向の長さは、-1.0から+1.0になるのだから、横の長さは 2.0 ってことになるよなと。円周 2πr = 2、なのだから、r = 2 / 2π = 1/π になるのかな。
y も、-1.0 から +1.0 を取るわけだから…。正距円筒図法の場合、y = θ のはずなので、1.0 が 90度相当になるようにしないといけない。三角関数に与える値の単位がラジアンと仮定して、180度 = πラジアンなのだから、90度 = π/2 ラジアン。y値に π/2 を掛けてやれば、三角関数に与える値になりそう。
心射円筒図法の場合、y = r * tanθ だから…。MathMap では、in(xy:[x, (1 / pi) * tan(y * (pi / 2))])、になる?
そのままだと、縦に引き延ばされたような画像になってしまう。画像サイズを使って、縦方向に縮めてやらないといかん気がする。(H / W) を掛けてやればいいのかな。と思ったけど、コレをしちゃうと、ドットを拾ってくる y の位置が変わってくるから、ちゃんと変換できなくなる、のかな…。
面倒だから、縦方向の縮小は、MathMap でフィルタをかけた後、GIMP の「画像の拡大・縮小」でやってしまおう…。画像横幅の半分のサイズになるように、画像縦幅を指定して縮小すればいいはず。
とりあえず現時点では、MathMap用のスクリプトは以下のような感じに。
_cylindrical2equirectangular.mm
# cylindrical to equirectangular filter cylindrical2equirectangular(image in) in(xy:[x, (1/pi)*tan(y*(pi/2))]) end
結果画像を比較。
- 6方向をレンダリングして、「背景コンバータ」で正距円筒図法の画像に変換したもの。
- 360度パノラマ画像(縦:横=1:1)を、GIMP + MathMap で変換、横:縦 = 2:1 に縮小したもの。
一見すると上手くいったように見え…
あー。ダメだ。360度パノラマ画像のソレは、変換処理は上手くいってるっぽいけど、レンズフレアがとんでもない形になってる。コレ、元の画像が… Vue がレンダリングした時点でダメなんじゃないか?
それと、縦:横 = 1:1 になってないパノラマ画像を MathMap のソレで処理するとおかしなことになる。画像の比率に関係なく、y方向を -1.0 〜 +1.0 として処理してしまうから、だろうけど。補正しないと。
ちなみに「背景コンバータ」は、Cubemap用の6枚の画像から正距円筒図法の画像を生成できるツール。DoGA公式サイトの、 _背景コンバータ から入手できる。ありがたや。
[ ツッコむ ]
以上、1 日分です。