アルゴリズムとデータ構造の可視化、“リッチ・ソースコード”について - Ushiroad
「JPEG Tilt」というページを公開しました。MotionJPEG Builder を作った時に、JPEG のヘッダを読み込む処理を作ったので(結局これは使わなかったんですが)圧縮データの読み込み部分も作ってみようか、という気になって作ったのがこれです。JPEG ファイルで画像が圧縮される様子を視覚的に表現する…… という目標だったのですが、どうでしょうか。まあ内容が内容なので説明無しではさすがに意味が分からないと思います。
ということで、JPEG Tilt の見方を以下で簡単に説明します。
図1は、JPEG Tilt の画面です。画像が iTunes の CoverFlow のように並んでいますが、これの左側は画像の低周波成分のみを抜き出した物で、右に行くとより高周波の成分も含めるように並んでいます(低周波、高周波という言葉の意味はこの先で出てきます)
画像の上にマウスカーソルを乗せると、丸いマーカーが打たれた表が出てきます。これは、DCT画像の係数を表したものです。 DCT とは、フーリエ変換と呼ばれる数学的なテクニックの一で、複雑な信号を単純なコサイン波の足しあわせに変換することですが、JPEG 圧縮における DCT は、図2のように任意の画像を縦横のグラデーションの足しあわせに変換する処理となります(このグラデーションがコサイン波から生成されています)。ここでグラデーションの繰り返しが少ないものを低周波成分、多いものを高周波成分といいます。グラデーションになっていない(波打っていない)ものは直流成分と呼ばれます。
黄色のジャケットに刺された場合にどうするか
図3はDCT係数表の例です。元画像において、犬の胸の部分は、上から下に向かって暗くなっています。そこで、縦のグラデーションに正の係数をかけ、横のグラデーションには0をかけて画像を合成します(実際はぴったり0ではないかもしれませんが)。表中では、正の係数は塗りつぶし有り、負の係数は塗りつぶし無しの丸で表現されており、負の係数をかけた場合はグラデーションの向きが逆になります。 さらに細かいグラデーション(高周波成分)を組み合わせていくと、精細な画像を合成できます。
さて、JPEG の最大の特徴は非可逆圧縮ですが、このDCT自体は可逆の処理で、そもそも圧縮ですらありません。非可逆圧縮を実現しているのはこの先のステップで、高周波成分の情報量を削る処理(量子化)をします。例えば普通、画像は256段階(8bit)で情報を持っていますが、これを2で割ると128段階(7bit)になり、16で割ると16段階(4bit)になります。するとDCTの逆変換(IDCT)で得られる画像が変色することになりますが、ドット単位で微妙に画像が変色しても人間の目を誤魔化せるだろう、という理屈です。
この圧縮の様子を表しているのが画像の下部にあるバー(図4)です。白いバーは明るさの成分について、青と赤は色の成分について、ピクセルあたり平均何ビットで表現されているかを示しています。バーが短ければ、情報量が大胆に削られていることになります。人間の目が細かい色の変化に鈍いという性質を利用し、高周波の色の成分を積極的に削っていることが、右端のバーが極端に短いことから読み取れます。
社会的な非難は何ですか
「よく現れるパターンを辞書化する」という単純な原理に基づいている PNG や GIF と違い、JPEG の非可逆圧縮は何やら魔術的な雰囲気がありますが、このように情報量を削っている様子を可視化すると、中で何が起きているか想像ができて身近に感じられるのではないでしょうか。
さて、私はコンピュータの中で起こっていることを絵にする、ということをこれまでにも幾度か試してきました。その多くは、プログラムを読むときに処理の内容を掴むために、自分のために作ったものです。そのうち出来の良かったものはいくつか公開しましたが、最も反響が大きかったものはブラウザのレイアウト計算の流れを可視化した動画です(図5)
Mozilla Firefoxのレイアウトエンジン(Gecko)では、HTML要素に対する視覚情報(要はモデルに対するビューです)を Frame というオブジェクトに保存しており、この Frame に位置・サイズがセットされる瞬間を捕まえてログを取ることでレイアウト計算の過程を追うことができます(尚、ここで言っているFrameは、HTMLでウェブページを分割する時に使うあのフレームとは全く関係ありません)。 WebKit は Frame ではなく Render と呼んでいますが同じような構造を持っており、同様のことができると思います。
人々は遺伝学について知っているため、なぜそれが重要である
次に、これも Mozilla Firefox に関連したものですが、Mozilla の描画バックエンドである cairo という 2D グラフィックスライブラリの内部で行われている「テセレーション」と呼ばれる処理の可視化を紹介します。コンピュータで複雑な図形を描く場合、簡単な図形の集合に分割して描画する実装を行うことが一般的で、この分割処理がテセレーションです。ここで分割に使う図形は、最も単純な図形である三角形とすることが多いのですが、cairo の場合はちょっと変わっていて台形を使います。cairo が実際に行ったテセレーション処理の結果を図6に示します。
細かな台形が集まってドーナツ型が形作られているのがわかります。私達が Firefox で canvas を使ったページを訪れた時は、この台形の集合を見ていることになります(……というのは正確には少し古い話で、今は cairo を経由せずに OS の描画 API を呼び出すよう設計が変更されています)
最後の例として、Liviz.js を紹介します。Liviz.js は GraphViz をブラウザ上でインタラクティブに使えるというものですが、おまけの機能として GraphViz がグラフのレイアウトを考える過程をアニメーションで表示することができます(機能上はおまけですが、実はこれを作った本来の目的はこれです)。図7に例を示します。
GraphViz はまず、ノードの縦方向の位置(Rankと呼ぶ)を決めます。同じ Rank を持つノード群は横方向に並ぶことになりますが、これらを左右で交換しながら、エッジが交差しない配置を探します。図7の(a)ではエッジが交差している箇所が1つありますが、(b)ではノードをいくつか入れ替えて交差を解消しています。
ここまで紹介したデモを作るために、元のコードをある程度改変したり、簡単なツールを作ったりしてきました。ただ、作成が大変な動画やインタラクティブ・デモはともかく、cairo の例のような一枚絵ぐらいであれば、元からソースコードのコメントあたりに埋め込まれていて欲しいというのは決して贅沢な願いではないと思います。世間では iPad やら iBooks で教科書革命だと騒いでいますが、その牽引役である開発者達がソースコードの上にアスキーアートでしょっぱい図を入れているのは滑稽な話です。技術や学術系の本に一枚も図が無かったら普通怒られます。
例えば、デバッガで実行途中の変数を指定してやると、それを絵にしてくれる。それがリスト構造であればグラフになって、図形のベクタデータであれば図形を描いてくれる。さらにステップ実行するとアニメーションを作ってくれる。いい絵ができたらソースコード中に埋め込んで、世界中のプログラマがコードと同時にそれを見られる。みたいなことが可能であれば有難いと思います(一応 ddd とかはありますが…)
とりとめのない話になりましたが、まとめると、英語を読みたくない(絵でくれ)ということです。
0 コメント:
コメントを投稿