Denis Pătruț

【実験解説】簡易物理ベースのフィルム粒子シミュレーション

2025-07-12

元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像

概要

この記事はフィルムグレインのシミュレーション検証の解説となります。
サンプル画像、アルゴリズム解説、ソースコード、などが含まれています。

新しいメディアの奇妙・不細工・不愉快・醜悪と感じる部分がいずれその特徴となる・・・
― ブライアン・イーノ(Brian Eno)、 『A Year With Swollen Appendices』

フィルム写真は完璧かつ写実的な表現から程遠い。
20世紀の写真・動画の定番として、人類が今まで見てきた実写画像の大半がフィルムの結果によるもの。
その遺産は、ある種の聖杯として、現実から離れて映画や写真の世界に視聴者を引き込む、温かみのあるスタイライズされたメディアとして生き続けていると言えます。

デジタル画像をフィルム画像に見せるというのは以前から目指されてきたもので、ACESのトーンカーブがフィルムに似せるように設計されるほどです。
しかし色や明度をフィルムに似せる研究は多くされているというのに、フィルムの物理的な構造そのものをシミュレーション化することはどれほど研究されているのでしょうか?
フィルム粒子は実際に画像を作っている仕組みそのもので、少しでも検証する価値があるはずです。

Harman
Harman Phoenixという実験的なフィルムで、福岡市内撮影。
粒子の豊かさに注目。

「フィルムシミュレーション」というキャッチコピー

富士フィルム製のデジタルカメラには「フィルムシミュレーション」という機能が入っていて、実際の伝説なフィルムに基づいた懐かしい色を提供してくれます。(それで「Classic Chrome」だけは実際とあるK社の某フィルムだという噂も)

しかし「フィルムシミュレーション」と言われても、実際にどうでしょうか?
あくまで推測なんですが、おそらくカメラではLUTを適用するシンプルな仕組みで、グレインは予めに用意された粒子テクスチャを乗算させているだけなのかもしれない。1

富士フィルムの報告画像、
富士フィルムの報告画像、 こちらから。

これはもちろん富士フィルム様が手掛けたフィルムらしい色を出すLUT作成の労力を過小評価する目的ではございません!むしろとても完成度が高く、調整可能な設定が用意されてレシピとして保存して共有する仕組みまであるので、一部のLUT生成がデバイス上で行われているかもしれない。個人的にデジタルカメラでオンデバイスで創作的な色(リアルな色ではなく)をいろんな手法で用意されているというのは富士フィルム以外は中々ないんじゃないかと思います。レシピを共有し合うコミュニティも広く、編集ソフトで一枚一枚苦労することなくフィルムのスナップ写真と同じ感覚でカメラから直接出てくる開放感はものすごく評価されるべきかと思います。色がユニークで、魅力的で、そしてフィルムと同じように「ちょうどいい」と言えます。

論点はどちらかというと、これはシミュレーションなのかエミュレーションなのか?です。
実際LUTと粒子テクスチャの適用というのはフィルムの見た目を真似する仕組みで、どちらかというとエミュレーションに近いです。
逆にフィルムの物理特徴を用いて光xフィルムの反応の実際のシミュレーションを研究する価値があると思います。

フィルムのシミュレーションにどう手を出していくか考えるために、まずはフィルムの物理的な仕組みから見てみましょう。

フィルムの物理的な構造とは?

フィルムの一番大切な要素はまさに粒子です。
粒子は見た目的な現象ではなく、画像生成の主な物理的な仕組みなのです。

ピクセルよりグレイン

カメラのセンサーの仕組み、画像は
カメラのセンサーの仕組み、画像は こちらの記事から引用
顕微鏡で見た二種類のフィルム粒子、
顕微鏡で見た二種類のフィルム粒子、 画像はこちらの記事から引用。

デジタルカメラには均等に配置された小さなライトセンサーが入っています。
これらは画像データのデジタルピクセルと一致していて2、その一律性が画像に影響を与えています。
たとえばISO感度が高い場合は、暗いところにデジタルな「グレイン」的なノイズが見られますが、フィルム粒子とは雰囲気がかなり違います。ノイズ感がより強くて、画像の暗い部分が特に目立ちます。

フィルムでは、ハロゲン化銀結晶が細かく分散されています。
これは「粒子」と呼ばれるもので、現象ではなく実際に物理的な物を指しています。
光がフィルムにあたったら、一部の結晶に反応が発生します。光の強さによって反応する結晶の数が変わります。

粒子は二値

Photomicrograph
Photomicrograph of grain of different photographic plates

興味深いのは、フィルム粒子にはグレイスケールな明度が存在しないことです。
フィルムをとても近く見たら、実際は二値画像であることが見られます。
光によって有効化された粒子は現像段階では固定化されて、未反応の粒子は半透明になります。

ぼかし

しかし実際は二値画像から、明度に階調のある多値画像に、どんな現象で変換されるのだろう?
それは単純に、粒子はとても小さいがため、ぼかされて見えて段階的な明度に見えるのです。

とある論文に遭遇・・・

この実験のきっかけは、完成度が高くとても興味深い論文です:A Stochastic Film Grain Model for Resolution-Independent Rendering (A Newson, Julie Delon, B Galerne)。

この論文の主なポイントは:

簡略化実験: サンプル

論文より大きく簡略化したアルゴリズムで実装されたツールに通した画像のサンプルです。
手法の解説は下記をご覧ください。

元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像The
フィルム粒子シミュレーションによって描画された画像
The noise texture tiling is noticeable in the very even colour of the sky.
元の画像
元の画像
フィルム粒子シミュレーションによって描画された画像
フィルム粒子シミュレーションによって描画された画像

アルゴリズム解説

全体的なアイデア(二値粒子で画像を再構築しぼかす手法)は元の論文に基づいています。
簡略化されたのは、粒子配置はその場で計算せずテクスチャで用意するところです。
このように簡略化したら、実装しやすくなりますしある程度はリアルタイムにもなります。コンピュートシェーダーで実装されているのですが、ピクセルシェーダーでも実装で十分です。

論文と大きく違う点は、明度が入力画像に合わせようとしないところです。
さらに言えば、ネットから拾ったノイズテクスチャを使用して全く対策していないのです。
ということは、コントラストのカーブが場合によって大きく変わってしまい制御が独立していません。
製品化するには、コントラストが粒子適用で変わらず個別に制御できる、という仕組みにすることがおそらく重要になってくるのでしょう。しかし逆に、実験的な視点からはあらゆるノイズテクスチャでどのように反応するか観測することが興味深いと言えます。

ブルーノイズのテクスチャ

実際に使用されたブルーノイズのテクスチャです。
実際に使用されたブルーノイズのテクスチャです。

使われたのがクリストファー・ピーターズさんのとても素敵なブログ記事で無料配布されているブルーノイズのテクスチャです。
この場合は、8ビット色で4チャンネルの512x512解像度のLDR_RGBA_0.pngが使われています。
もしかしてHDRノイズテクスチャで16-bitのRAW画像の明度範囲がより保たれるのかもしれない、検証する価値があります。

ほとんどのテクスチャを使用した手法と違って、ノイズの適用方法は乗算ではないことです。ピクセル明度によってステップ(ディゾルブ)されるのです。
これがこの手法のキーポイントとなります。入力画像を 調整 して粒状性を高めるのではなく、入力画像を二値画像として 再構築される のです。

テクスチャを一回そのまま適用するだけではただのディザー画像っぽいのが出てくるだけで、最終結果ではないのです。
粒子をもっと小さくしフィルターをかけるのが次の段階です。

ピクセル細分化&ぼかし

ピクセル値
ピクセル値
ノイズテクスチャの一部をサンプリング
ノイズテクスチャの一部をサンプリング
ピクセル値が二値粒子として描画された結果。8x8の細分化。
ピクセル値が二値粒子として描画された結果。8x8の細分化。

各ピクセルはグリッド(2x2 〜 8x8)に細分化され、ノイズテクスチャの一部をサンプリングします。
ノイズ値はピクセル値でステップ化され、実質的にノイズを「ディゾルブ」させて二値画像になります。

その後、サブピクセル粒子が平均化されてピクセル値に戻されます。
ノイズテクスチャはサブピクセルのタイルより大きく、全体的にタイリングされるグレインとなります。

カラーテクスチャの場合は、チャンネルごとに行われます。
同じノイズテクスチャが使用されますが、カラー写真がランダムすぎる見た目にならないように、わずかにオフセットされます。

レイヤー

レイヤー無しグラデーションの細部がより失われて、高コントラスト
レイヤー無し
グラデーションの細部がより失われて、高コントラスト
レイヤー有り細部がより保たれる
レイヤー有り
細部がより保たれる
レイヤー無しズームイン
レイヤー無し
ズームイン
レイヤー有りズームイン
レイヤー有り
ズームイン

フィルムの層の中の粒子結晶は実際立体的に配置されています。
要は粒子は重なり合っているのです。
これをシミュレートするために、複数のノイズテクスチャを重ねることにしました。

ノイズテクスチャの後続のレイヤーは、上のレイヤーが光の一部をブロックすることをシミュレートするために、ステップ値が徐々に減少されます。
最終的な計算式は次のようになります: grain += step(noise_layer[i], value * weight[i])
利便性とパフォーマンスのために、ノイズテクスチャはそれぞれのRGBAチャンネルに4つのノイズを持たせています。

フィルム種類によっては、多層のグレインは光感度が異なる場合があり、グレインサイズが異なることを意味します(遅いグレインはより細かく、速いグレインはより粗く)。
これは、レイヤーごとにテクスチャ解像度を変えるとか、再現できる方法がいつかありそうです。

ブルーノイズ(等間隔)を重ねることで、純粋にランダムなホワイトノイズではないものの、フィルムグレインが持つ塊状のようなものが少し再現できます。

ベースカラー

ベースカラーのエミュレーション無し
ベースカラーのエミュレーション無し
ベースカラーのエミュレーション有り
ベースカラーのエミュレーション有り

現像済みのフィルムは、粒状結晶に影響を与えなかった低い露出の部分では完全に透明になっています。3
とはいえ、カラーネガフィルムは通常、染料が塗布されていて、ベースカラーがあります。
カラーフィルム独自の色合いの雰囲気は、印刷・スキャンでベースカラーが少し残ることが原因の一つだと考えられます。

この実験は色ではなく粒子に関するものとはいえ、ベースカラーを再現する簡易なエミュレーションを入れてみました。
ブラックポイントを若干青い色(ネガのオレンジの逆)に変えてるだけの単純なものですが。
実際ベースカラーは印刷の紙やスキャン設定でなるべく除外される仕様にはなっているのですが、現代はこれをさほど意識されなかったスキャンがSNSなどでよく見かけるようになっていて、少し強めなベースカラーを入れてあげると期待されているフィルム・ルックに近づけることができます。

ソースコード

この手法はもともと開発中のRAW画像編集プロジェクトの中で検証していたのですが、参考のために関連している部分を最低限のC言語のプログラムに集約させておきました。是非ご覧ください。

このプログラムは素敵なSDL3のGPU APIを活用して全計算をGPUで行っています。シェーダーはHLSLでVulkanバックエンド用にSPIR-Vに変換されています。
バイナリもあるし、コンパイルされたシェーダーコードもリポジトリにあるので手元にDXCがなくてもコンパイルできます。
(現代Macは手元になくてHLSLをMSLにクロスコンパイルする方法も把握していないので、Mac版はありません)

リポジトリは GitHub上のkanzwataru/filmgrain-simplifiedです。

結論&NEXT STEPS

元画像
元画像
1x1粒子
1x1粒子
2x2粒子
2x2粒子
3x3粒子
3x3粒子
4x4粒子
4x4粒子

シンプルな手法が、一回り複雑な論文に基づいて、今後も拡張の余地があります。
ノイズテクスチャを変えたり、レイヤー方法を改善したり、バイアスを様々かけたり、HDRノイズ活用したり、次のレベルに持っていく方法はいくらでもあります。
さらに言うとSDFテクスチャを粒子の形状として使ってみたら、少しもとの論文にも近づけてしまうかもしれません。

全体的に、この手法は「フィルム粒子を乗せる」というより画像を粒子として再構築するを目指しています。この違いはポイントになります、なぜならよりシミュレーションに近い物になるため。
ピクセルデータがカメラに入ってくる光で、シミュレートされた粒子がフィルムの反応、というモデルです。

この解説記事が役に立つと幸いで、ソースコードも是非ご覧ください!

後書き: なぜ機械学習の出番がなかったのか?

画像に特定の「スタイル」を適用するのが機械学習デモの中心と以前から流行っていて熱意がどんどん増えてきています。
ただしコンテンツ制作に使用するツールとしては、予測可能性と細かく調整できる柔軟な制御が最も大事なのでしょう。

機械学習は幅が広く、著作権で守られている大量の画像に依存せずに様々な手法を適用する機会が多いかと思います。
スタイル・トランスファー手法は既存画像を何千もの消費したブラックボックスに画像を改造してもらうような物で、もっと違う機械学習の活用方法が見てみたいです。

強調したい点というのは、フィルムの既存出力の真似( エミュレーション )というより、細かく調整可能なフィルムモデルの シミュレーション を探求する価値があるということです。
物理的なフィルムが物理現象によって画像を出力させてきた同様に、「デジタル・フィルム」的な物があれば既存フィルム画像の見た目に縛られずに次世代の画像作りに繋がるのかもしれません。
これを実装する方法は(機械学習を含めて)なんでもいい。

参照


  1. こちらのグレインに関する記事からしたら、特に複雑な実装ではなさそうです。グレインのテクスチャがあって、適用(おそらく乗算)されます。さらなる情報はこちらのページをご覧ください。 

  2. 厳密にいうと、デジカメのセンサーはピクセルと一対一な関係ではありません。 センサーのRAW出力では各”ピクセル”は色チャンネルが一つしかなく、その配置はカメラによって異なります。ほとんどの場合はGチャンネルが他の色より二倍あったり、標準RGBのピクセルにそのままマッピングすることが難しいです。センサー配置からRGBピクセルを再構築することは「デモザイク」といいます。こちらの論文(Efficient, High-Quality Bayer Demosaic Filtering on GPUs)もしくはこちらの日本語の記事で詳しく解説されています。 

  3. 実際フィルムは透明な部分がたくさんあります。粒子が無い部分はすべてそうです。一箇所に有効化された粒子の数がフィルムの密度といいます。