Rubyで動画を造ろう

実験のために大量の単純な動画が必要になった。Flashなどで一つ一つ丁寧に作るという手はもちろんあった。今考えてみればそれほど時間はかからなかったかも知れないが、最近はもっぱらプログラミングに没頭する日々が多いせいかそういう単純労働をやる気になれない。やれやれ。どうしよう。多少恥ずかしい気分に襲われた。昔、僕ってMaxの名人と言われたことがなかったっけ?MaxとJitterなら出来ると言えば出来る。Maxを使いたいかというと、ふむ、まあ、特に使いたいと思わないのが本音だ。コードを書きたい。いや、コードを書くのが今の自分にとって自然なんだ。

ということで、Rubyでモーショングラッフィクス的な動画が作れないかと挑戦してみた。

この挑戦にとりあえず必要なツールは2つ。まず、描画はRCairoで行う。RCairoはCairoライブラリーのRubyバインディングだ。CairoはIllustratorなどのようにベクトル・グラフィックが描けるかなりパワフルなライブラリーだが、Rubyist Magazineにて日本語の紹介記事が読める。RCairoを使えば、静止画が簡単に書き出せるが動画は無理だから、RCairoで描いた絵をなんとか動画に変換する必要がある。いろいろ試した結果、結局短い動画ならフレームを1つ1つ画像ファイルに出力し、FFmpegでその画像たちを動画に仕上げるという戦略を選んだ。一見面倒な手法に見えるかも知れない。でも意外と楽で、画像を書き出した後、FFmpegでいろいろと圧縮設定を変えたりして動画を手軽に書き直すことができる。

では、まずFFmpegを入手する。便利なツールだからこんなプロジェクト以外にも役立つ。入手方法はいろいろあるが、OSXならHomebrewを使った方がおすすめ。

Homebrewそのもののインストール。ターミナルで以下のコマンドを実行する:

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

そしてHomebrewの初期処理を行う:

brew doctor

FFmpegをインストールする:

brew install ffmpeg

最後にRCairoもインストールする:

gem install cairo

それで下準備ができた。早速コードを書こう。とりあえず簡単な絵の画像を書き出してみよう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'cairo'
 
width = 1280
height = 720
pixel_format = Cairo::FORMAT_ARGB32
 
surface = Cairo::ImageSurface.new(pixel_format, width, height)
context = Cairo::Context.new(surface)
 
context.set_source_rgb(0,0.1,0.333)
context.rectangle(0,0,width,height)
context.fill()
 
surface.write_to_png("test.png")

上記のスクリプトを実行すれば… おおおおお!こんな奇麗が画像が出来上がった。

test

すばらしい。すばらしい。でも大したことはやっていない。Cairoで描画する前にサーフェイス(面)とコンテキストが必要。絵画で例えるとサーフェイスがキャンバスでコンテキストが筆だ。基本的にコンテキストを通して描画を行う。行7でサーフェイスを作る。その際、ピクセルのフォーマットと画像の幅と高さを指定する。ここで使うピクセルフォーマットは32ビットのRGBA(各チャンネルは8ビット)。

次はいよいよ描画だ。Contextのset_source_rgbメソッドで色を指定する。アルファチャンネルを使用するならset_source_rgbaを使う。ここは奇麗なブルーにする。次の行は長方形を描くように見える。しかし、長方形が描かれるのは次の行のcontext.fill()だ。そう。Illustratorを使っている人なら基礎中の基礎だが、ベクトル絵には「塗り」と「線」がある。英語では塗りのことを「fill」といい、線は「stroke」だ。つまり、ここで長方形を塗るという指示を出している。最後にサーフェイスのwrite_to_pngメソッドでPNGファイルを出力する。

では、何かを動かそう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
require 'cairo'
 
width = 1280
height = 720
pixel_format = Cairo::FORMAT_ARGB32
 
surface = Cairo::ImageSurface.new(pixel_format, width, height)
context = Cairo::Context.new(surface)
 
15.times do |frame_no|
	y = height * 0.5 + height * 0.4 * Math::sin(2 * Math::PI * frame_no.to_f / 15.0)
 
	context.set_source_rgb(0,0.1,0.333)
	context.rectangle(0,0,width,height)
	context.fill()
 
	context.set_source_rgb(1,1,1)
	context.arc(width * 0.5, y, 35, 0, 2 * Math::PI)
	context.fill()
 
	Dir.mkdir("cache") unless File.exists?("cache")
	surface.write_to_png("cache/img#{frame_no}.png")
end

ちょっと長くなったが、最初のプログラムと大して変わったことはやっていない。大きな違いは1枚ではなく15枚もの画像を出力していることだ。そして、下記のコードで白い正円を描いている。

context.set_source_rgb(1,1,1)
context.arc(width * 0.5, y, 35, 0, 2 * Math::PI)
context.fill()

context.arcで正円を描く場合、x座標、y座標、半径を渡してからさらに弧の開始角度と終了角度が必要。円なら、0から2πにする。y座標はサイン派に乗って上下する。

y = height * 0.5 + height * 0.4 * Math::sin(2 * Math::PI * frame_no.to_f / 15.0)

「cache」フォルダーがなければ作ってから15枚の画像をそこに保存する。

Dir.mkdir("cache") unless File.exists?("cache")
surface.write_to_png("cache/img#{frame_no}.png")

後一歩。

FFmpegを使えば、その画像から動画が簡単に作れる。一旦Rubyをやめてターミナルに戻る。

ffmpeg -r 29.97 -i cache/img%d.png -vcodec mpeg4 -b:v 2M ball.mp4

「cache」フォルダーにあるimg<フレーム番号>.pngという形式のファイル名を持つ画像を入力にする。しかし、画像にはフレームレートがないので、読み込み前に「-r 29.97」でフレームレートを指定する。出力のフォーマットを「mpeg4」にして、「-b:v 2M」でビットレートを2 Mbpsにして「ball.mp4」に動画を保存する。こんな感じになる(ブラウザーによって再生できない場合がある):

いいじゃないか。でもターミナルに戻るのはやはり面倒だ。運良く、Rubyで上記のコマンドが簡単に実行できる。おまけに、途中に生成したファイルを削除することもできる。でも冒頭に書いた通り、残すとターミナルで圧縮設定を変えて動画を書き直すことができる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
require 'cairo'
 
width = 1280
height = 720
pixel_format = Cairo::FORMAT_ARGB32
 
surface = Cairo::ImageSurface.new(pixel_format, width, height)
context = Cairo::Context.new(surface)
 
15.times do |frame_no|
	y = height * 0.5 + height * 0.4 * Math::sin(2 * Math::PI * frame_no.to_f / 15.0)
 
	context.set_source_rgb(0,0.1,0.333)
	context.rectangle(0,0,width,height)
	context.fill()
 
	context.set_source_rgb(1,1,1)
	context.arc(width * 0.5, y, 35, 0, 2 * Math::PI)
	context.fill()
 
	Dir.mkdir("cache") unless File.exists?("cache")
	surface.write_to_png("cache/img#{frame_no}.png")
end
 
`ffmpeg -r 29.97 -i cache/img%d.png -vcodec mpeg4 -b:v 2M ball.mp4`
`rm -rf cache`

究極につまらない動画だが、同じ方法で究極に格好いいジェネレーティブ・アートも造れるので、一度試してみてください。

味の色色

先週、六本木のミッドタウンで開催されていた慶應義塾大学SFCキャンパスのOpen Research Forumへ行ってきました。いくつもの面白い研究の成果を拝見させてもらいました。そういう機会に出会うと自分の関心について考えさせられます。

メディアではないですが、一つ注目した研究は山形県産のコメ「つや姫」の味成分を分析した後藤元氏担当の研究でした。つや姫は他の品種とどう違うか科学的に検証する研究です。「キャピラリー電気泳動?質量分析計」という機械を使ってアミノ酸など味に影響がある成分の分布を調べたそうです。

とても興味深い研究ですが、「味」はそもそもなんだろうと思ってしまいます。英語では「taste」と「flavour」、二つの単語がありますが、専門文献ではその意味がはっきりと違います。「Taste」とは、舌の刺激によって感じる5つの基本味:甘味、酸味、塩味、苦味とうま味です。それに対して「flavour」は「嗅覚、味覚、三叉神経による触覚の複雑な組み合わせで、触感、熱、痛みや深部感覚に影響されます」。それは私の定義ではありません。国際標準化機構(ISO)によるものです。ISOがこんなところまで手を伸ばしていますね。英語だらけの文章を読むのは面倒ですから、tasteを「味覚」、flavourを「風味」と訳しましょう。

重要なのは、味覚と風味を切り離せないことです。風味は当然、味覚に大きく依存しています。もう一方で、味覚は必ずほかの刺激と合わせて感じます。その組み合わせこそが風味です。その組み合わせを構成する要素はISOの定義で挙げられるもの以外にも沢山あります。実は、視覚も聴覚も記憶も期待も注意もすべて風味に影響を及ぼします。その感覚が「風味に影響を及ぼす」と言ってしまえば、「風味の一部」と言うのと同じです。

我々の「五感」は常に情報を共有しています。極端な場合、音によってないものを見てしまうこともありますし、見ることによって同じ音が別の音に聞こえることもあります。しかし、風味ほどその情報の共有が豊かな体験はないでしょう。風味はまさに五感を結束させる体験です。

McGurk効果:一回目顔をじっと見て声を聞いてください。2回目は目を閉じて聞いてください。音が変わるはずです。

2001年にフランスの研究者が57人のソムリエ学校の学生を集め、白ワインと赤ワインを用意してそれぞれのワインの香りを説明するように指示しました。学生たちが書いた文章を分析してよく使われた単語を調べました。その結果、赤ワインの香りはチコリー、炭、牡丹、プルーン、ブルーベリー、ラズベリーなどいかに赤ワインらしい単語が多かったそうです。白ワインは蜂蜜、レモン、グレープフルーツ、藁、バナナ、レイシなど。白ワインですね。しかし、「赤ワイン」なんてなかったのが落ちです。両方とも同じ白ワインでした。「赤ワイン」には無臭の着色料が入っていただけです。気づく被験者は一人もいませんでした。

(c) rogersmj

この結果についてどう考えればよいでしょうか。「やっぱり、ソムリエだってワインが全然分からない」と思う人も多いでしょう。全く別の(有名な)実験ですが、以下の映像を見て白いTシャツを着ている人が何回ボールをパスしたかを数えてみてください。

難しいからよくボールを追わないと…

最後まで見るとこの実験にも落ちがあることが分かります。何かに対して注意を払うと視覚でも騙すことができます。それでも、「やっぱり、ボールを見ている人だってなにも見ていない」なんて誰も思わないでしょう。

実は、色が香りと風味、狭義の味覚まで影響します。その働きはまだ議論が続いてはっきり分かりませんが、いくつかの仮説があります。まず、色は意識する以前に風味の知覚を変える説です。このような働きは聴覚と視覚の間に発見されました。上でリンクしたMcGurk効果では、クオリア(知覚の意識)を変える「完全キャプチャ」もあれば、判断を一瞬混乱させたり、違和感を感じさせたりする「不完全キャプチャ」があります。この類の効果は「ボトムアップ」と呼ばれることがあります。低レベルの処理が高レベルの意識に影響するからです。

違和感を感じますか?

それに対して、色と風味の影響は意識など、より高レベルの機能で起きているのではないかという説もあります。ボール投げの実験のように、何かに注意すると別のものに全く気付かないことがあります。赤い液体をみれば、匂いを嗅ぐ前にすでに赤ワインらしい匂いを想像してしまって、その匂いを探します。人間の嗅覚はそもそも非常に鈍感なので、雲など曖昧な形を見て動物を探せば見えてくると同じく、牡丹の香りを探せば、白ワインで見つかります。プラセボ効果も同じですね。薬だと思えば、偽薬でも一時効果がでます。我々の期待は脳と体の意外と深いところまで波紋が広がります。

おそらく、ボトムアップとトップダウンの働きが両方存在するでしょう。しかし、実験で区別させるのは非常に難しいので、解明されていないことがまだ多いです。
「味」は総合的に考えないと意味がないというのは過言ではありません。食べ物の成分は全体像の重要な一部になりますが、「成分の知識」の影響が成分そのものの影響よりも影響が大きいかも知れません。ある食材にうまみ成分が沢山含まれていると聞いた時、無意識にもうま味により深く注意を払ってその味に敏感になります。味の成分研究は味を解明するだけでなく、味を変えるかも知れません。
The Color of Odors
http://www.stanford.edu/class/linguist62n/morrot01colorofodors.pdf
Does Food Color Influence Taste and Flavor Perception in Humans?
http://psy.fgu.edu.tw/web/wlchou/perceptual_psychology/class_pdf/Advanced%20Perceptual/2011/2011week4_ChengChung_paper.pdf