Polaroid Effect
開始日 | 2007年01月29日 |
最終更新日 | 2009年06月08日 |
はじめに
最近(2007/01/23くらいから?)、はてなダイアリーや色々な場所でで賑わっている「Polaroize」というWebサービスがあります。ローカルの画像を選択し[Upload]ボタンを押すだけで、ポラロイド写真風の画像が出来上がるというサイトです。
単一の目的に特化していて、余計な作業が要らないのがいいので個人的にも使わせてもらっています。
単一の目的に特化していて、余計な作業が要らないのがいいので個人的にも使わせてもらっています。
このサイトで使われている技術が気になったので調べてみたら、どうも「Polaroid Effect」と呼ばれているRubyスクリプトを(たぶん)使用していることが分かりました。
(2007/1/30追記。作者であるsecondlifeさんのブログでPolaroid Effectを参考にしていることがしっかりと書かれていました・・・読解力がなくてすみません)
(2007/1/30追記。作者であるsecondlifeさんのブログでPolaroid Effectを参考にしていることがしっかりと書かれていました・・・読解力がなくてすみません)
スクリプト自体も思っていたよりずっと少ないコード量で処理を実現していたのでビックリ。その驚きが冷める前に、説明サイトを(意)訳してみることにしました。
原著
「Polaroid Effect」
http://rmagick.rubyforge.org/Polaroid/polaroid.html
http://rmagick.rubyforge.org/Polaroid/polaroid.html
注意
- Polaroizeがこのソースを使っているかどうかは分かりません。実際、Polaroizeで生成された画像は少しボケが入っているようですし、使っていたとしてもよりリアルになるようなチューニングをしている可能性が高いです。
- もともと個人利用を目的として日本語化したために、けっこう意訳している部分があります。「意味分からないよ」とか「おかしいんじゃない?」とかいうのがあれば、オリジナルを参照するか、コメントで質問してください(がんばって調べます)。
- "Not bad for about a dozen methods, eh?"ってどういう意味なんだろう?
- 間違いや改善点をコメントしてもらえると、かなり嬉しいです。
- 画像のリンクを勝手にしてしまっているのですが、まずい場合には指摘してください。
更新履歴
- 2007/1/29 新規作成
- 2007/1/30 画像の位置を修正したり、細かい修正とか。あと、訳文に「末尾に完全なスクリプトを載せる」と書いておきながら載せてなかったので(汗)、追加しました。
- 2007/2/1 オリジナルのサイトをみたら(updated Jan 31, 2007)となっていたので、あわてて確認&修正。最後に「One more thing...」が追加されていて、何でもImageMagick 6.3.2以降ではPolaroid Effect自体がそのままサポートされるらしい・・・ってまじですか!?RMagickでは(機能拡張された上で)1.15.0からサポートされるらしい。あわせて訳の細かい見直し。
- "matte-pct"がアルファチャネルのことだと判明。ここに「the opacity (also called alpha, or matte) channel」と書いてあった。
- 2007/2/2 細かい部分を修正。ただ、自分が分かりやすくするために結構意訳している部分が気になってきました。公開している文章である以上、正確に原文を訳したほうが良いと思うので。今後は少しずつ原文に近い形に訳を戻していこうと思います。
- 2007/2/26 実機(Mac OSX10.3.9)上で現時点の最新版(IM6.3.2&RM1.15.2)を使って確認してみたところ、色々とサンプルどおりに動いていないことが分かったので、追記。
- 2008/3/17 ソースコードを引用記法ではなく専用のプラグインで記述するよう変更。だいぶ読みやすくなった。
訳文
古いポラロイドカメラがどのように動いていたかを覚えているだろうか?写真を撮ると印画紙が現像中の状態でカメラ後部から出てきていた。そしてしばらくしてから注意深く上を覆う膜をはがせば、「インスタントな」あなたの写真が姿を現していた。
出来たての写真はいつも少し反っていたから、反対側に優しくしならせて平らにしなければならなかった。
出来たての写真はいつも少し反っていたから、反対側に優しくしならせて平らにしなければならなかった。
このツカミ(*1)は、RMagickを使って古いポラロイドカメラ風の画像を作る方法を示している。Scott Kelbyは著書「The Photoshop Elements 4 Book for Digital Photographers」の中で、このようなエフェクトを「The Polaroid Effect」と名付け紹介していたが、同じことをしてみることにしよう。
以下はエフェクトを適用した一例だ。左側はオリジナルの画像で、右側はエフェクト適用後の画像だ。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
なお、これはRMagickのチュートリアルではないことに注意してほしい。私の(以前の記事の)ように、RMagickを使った画像の操作に慣れていることを前提としているからだ。
以降でこのスクリプトのポイントを実行順に紹介し、そのときどきでの中間イメージを掲載するつもりだ。ただし、トラフィック節約のためにも画像はすべてオリジナルの1/2のサイズで表示している。
以降でこのスクリプトのポイントを実行順に紹介し、そのときどきでの中間イメージを掲載するつもりだ。ただし、トラフィック節約のためにも画像はすべてオリジナルの1/2のサイズで表示している。
完全なスクリプトファイルは本書の末尾に置いておいた。
「フチ」の追加
require "RMagick"
if !ARGV[0]
puts "Usage: photo.rb path-to-image"
exit
end
image = Magick::Image.read(ARGV[0]).first
image.border!(18, 18, "#f0f0ff")
このスクリプトは、唯一の引数として画像ファイル名を受け取るプログラムだ。
さて、ポラロイド写真は常に周りが白い「フチ」で囲われていたので、borderメソッドで画像に「フチ」を付け加えよう。
borderメソッドには3つの引数が必要だ:
- 左右の「フチ」のサイズ
- 上下の「フチ」のサイズ
- 「フチ」の色
サイズはどれもピクセルで指定すること。例では上下左右共に18ピクセルで指定している。なぜ18ピクセルかって?72dpiの解像度で表示したときにちょうど18ピクセルは1/4インチになるよう狙っているからだ。だからプリンタなど別のデバイスを使用するような場合は、適当に調整してほしい。
「フチ」の色について、私は青みがかった白(*2)を選んだ。この色は私のDellのモニターではいい塩梅だが、Macだとちょっと眩しすぎるかもしれないな。あなたがPowerBookユーザーだったらこう言うだろうよ。「フチ?どこにあるんだい?(*3)」。
「フチ」の色について、私は青みがかった白(*2)を選んだ。この色は私のDellのモニターではいい塩梅だが、Macだとちょっと眩しすぎるかもしれないな。あなたがPowerBookユーザーだったらこう言うだろうよ。「フチ?どこにあるんだい?(*3)」。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
「反り」の追加
image.background_color = "none"
amplitude = image.columns * 0.01
wavelength = image.rows * 2
image.rotate!(90)
image = image.wave(amplitude, wavelength)
image.rotate!(-90)
次は、カメラから写真が出てきた直後のように画像を反らせる。
もちろん、画像を本当にしならせるわけじゃない。目の錯覚によるトリックをつかって、「反り」を表現しているんだ。
もちろん、画像を本当にしならせるわけじゃない。目の錯覚によるトリックをつかって、「反り」を表現しているんだ。
まずは左右にほんのわずかなカーブを与えよう。ここでは、サインカーブに沿って画像を歪ませるwaveメソッドを使って画像をカーブさせている。
ところでwaveメソッドではカーブに沿ってピクセルを移動するため、どうしても元の画像で存在しなかった部分に、新しいピクセルが追加されてしまう。デフォルトでは、新しいピクセルの色には背景色が使われるため、今回は"none"という透明なピクセルを背景色として設定する。
これはあとで行う、写真が落とす影を付けるためだよ。
(2007/2/26追記:実際にローカルで確認したところ、jpegファイルの場合は上記に加えて「image.opacity = 0」というように『透明度を取り扱います』というように宣言しないと黒地が見えてしまいます。0は適当な値でいいので、一度opacityを設定しておいてください)
これはあとで行う、写真が落とす影を付けるためだよ。
(2007/2/26追記:実際にローカルで確認したところ、jpegファイルの場合は上記に加えて「image.opacity = 0」というように『透明度を取り扱います』というように宣言しないと黒地が見えてしまいます。0は適当な値でいいので、一度opacityを設定しておいてください)
おっと、運が悪いことにwaveメソッドは上下方向にしか画像を変換できない。しかも私たちが必要なのは左右方向への変換だ。このことは物事を少しだけ難しくするけれど、画像を90°回転させてwaveメソッドを呼び、その後でまた90°回転させて元通りに戻せばいい。90°の回転は画像の情報を失わせることが無いので、何の問題も無いからだ。
waveメソッドには2つの引数が必要だ:
- amplitude(振幅。波の高さ)
- wavelength(波長。1周期の長さ(*4))
何回かの試行の末、私には振幅が1%の画像が一番「それっぽく」見えた。もちろんこれは私の芸術的センスによる判断なので、2.0%や2.5%がいいと思うんだったら、amplitudeの値を適当に変えてほしい。ただし、スムーズな「反り」にするには、wavelengthは必ず画像の高さの2倍ちょうどにすること。(*5)
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
「影」の作成
shadow = image.flop
shadow = shadow.colorize(1, 1, 1, "gray75")
shadow.background_color = "white"
shadow.border!(10, 10, "white")
shadow = shadow.blur_image(0, 3)
ポラロイド写真が下に落とす影を作るため、ここでは4つのメソッドを使う。
「反り」を完ペキに表現するためには、影を同じような形で、ただし逆向きに反るよような形状で作成することが必要だ。
そこで、まずはflopメソッドを呼んで画像を縦軸に対して反対にしている。
そこで、まずはflopメソッドを呼んで画像を縦軸に対して反対にしている。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
次にcolorizeメソッドを使って、画像の色全てをライトグレーに変える。
colorizeメソッドには4または5個の引数が必要だ(*6):
colorizeメソッドには4または5個の引数が必要だ(*6):
- R領域にブレンドする割合(0.0 - 1.0)
- G領域にブレンドする割合(0.0 - 1.0)
- B領域にブレンドする割合(0.0 - 1.0)
- アルファチャネルにブレンドする割合(オプション)
- ブレンドする色
色の指定には、直接指定以外にもMagick::Pixelオブジェクトも使える。
各引数はRGBそれぞれのチャネルに対して指定色をどのくらい混ぜるかをパーセントで指定する。今回は単色の影を作ることが目的なので、RGBすべてに1.0(=100%)を指定して「gray75」色に塗りつぶしている。なおcolorizeメソッドはアルファチャネルに影響を与えないため、オリジナルで透明だった部分はcolorize後の影でも透明のままだ。
各引数はRGBそれぞれのチャネルに対して指定色をどのくらい混ぜるかをパーセントで指定する。今回は単色の影を作ることが目的なので、RGBすべてに1.0(=100%)を指定して「gray75」色に塗りつぶしている。なおcolorizeメソッドはアルファチャネルに影響を与えないため、オリジナルで透明だった部分はcolorize後の影でも透明のままだ。
"gray75"はImageMagickが持つ名前付きパレットの1つだ。灰色用のパレットには100色用意されていて、"gray0"(黒)から"gray100"(白)まである。"gray50"はちょうど真ん中の灰色で、つまり今回の"gray75"は白と"gray50"の真ん中あたりの明度というわけだ。
ちなみにこれも私の芸術的センスによる判断なので、他の色・明度を使いたければ使うといい。
ちなみにこれも私の芸術的センスによる判断なので、他の色・明度を使いたければ使うといい。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
そして最後はblur_imageメソッドによって影をぼかそう。
blur_imageメソッドには2個の引数が必要だ:
- radius(直径)
- sigma(標準偏差σ)
影を作る場合、私はいつもradiusに0を渡している。もちろん、radiusが他のアプリケーションにとっては非常に重要なことは分かっているつもりだ。だけど今回のような影を作る場合には特に問題とならないからね。radiusを固定し、sigmaでぼかし具合を調整している。
なおsigmaが大きな値であるほど画像のぼけ量は大きくなるが、blur_imageの実行に時間がかかってしまうことには注意してほしい。
なおsigmaが大きな値であるほど画像のぼけ量は大きくなるが、blur_imageの実行に時間がかかってしまうことには注意してほしい。
今回はそれらしい影を得るためsigmaへ3を渡した。これも他と同様、主観的な判断だ。
あと、border!メソッドを呼んでいるのはblur_imageメソッドの結果がオリジナルの画像サイズよりもぼかしたぶんだけ大きなサイズの画像を返すため。白い枠をすこし加えることで、白い背景になじむ影を得ている。(訳注:ここはかなり原文を変更しています)
あと、border!メソッドを呼んでいるのはblur_imageメソッドの結果がオリジナルの画像サイズよりもぼかしたぶんだけ大きなサイズの画像を返すため。白い枠をすこし加えることで、白い背景になじむ影を得ている。(訳注:ここはかなり原文を変更しています)
ここでの一連の処理を行わせた結果が、下の画像だ。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
影と画像の合成
image = shadow.composite(image, -amplitude/2, 5,
Magick::OverCompositeOp)
これまでに私の書いた記事を読んだことがあれば、ここではそんなに驚く要素はないだろう。
ここで再度ポイントに挙げるべき点は第2,3引数だ。それっぽく合成するために、画像を影からわずかに左にずらし、そして影よりも5ピクセル上に配置している。
(正直に言うとこの設定には満足していない。影に対する画像の正確な配置場所は画像の縦横比に依存するだろうから。現在の設定はこれまでの試行による近似値であり、実際にはオフセット計算の良い方法があるはずだ。(が、私には表現できなかった))
(正直に言うとこの設定には満足していない。影に対する画像の正確な配置場所は画像の縦横比に依存するだろうから。現在の設定はこれまでの試行による近似値であり、実際にはオフセット計算の良い方法があるはずだ。(が、私には表現できなかった))
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
ちょっとした傾き
image.rotate!(-5)
image.trim!
out = ARGV[0].sub(/\./, "-print.")
puts "Writing #{out}"
image.write(out)
残る作業は-5°のイカシタ傾きとtrim!メソッドによるバリの排除だけだ。もう一度言うが、ここでの値も私の芸術的センスによる判断の結果だから、7.5°でも、4~8°のランダムな値でも好きにしたらいい。ただし、私もよく変更に対して「less is more(少ないことは、より豊かなこと)」と考えるが、今回はよしたほうがいい。ほんの少し傾けただけでは画像がずれて配置されているように見えてしまうから!
最後に、ファイル名+「-print」という名前でディスクに保存する。ここでは同じフォーマットで保存しているが、別のフォーマットで保存したければファイル拡張子を別のフォーマットのそれに変えればいい。暗黙のうちに変換してくれるからだ(*7)。ただしJPEGのような透過色をサポートしない形式の場合、出力は不透明な画像になることは覚えておいてほしい。
これが最終的な画像(フルサイズ)だ。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
まとめ
Not bad for about a dozen methods, eh?(*8)設定を色々と変えてみて、どういう結果になるかを試してみてほしい。こんな短いスクリプトでさえ、本当に色んな出力が得られるんだ。
この「Polaroid Effect」を作るに当たって、Anthony Thyssenにはお礼を言いたい。AnthonyはImageMagickのイカしたサンプルが多数紹介されているWebサイト「Examples of ImageMagick Usage」の管理者だ。Check it out!
One more thing... (原著で2007/1/31に追加)
ニュース!!
ImageMagickの開発者がこのチュートリアルを読んでくれて、何とPolaroid EffectをImageMagick自体に取り込むことを決めてくれた。ImageMagick6.3.2以降のリリースでサポートされるとのこと。
早速RMagickでも1.15.0からImage#polaroidメソッドを追加することにしたよ。さらに、polaroidメソッドでは写真の下にキャプションも追加できるようにした。
詳しくはこちらのドキュメントを見てくれ!
ImageMagickの開発者がこのチュートリアルを読んでくれて、何とPolaroid EffectをImageMagick自体に取り込むことを決めてくれた。ImageMagick6.3.2以降のリリースでサポートされるとのこと。
早速RMagickでも1.15.0からImage#polaroidメソッドを追加することにしたよ。さらに、polaroidメソッドでは写真の下にキャプションも追加できるようにした。
詳しくはこちらのドキュメントを見てくれ!
(訳者追記:参照先のドキュメントにある画像を転載します。こんな感じに仕上がるそうです。日本語はサポートされるんでしょうか?)
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
その他の例
「Polaroid Effect」によるその他のサンプルをここに置いておく。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
#ref error :画像を取得できませんでした。しばらく時間を置いてから再度お試しください。
polaroid.rbの完全なソース
(訳注:サイトのスペースの関係で、コメントを別行に書いたり行の途中で折り返したりしています。「オリジナルじゃなきゃいやだ!」という方はこちらから入手してください)
require "RMagick"
if !ARGV[0]
puts "Usage: polaroid.rb path-to-image"
exit
end
image = Magick::Image.read(ARGV[0]).first
image.border!(18, 18, "#f0f0ff")
# Bend the image
image.background_color = "none"
# vary according to taste
amplitude = image.columns * 0.01
wavelength = image.rows * 2
image.rotate!(90)
image = image.wave(amplitude, wavelength)
image.rotate!(-90)
# Make the shadow
shadow = image.flop
# shadow color can vary to taste
shadow = shadow.colorize(1, 1, 1, "gray75")
shadow.background_color = "white" # was "none"
shadow.border!(10, 10, "white")
# shadow blurriness can vary according to taste
shadow = shadow.blur_image(0, 3)
# Composite image over shadow.
# The y-axis adjustment can vary according to taste.
image = shadow.composite(image, -amplitude/2, 5,
Magick::OverCompositeOp)
# vary according to taste
image.rotate!(-5)
image.trim!
# Add -print to image basename, write to file.
out = ARGV[0].sub(/\./, "-print.")
puts "Writing #{out}"
image.write(out)
Tim - Sep 22, 2006 (updated Jan 31, 2007)
参考サイト(訳者による追加)
- Polaroize : http://lab.rails2u.com/polaroize/
- 原著:「Polaroid Effect -- http://rmagick.rubyforge.org/Polaroid/polaroid.html」
- RMagick : http://rmagick.rubyforge.org/Polaroid/polaroid.html
- RMagickオンラインドキュメント : http://www.simplesystems.org/RMagick/doc/index.html
- Examples of ImageMagick Usage : http://www.cit.gu.edu.au/~anthony/graphics/imagick6
( - )