約束ではなく、計測
パフォーマンス
このページの数字はすべて、ごく普通のノートパソコン(Apple M3、16 GB)で本物の写真から計測したもので、それを出すスクリプトはリポジトリにあるので誰でも再実行できます。各グラフの下にはプリントにとっての意味を、最後には数字の裏にある用語の説明を載せています。
Fotollectionが速い理由
魔法はありません。最初のコードを書く前に決めたいくつかの方針と、そのすべての計測です。
すべてのコアでネイティブコード
Fotollectionの処理はRustで動き、あなたのプロセッサー向けにコンパイルされてすべてのコアに分散され、プロセッサーがピクセル処理のために持つベクトル命令(SIMD)を使います。1,2,3
23.5 / 秒16 MPでの写真の書き出し
必要なものだけ
フォルダーを開くときは、各ファイルのEXIFと小さな埋め込みサムネールだけを読み、写真全体は読みません。サムネールはディスクのキャッシュに保存されます。4
0.12秒1,000枚の写真を開く
画面より多いピクセルは扱わない
プレビューは最大1600 pxで、メモリに保持した2048 pxのコピーから作ります。写真全体は拡大したときだけ、部分ごとに読み込みます。
17 msプレビューの再描画
クリックする前に準備完了
サムネールができると、すべての写真のプレビューをバックグラウンドで作ってディスクに保存し、メモリの4分の1で画面上の写真の前後を保持します。
27 msどの写真を開くのも
同じものを二度作らない
カラースライダーは色だけを変え、サイズは変えません。すべてのカラースライダーは33 × 33 × 33色のテーブルひとつにまとめられるので、スライダー10本でも1本と同じコストです。
2 msプレビュー上のカラースライダー10本
予算内のメモリ
Fotollectionが同時に扱うフルサイズの写真は、メモリ予算が許す枚数だけ。その予算は書き出しでいちばん大きな写真で決まります。
1.45 GB5,035枚でのメモリのピーク
計測で調整したエンコーダー
プリント用ファイルでは、サイズを1 % も小さくしないのにエンコード時間の3分の1を使っていたテーブルの最適化を省いています。
−33 %プリント用ファイルのエンコード時間
編集中はグラフィックスカード
カラースライダーを動かしている間は、コアが作ったテーブルからグラフィックスカードが描画します。書き出しはプロセッサーで行うので、プリントはどのマシンでも同じになります。
1–2 msスライダー1ステップあたり(26 msから)
最大20倍速く。メモリの新しい使い方。
v0.11.0では、Fotollectionが写真を保持する方法を見直しました。サムネールができるとすぐに、すべての写真のプレビューをバックグラウンドで作ってディスクに保存し、パソコンのメモリの4分の1で見ている写真の前後を保持し、画面上の写真はいつも最優先です。その結果、近くても遠くても、JPEGでもRAWでも、どの写真も27ミリ秒で開きます。同じ旅の422枚で計測して、RAWを開くのはv0.9.0の最大20倍、JPEGは10倍の速さです。5,6
以前:クリックのたびに写真をデコード
v0.10.0までは、プレビューは求められた時点で作っていました。ファイルを読み、写真をデコード(RAWなら現像)し、向きを直し、2048 pxにリサイズしてsRGBに変換し、それからトリミング、色付け、日付入れ、画面用のエンコード。Lumix GX9の20 MPの写真で、直近の8枚に入っていない写真を開くたびに、JPEGで274〜278 ms、RAWで440〜531 msかかりました。1枚なら十分速くても、旅行の写真を次々に見るには足りません。
Lightroomと同じ標準プレビュー
v0.11.0からは、ユーザーが待つ処理を、求められる前に済ませておきます。フォルダーのサムネイルがそろうとすぐ、Fotollectionはバックグラウンドで全写真の2048 pxコピーを、スレッドごとに1枚ずつ作り、サムネイルの隣のディスクに約0.66 MBのJPEGとして保存します(旅行全体で約280 MB)。近くても遠くても、今のセッションでも次のセッションでも、どの写真をクリックしてもこのコピーから始まります。JPEGでもRAWでも27 msです。残るのはプレビュー自身の処理(トリミング、リサイズ、色、日付、エンコード)で、メモリーから開くときと同じ27 msです。ディスクのコピーから作ったプレビューは、新しく作ったものと平均1.35レベル(255段階中)しか違わず、見て分かる差ではありません。8
メモリーは最小ではなく、上手に使う
16 GBのノートパソコンで8枚しかメモリーに置かない写真ビューアーは、そのノートパソコンを無駄にしています。Fotollectionはいま、コンピューターのメモリーの4分の1をプレビューに充てます(16 GBのMacなら、2048 pxで約190枚、スライダー用のRAW現像20枚分、ズーム用に600 MB)。バイト単位で数え、いちばん古いものから解放します。写真が画面に出ると、進む方向の次の2枚と後ろの1枚も読み込むので、矢印キーで待つことはありません。書き出しには引き続き2 GBの上限がかかります。
画面上の写真が最優先
RAWの現像は一度に1つだけ動かし、RAWの束がメモリーに収まるようにしています。以前は順番が運次第で、作成中のプレビュー、書き出しサイズの見積もり、書き出しが、クリックした写真を待たせることがありました。今はどの現像も誰が待っているかを伝え、画面上の写真が現像を必要とするたびにバックグラウンドの処理が道を譲ります。この作業で、まれに起きる2つの停止も見つかり、今は解消しています。ひとつは、実行するスレッドが残っていない現像をすべてのスレッドが待っていたもの、もうひとつは、画面が一度も求めていない画像を待っていたものです。
| バージョン | JPEG p50 / p95 | RAW p50 / p95 | 方法 |
|---|---|---|---|
| v0.9.0 | 274 / 286 ms | 531 / 550 ms | クリック時にデコード。RAWはmacOS経由 |
| v0.10.0 | 278 / 293 ms | 440 / 471 ms | クリック時にデコード。RAWは独自の現像 |
| v0.11.0 | 27 / 32 ms | 27 / 30 ms | ディスク上の標準プレビューまたはメモリーから |
オーナーのプラハ旅行(JPEG 396枚とRAW 26枚、20 MP)で、Apple M3上で measure_browse を使って測定。v0.9.0はそのタグからビルドし、v0.10.0はこの変更の直前のコードで測りました。
速さ:1,000枚の写真を一瞬で
フォルダーを開くときは、各写真のEXIFと小さな埋め込みサムネールだけを読み、画像全体は読みません。設定を変えたときに再描画するのはプレビューだけです。ネイティブのRustは、同じことをするWebブラウザーにも勝ります。書き出し速度は同じで、プレビューはより速く、メモリは4分の1少なくて済みます。9
フォルダーを開いたときに起きること
Fotollectionは写真フォルダーを丸ごと読み込みません。各ファイルから読むのはEXIF(日付、カメラ、撮影地)と、どのカメラもファイルに保存している小さなサムネイルだけです。1000枚で0.12秒、コードを書く前に決めた1秒の目標を大きく下回ります。その後バックグラウンドで、Fotollectionが軽快なままでいられるよう2つのスレッドで、より鮮明な400 pxのサムネイルを作ってディスクキャッシュに入れるので、もう一度開いたフォルダーはすぐに表示されます。5035枚では、読み込みに383 ms、埋め込みサムネイルに236 msかかりました。
プレビューの17 msの内訳
設定を変えると、プレビューはメモリー内にある写真の2048 pxコピーから描き直され、フルサイズのファイルからは決して描きません。所要時間16.7 msのうち、トリミングとLanczosフィルターでのリサイズが9.7 ms、日付が0.1 ms未満、画面用のプレビューJPEGエンコードが7.0 msです。このエンコーダーは測定しながら調整しました。書き出しと同じ設定(フルの色解像度と最適化したテーブル)では16.2 msかかりました。画面にはそれらは必要ないので、プレビューは色情報を半分にして標準テーブルを使い、書き出しはフルカラー(4:4:4)で作ります。もっと軽いリサイズフィルターも試しましたが、このプロセッサーではかえって遅く(12.5 ms)、Lanczosのままにしました。
ネイティブコードとブラウザー
同じ処理(デコード、2:3にトリミング、日付、品質95のJPEG)を、同じ95枚の写真で、FotollectionとChromium(コアごとに1つのワーカー)で実行しました。書き出しの速さは同じで、毎秒18.0枚対17.9枚。ブラウザーは遅いという最初の仮説は否定されました。ネイティブコードの強みは別のところにあります。ブラウザーのエンコーダーが色情報を半分にするのに対し、Fotollectionはフルの色解像度4:4:4でファイルを書き、各写真のカラープロファイルを保ち、ファイルをディスクに直接書き込み、メモリー使用量は4分の1少なく済みました(1.35 GB対1.78 GB)。その後、プリント用エンコーダーはさらに速くなり、16 MPで毎秒23.5枚です。
編集にはグラフィックスカード、書き出しにはすべてのコア
カラースライダーをドラッグしている間は、Fotollectionのコアが作るのと同じテーブルからグラフィックスカードがルックを描画し、手を離すと正確なレンダリングに切り替わります。書き出しはプロセッサーで行うので、プリントはどのマシンでも同じに仕上がります。
10本のスライダーを1本分のコストで
すべてのカラースライダー(明るさ、コントラスト、色温度、彩度、フェード、シャドウとハイライトの色付け、モノクロ)は、33 × 33 × 33色の1つのテーブルにまとめられます。各色の行き先を示す35,937個の点です。これを写真に適用するときは、ピクセルごとにテーブル内のセルを探し、セルの4つの頂点の間で補間します(四面体補間)。そのため10本のスライダーのコストは1本と変わりません。すべてのスライダーを動かした状態でのテーブル作成は約2.6 ms、1600 pxのプレビューへの適用は2.2 ms未満、24 MPの書き出しでは約24 msです。
それでもドラッグが遅く感じた理由と、グラフィックカードが変えたこと
ステップごとに測ると、スライダーの1回の動きに約26 msかかり、そのうち色そのものは2 msだけでした。残りはプレビューのJPEGエンコード(7〜11 ms)と、ウィンドウでの再デコード(9〜15 ms)です。グラフィックカードはこの両方をなくします。ドラッグが始まると、色を付ける前のプレビューと、写真がどこにあるか(日付、フレーム、余白ではない部分)を示すマスクを一度だけグラフィックカードへ送ります。以後のステップで送るのは新しいテーブルだけで、小さなWebGL2プログラムがコアとまったく同じ方法で補間します。1ステップあたりmacOSのWebKitで1 ms、Chromiumで2 msです。手を離すと、コアの正確なレンダリングに置き換わります。すべてのスライダーを動かした強いルックで両者を比べると、ΔE2000の差は平均0.13、99パーセンタイルで0.77で、並べて見たときに目が気づく1を大きく下回ります。
スイッチは必要ありません。最初のドラッグでFotollection自身が確認し、WebGL2がない、レンダラーがソフトウェア、または試しの1ステップに8 ms以上かかる場合は、セッションが終わるまでプロセッサーの経路を使います。テストではソフトウェアレンダラーが1ステップに16.5 msかかったので、その場合はプロセッサーのままが正解です。
全コアで書き出す
1枚の写真のデコードとエンコードはそれぞれ1つのコアで動くので、書き出しは複数の写真を同時に処理してこそ速くなります。何枚同時にするかはメモリー次第です。24〜26 MPの写真では、同時2枚で毎秒4.9枚、4枚で9.4枚、6枚で11.5枚、8枚で12.5枚となり、メモリーは0.49 GBから1.21 GBに増えました。Fotollectionは1.6 GBのメモリー枠と最大の写真のサイズから枚数を決め、6枚で止めます。実際の旅行の写真では、同時8枚にしても速くならず、メモリーを0.2 GB多く使ったからです。書き出しにグラフィックカードは使いません。プリントはどのコンピューターでも同じでなければならず、書き出しをバイト単位で比べるテストもそれを前提にしています。
本物の旅:プラハの422ファイル
テスト用のセットは実際より良く見せることがあります。そこで、プラハでの週末のあとにLumix GX9から取り込んだままのフォルダーを使いました。1枚約11 MBの20 MPのJPEGが396枚と、RAWファイルが26枚、合計4.7 GB。開くと0.23秒ですべてのファイルのEXIFを読み込みます。プレビューは19 msで再描画し、RAWは0.35秒で現像、ポストカード10枚は21 msで再描画します。2026年11月3日、これらの大きなファイルで2つの数字が予算に収まりませんでした。書き出しは毎秒7.6枚、メモリのピークは2.14 GB。原因を突き止めてv0.9.7で修正し、今ではJPEGの書き出しは毎秒10.1枚、実行全体で1.31 GB以下に収まります。10,11
達成できなかった2つの目標と、見つかったこと
この20 MPのファイルでは、最初の実行で2つの目標を達成できませんでした。書き出しは毎秒7.6枚、メモリーのピークは2.14 GBで、2 GBの上限を超えていました。1枚の写真の各段階の時間を測ると、時間の行き先が分かりました。デコード約100 ms、トリミング2 ms、プリントのエンコード203 ms。プリント用エンコーダーは2回目のパスでテーブルを最適化しており、そのために画像のすべての係数をメモリーに保持していました。1枚あたり約160 MB、同時6枚で約1.5 GB、それでファイルが小さくなるのはわずか0.9% です。標準テーブルならファイルを帯状に書けます。138 ms、レンダリング画像に対する誤差は同じで、増えるのは数キロバイトだけです。
メモリーの一部は、そもそもFotollectionのものではありませんでした。ベンチマークはサムネイルを全コアで作っていましたが、Fotollectionは2つのバックグラウンドスレッドを使います。さらに自身のプレビュー測定を書き出し中も保持していました。Fotollectionと同じ動き方で測ると、書き出し開始前は0.35〜0.39 GBです。v0.9.7からは、同時に処理する枚数を書き出す中で最大の写真にも合わせる(非常に大きな写真なら減らす)ので、どんなサイズでもピークは上限を下回ります。このフォルダーでは毎秒10.1枚、1.31 GBです。
メモリ:5,035枚でも安定
Fotollectionがメモリに保持するのは写真1枚あたり数バイトだけ。サムネールはディスクのキャッシュに書き込み、同時に扱うフルサイズの画像はメモリ予算に収まる枚数だけです。だから旅の写真が何千枚に増えても、メモリは安定しています。
フォルダーが大きくなってもメモリーが増えない理由
Fotollectionがライブラリーに保持するのは写真1枚あたり数バイト(5035枚で13 MB)です。サムネイルはメモリーに置かずディスクキャッシュに書き、メモリー内のプレビューは数を限り、フルサイズの写真は枠に収まる枚数だけを同時に処理します。画面上のグリッドは仮想化されていて、見えているタイルだけが存在します。テストでは、同じ95枚の写真を53回リンクして5035ファイルのフォルダーを作りました:
| 95枚 | 5035枚 | |
|---|---|---|
| 読み込みとEXIF | 5 ms、7 MB | 383 ms、13 MB |
| 400 pxのサムネイルをディスクキャッシュへ | 47.8枚/秒 | 46.4枚/秒 |
| 書き出し、同時6枚 | 18.0枚/秒 | 15.4枚/秒、失敗0 |
| 全体のメモリーのピーク | 1.35 GB | 1.45 GB |
写真が53倍になっても、メモリーは0.1 GB増えただけでした。長い書き出しで1枚あたりが少し遅いのは、5分以上動き続け、ノートパソコンのプロセッサーが持続的な負荷で速度を落とすためです。
プリント品質:プリントは、写真のとおりに
Webエディターで作ったプリントは、くすんで見えることがよくあります。エディターがカラープロファイルを捨て、写真を2000 pxに縮小し、品質80、色を半分にして保存するからです。Fotollectionはプロファイルを保ち、フル解像度の4:4:4で書き出します。
Web編集ツールからのプリントが平板に見える理由
テストでは、カメラの写真20枚と、そのDisplay P3版(最近のスマートフォンやMacの広い色空間)5枚をFotollectionの実際の書き出しで書き出し、両方のファイルを独立したデコーダーで読み込みます。カラープロファイルを通してCIELABに変換し、元の写真とピクセルごとに比べます。一般的なWeb編集ツールの書き出しにも同じ比較を行います。プロファイルを削除し、2000 pxに縮小してからプリント用に拡大し直し、品質80、色情報を半分(4:2:0)にして保存したものです。
| 中央値 | Fotollection、sRGB | Web編集ツール | Fotollection、Display P3 | Web編集ツール |
|---|---|---|---|---|
| ΔE2000(色の誤差、1未満は見えない) | 0.19 | 1.39 | 0.31 | 2.15 |
| PSNR | 52.6 dB | 37.9 dB | 50.8 dB | 37.0 dB |
| 残った彩度 | 100% | 99.9% | 99.9% | 86.8% |
| 残った細部 | 99.8% | 13% | 100% | 18% |
平板に見える原因は2つです。2000 pxへの縮小とラボ用の再拡大で、プリントをシャープに見せる細部の87% が捨てられます。そしてカラープロファイルを削除すると、Display P3の写真をsRGBとして読むことになり、彩度の13% が失われます。Fotollectionはプロファイルを保持し(25ファイル中25)、写真のフル解像度、フルカラー(4:4:4)、品質95で書き出します(測定時の値。v0.13.0からの標準は90で、それでも見て分かる差を下回ります)。大きめの誤差は、どのJPEGも最も苦労するシャープなエッジにだけ現れます。今後の課題:実際のiPhoneのHEICファイルと、分光測色計で測ったプリント。
カメラのRAW:そのまま開く
Fotollectionは、よく使われる9機種のカメラのRAWファイルを変換なしでそのまま開きます。WindowsとLinuxではインストールも不要です。v0.10.0からは、ベイヤーセンサーのすべてのカメラでフルサイズの画像を独自に現像し、RAWエディターと同じくカメラ自身のデータから作ります。一方、Adobe DNG ConverterはRAWファイルを別のRAWファイルに変換するだけです。12,13,14,15
センサーが実際に記録しているもの
カメラのセンサーは、フォトサイト(photosite)と呼ばれる小さな井戸が何百万個も並んだ格子です。シャッターが開いている間、それぞれが当たった光を集めて電荷に変え、閉じると変換器が各電荷を数値にします。この関係はリニアで、光が2倍なら数値も2倍です。人の目はまったくリニアではなく、明るさを比率で判断します。だからRAWファイルは現像するまで暗く平板に見えるのです。
この格子を読み出すセンサーは2種類あります:
- CCD(charge-coupled device、電荷結合素子)は、各フォトサイトの電荷を1行ずつ、チップの端にある1つの増幅器へ送ります。初期のデジタルカメラや多くの初期の中判デジタルバックのセンサーで、画像はきれいですが、読み出しが遅く消費電力が大きいものでした。
- CMOS はフォトサイトごとに増幅器を持ち、多くを同時に読み出します。より速く、消費電力が少なく、安く作れるため、今ではほぼすべてのカメラとスマートフォンに使われています。多くのCMOSセンサーは行を順番に読み出すため、電子シャッターで撮った速い被写体が斜めに歪むことがあり(これがローリングシャッター)、はるかに速く読み出す積層型(stacked)センサーでは歪みが少なくなります。
この数値はJPEGよりずっと多くの段階を持ちます。カメラはフォトサイトごとに12または14ビット、つまり4096または16,384段階を記録し、JPEGが保つのは8ビット、256段階です。この余分な段階のおかげで、シャドウを持ち上げたり明るい空を抑えたりしても、トーンジャンプが出ません。そして光がないことはゼロでもありません。どのセンサーも、黒付近のノイズが切り捨てられないよう、小さなオフセット、つまりブラックレベルを加えます。Nikon D750のサンプルでは黒が600、センサーが記録できる最大値であるホワイトレベルが15,520です。どのRAW現像でも最初の仕事は、この2つの数値を0と1に合わせることで、カメラによってはカラーフィルターの位置ごとにブラックレベルが違うため、位置ごとに別々に行います。
色は各フォトサイトの上のフィルターから生まれる
フォトサイトが測るのは届いた光の量だけで、色は測りません。色を見るために、センサーはカラーフィルターアレイで覆われています。各フォトサイトの上に小さな赤、緑、青のフィルターがあり、それぞれがスペクトルの一部だけを数えます。
- Bayer 配列は、1976年にKodakのBryce Bayerが特許を取ったもので、2 × 2の正方形を繰り返します。赤1、緑2、青1です。フォトサイトの半分が緑なのは、人の目が細部の大部分をスペクトルの中央から感じ取るためで、緑がシャープさの大半を担います。ほぼすべてのカメラがこの配列を、4つの向き(RGGB、BGGR、GRBG、GBRG)のどれかで使い、その向きはファイルが示す必要があります。
- X-Trans はFujifilmが2012年から使う配列で、6 × 6の正方形を繰り返し、どの行とどの列にも赤、緑、青があります。不規則な配置のおかげで、細かい繰り返し模様に色モアレが出にくく、Fujifilmは多くのセンサーが備えるローパスフィルターを省けます。その代わり、再構成は難しくなります。
- その他の方式:モノクロセンサーにはフィルターがまったくなく、すべてのフォトサイトが細部をすべて捉えます(LeicaのMonochrom)。SigmaのFoveonはシリコンの深さごとに色を吸収する3層を重ねます。多くのスマートフォンは同じ色のフォトサイト4つをまとめ(Quad Bayer)、暗い場所ではひとつとして読み出します。
つまり24 MPのBayerセンサーは2400万個の数値を記録し、それぞれが1色だけです。どのピクセルも3色のうち2色が欠けています。このモザイクから画像を作るのがデモザイクの仕事で、下で説明します。
RAWファイルの中身
JPEGは完成した画像で、カメラがすでにすべての判断を下しています。RAWファイルは、その判断の前のセンサーの数値を、後で判断するために必要なものと一緒に保存しています:
- サンプルそのもの(フォトサイトごとに1つ)と、それぞれがどのカラーフィルターの下にあったか
- ブラックレベルとホワイトレベル
- 有効領域(光を受けたフォトサイト。周囲の数行と数列は黒を測るためにわざと覆われています)と、カメラのデフォルトのトリミング
- 撮影時にカメラが選んだホワイトバランス
- このセンサー固有の赤、緑、青が、人の見る色とどう対応するかを示すカラーマトリクス
- カメラ自身が自分の色とトーンで作ったJPEGのプレビューと、EXIFデータ
メーカーごとに独自の形式があり、多くはTIFFベースで、一部は非公開です。CR2とCR3(Canon)、NEF(Nikon)、ARW(Sony)、RW2(Panasonic)、ORF(Olympus)、RAF(Fujifilm)。DNG はAdobeが公開している形式(バージョン1.7)で、Ricoh、Leica、Pentax、多くのスマートフォンが使います。このページはその規則に従っています。
FotollectionはDNGを仕様から書いた独自のリーダーで読み、ほかの形式はFotollectionに組み込んだLGPLのライブラリーrawlerで展開します。グリッドのサムネイルはセンサーのデータにまったく触れず、ファイル内のプレビューから9〜32 msで作られます。だからRAWのフォルダーもJPEGのフォルダーと同じ速さで開くのです。
デモザイク:欠けた2色を計算する
各ピクセルで欠けている2色を周りから再構成することをデモザイクと呼び、RAW写真のシャープさとクリーンさを、ほかのどの工程よりも左右します。どの方法も同じジレンマを抱えています。周囲を平均すれば平坦な部分では安全ですが、エッジをまたぐと2つの異なる面が混ざります。どの隣同士が同じものに属するかを見極めることが腕の見せどころです。
- バイリニアは、各色の最も近いフォトサイトを単純に平均します。あらゆる方法の比較基準で、柔らかく、赤、緑、青をわずかに違う位置で平均するため、シャープなエッジに沿って色のにじみが出ます。
- Malvar–He–Cutler(2004年)はこの平均から始め、固定の5 × 5フィルターで、そのフォトサイトが見た色の細部を使って補正します。よりシャープで、しかも非常に高速です。Fotollectionはv0.10.0までこれで現像していました。
- PPG(patterned pixel grouping)は、まず画像の変化が最も少ない方向を判断し、その方向にだけ補間します。rawlerが使う方法で、v0.10.0まではWindows版とLinux版のFotollectionでもほとんどの形式に使っていました。
- RCD(ratio corrected demosaicing、Luis Sanz Rodríguezによる)は色の差ではなく比率で処理し、明るい部分でも暗い部分でも崩れにくく、細部でエラーが少ないことで知られています。darktableとRawTherapeeも備えています。
- Markesteijn はFrank MarkesteijnにちなむX-Trans用の方法で、1パス、またはより遅くクリーンな3パスで動きます。
- v0.10.0以降のFotollectionのデモザイクは、方向の判断をRCDから取り入れ、緑を両側から推定してその点自身の色で補正し(HamiltonとAdamsの方法)、それぞれの側の変化の大きさで重みづけします。最初にRCD自身の比率ステップを実装しましたが、テストチャートで成績が悪かったため、勝った方を独自の名前で出荷しています。
方法が推測を誤ると、4つの典型的な形で現れます:
- ジッパー:シャープなエッジに沿って明暗のピクセルが交互に並ぶ。方法がエッジの両側から隣を取ってしまったとき
- 迷路:平坦な部分に出る細かい虫食い状の模様。Bayerの正方形の2つの緑が完全には同じ値を読まないとき(隣接する色の違う行にあり、多くのセンサーで1〜2% ずれます)
- 偽色:実際は灰色の細部、たとえば布、髪、レンガの壁、遠くのフェンスに出る色の点やにじみ
- モアレ:カラーフィルターが標本化できるより細かい、非常に細かな繰り返し模様に出る色の波
評価の方法。人の目はシャープに見える結果にだまされやすいので、すべての方法を、正解が正確に分かっている画像で採点します。コンピューターが768 pxのテストチャートを5枚描きます。ゾーンプレート(外側に向かって細かくなり、緑のフォトサイトが保てる最も細かい細部に達する同心円)、72本のスポークのジーメンススター、灰色の上に3方向で置いた飽和色の帯、なめらかなグラデーション、そして2つの緑が2% ずれた平坦な灰色です。それぞれをBayerセンサーが記録するであろう形に変換し、デモザイクして、元の画像と比べます。PSNRは全体の誤差をデシベルで測ります(大きいほど良く、6 dBごとに誤差が半分)。偽色は灰色のチャートに現れる色の平均、エッジ誤差はエッジから2 px以内の平均誤差です。
| チャート(768 px) | バイリニア | Malvar(v0.10.0までの方式) | v0.10.0以降の方式 |
|---|---|---|---|
| ゾーンプレート:PSNR、大きいほど良い | 13.0 dB | 17.3 dB | 16.5 dB |
| ゾーンプレート:偽色、小さいほど良い | 65.9 | 43.0 | 18.7 |
| ジーメンススター:PSNR | 21.3 dB | 25.2 dB | 37.9 dB |
| ジーメンススター:偽色 | 9.4 | 8.4 | 0.16 |
| 飽和色の帯:エッジ沿いの誤差、小さいほど良い | 11.6 | 21.6 | 10.5 |
| なめらかなグラデーション:PSNR | 78.9 dB | 77.5 dB | 78.4 dB |
| 緑がずれた平坦な灰色:迷路、小さいほど良い | 0.38 | 0.38 | 0 |
| 固着ピクセルのあるテクスチャー:10,000あたりの残存数、小さいほど良い | 35.8 | 66.5 | 0 |
Malvarは論文どおり、細かい灰色の細部でバイリニアより約4 dB優れていますが、強い色同士のエッジでは劣ります。補正がある色の細部をほかの色に借り、色が一緒に変化すると仮定するためで、灰色の壁の赤い看板はそうなりません。どちらも迷路を消せません。迷路はデモザイクの問題ではなく2つの緑の差で、その前にそろえておく必要があるからです。v0.10.0からの処理の流れは、こうした穴をふさぎます。各点がまだ測った値だけを持っているうちに固着ピクセルと緑のずれを直し、方向に応じたデモザイクで色を再構成し、色差に小さなメディアンをかけて残った偽色を消します。テストチャートではすべての項目で勝ち、例外はゾーンプレート全体のPSNRだけで、どの方法もエイリアスが出る最も細かい細部の近くでMalvarより0.8 dB低くなります。それでも偽色はそこでも半分になります。実際の9ファイルでは、どのBayer機の現像もカメラ自身のJPEGに同じかそれ以上近づき、24 MPで約180 msかかります。Malvarの40 msと比べて1枚あたり数十分の1秒長くなりますが、その分細部のきれいなプリントになります。
カメラの色からあなたの色へ
カメラの赤、緑、青は、画面の色と同じではありません。センサーごとにフィルターの色素が違い、人の目の錐体とは違う形で重なり合っています。ファイル内のカラーマトリクスがカメラの色を CIE XYZ(1931年に定められた人の色覚の標準モデル)に変換し、そこから多くの画面と写真ラボの色空間である sRGB に変換します。
- 最初はホワイトバランスです。赤と青にゲインをかけ、シーンで白いものがニュートラルに見えるようにします。カメラは選んだゲインを記録しており、Fotollectionはそれをデモザイクの前に適用するので、上の方法が使う色差は小さいままです。
- DNGはふつうマトリクスを2つ持っています。ひとつは暖かい白熱灯、もうひとつは昼光で測ったものです。写真に合うのはその間で、現像はホワイトバランスから撮影時の光を色温度として計算し、2つを混ぜます。Fotollectionはほかの形式でも、rawlerがカメラのモデルごとに知っているマトリクスで同じことをします。
- これはすべて、どのカーブよりも前に、センサー自身のスケール、つまりリニア光で行います。色の混合、スケーリング、リサイズはリニア光で行うと物理的に正しい結果になり、カーブの後で行うとエッジが暗くなり、色がずれます。
カメラ本来のルック。カメラ自身のJPEGはニュートラルではありません。どのメーカーも独自のコントラスト、色、肌のトーンを加えていて、そのルックは人がブランドを選ぶ理由の一部です。v0.10.0から、RAW写真はニュートラルな表示で開きます。センサーのマトリクスに忠実で、レンズの周辺減光とカメラが選んだ露出を反映したものです。Like the camera’s JPEG はRAW写真の RAW colour カードにあり、ワンクリックで1枚にも、すべてのRAWにも一度に適用できます。(v0.10.0までは、すべてのRAWをカメラのJPEGに合わせていました。当時保存したプロジェクトはそのルックを保ちます。)この選択は、カーブとマトリクス、またはチャンネルごとのカーブという2通りでカメラのJPEGに合わせ、そのファイルでより近づいた方を残します。Nikon D750では差が半分になり、ΔE2000で2.26から1.16になりました。グリッドのサムネイルは、Lightroomと同じくカメラ自身のプレビューを使います。
トーン:リニアな数値から画像へ
リニアな数値は画面で暗く色あせて見えます。光が2倍になると、センサーは2倍の数値として記録しますが、私たちには1段分明るくなったようにしか見えないからです。トーンカーブがセンサーのスケールを画像に変えます。中間グレーの位置を決め、シャドウを持ち上げ、ハイライトを一気に切らずになだらかに丸め、画像のコントラストを決めます。その後、画像はsRGBカーブ(いわゆる「ガンマ」)で保存され、JPEGの256段階のうち多くを、目が段差に最も敏感なシャドウに割り当てます。
カメラがJPEGで行う補正のうち2つはRAWデータに含まれておらず、どちらもプリントに影響します:
- 周辺減光:どのレンズも隅に向かって暗くなります。Fotollectionは、カメラが隅をどれだけ明るくしたかを、カメラ自身のプレビューから放射方向のゲインとして測ります。最初にDNGの現像をカメラのJPEGと比べたとき、中央は約4 L* 明るすぎ、隅は1.5暗すぎました。放射方向のゲインで差は ΔE 3.8から2.67に縮まり、写真のどの部分も ±0.5 L* 以内に収まりました。
- 歪曲:レンズのわずかな樽型や糸巻き型の歪みです。マイクロフォーサーズのカメラ(Panasonic、Olympus)はカメラ側で補正する前提で設計され、ファイルにその方法が記録されています。Macではこれらのファイルを補正を適用するmacOSが現像し、独自の現像での補正は予定しています(FR-085)。
FotollectionのRAW現像、ステップごと
プリントプレビュー、ズーム、書き出しの裏にあるフル現像では:
- 判別:形式はファイル名ではなく先頭のバイトから判別するので、名前を変えたファイルや、ただのTIFFに見えるRAWも正しく読めます。
- 読み込み:センサーの数値。DNGは独自のリーダーで、ほかの形式はrawlerで展開します。大きすぎるファイルや壊れたファイルは、1ピクセルもデコードする前にエラーコード付きで拒否します。
- レベル:黒を0、白を1に。カラーフィルターの位置ごとに、有効領域の隅から数えて。
- ホワイトバランス、続いてデモザイク:最初に固着ピクセルと緑のずれ、次に方向に応じたデモザイク、最後に偽色のメディアン(X-TransのMarkesteijnはv0.15.0で登場予定)。
- 色:カメラのマトリクスを撮影時の光に合わせて混ぜ、リニア光で。
- トーンとルック:カメラのプレビューに合わせ、周辺減光も含めて。
- ここからはRAW写真もほかの写真と同じです。トリミング、日付、フレーム、プリントサイズ、カラープロファイル。フル解像度、4:4:4、品質95で書き出します。
いくつかの規則は全体を通して守られます。現像は一度に1つだけ、すべてのプロセッサーコアに分散して動き、ウィンドウ自身のスレッドでは決して動かないので、30 MPの写真を現像中でもFotollectionは反応します。書き出しは常にプロセッサーで行うので、プリントはどのコンピューターでも同じになります。グラフィックカードが速くするのは編集中に見えるものだけです。そしてコードは私たち自身のもので、ほかのプロジェクトからコピーせず、公開された仕様と論文から書き、検証しています。上の合成チャート、9機種のRAWファイル9点(CC0、raw.pixls.usより)、そしてファイルをわざと切り詰めたり壊したりして、壊れたファイルがクラッシュではなくエラーになることを確かめています。
v0.10.0から:すべてのBayer機に独自の現像。rawlerはファイルを展開するだけで、残りはFotollectionが行います。9つのサンプルファイルのフル現像、3回の中央値、同じノートパソコンで。よりクリーンなデモザイクを持つ私たちの現像と、rawlerのよりシンプルな方式、そしてmacOSの比較です:
| カメラ(形式) | Fotollection独自 | rawler | macOS |
|---|---|---|---|
| Panasonic GX9 (RW2, 20 MP) | 280 ms | 216 ms | 436 ms |
| Panasonic S5 (RW2, 24 MP) | 442 ms | 301 ms | 1044 ms |
| Olympus E-M10 III (ORF, 16 MP) | 308 ms | 364 ms | 1164 ms |
| Sony A7 III (ARW, 24 MP) | 372 ms | 241 ms | 488 ms |
| Canon R10 (CR3, 24 MP) | 494 ms | 360 ms | 1647 ms |
| Ricoh GR III (DNG, 24 MP) | 523 ms | 650 ms | — |
| Nikon D750 (NEF, 24 MP) | 502 ms | 402 ms | 412 ms |
| Canon 5D Mark IV (CR2, 31 MP) | 691 ms | 565 ms | 418 ms |
| Fujifilm X-T3 (RAF, 26 MP, X-Trans) | 対応予定 | 524 ms | 1339 ms |
私たちの現像は、よりクリーンなデモザイクと合わせ込んだ色のためにrawlerより0.1〜0.25秒長くかかりますが、ほとんどのカメラでmacOSより速いままです。現像は1枚につき1回だけで、その後はスライダーが保持したコピーを4〜11 msで処理し直します。Macでは、PanasonicとOlympusのファイルは、独自の現像が歪曲を補正できるようになるまで、レンズ補正のためmacOSのままです。S5のグレーのパッチはrawler経由よりもニュートラルになります(色のずれ1.42対2.43、0が完全なグレー)。次はMarkesteijnによるFujifilmのX-Trans、その後はプロセッサーの結果を基準にしたグラフィックカードでのプレビュー現像です。
ベストショットの提案:人の選択と比べて
本物の写真95枚を手作業で22の場面に分け、はっきりしたベストがある場面ではそれを選びました。そのうえでFotollectionのグループと提案をこの選択と比べました。
提案の仕組みと、その評価方法
Fotollectionはまず「瞬間」を探します。写真を撮影時刻の順に1秒未満の精度で並べ、間隔が2秒または普段の間隔の4倍を超えたとき、カメラやレンズが変わったとき、撮影地が30 m以上離れたときに、新しい瞬間を始めます。さらに写真ごとに小さな視覚的な指紋(明暗の配置と色の混ざり具合)を作り、直前の写真とまだ似ている場合にだけ、その瞬間に加えます。横への一歩や、焦点距離で説明できるズームは許容します。
次に、ひとつの瞬間の中で、縮小コピーを使って各写真を測ります。被写体のシャープさ、手ぶれ、露出(白飛び、黒つぶれ、明るさ)、ノイズ、そして顔があれば、目が開いているか、顔がカメラを向いているか。どの指標も同じ瞬間のほかの写真とだけ比べ、重みをつけます(被写体のシャープさ35%、開いた目20%、手ぶれ15%、露出15%、白飛び10%、その他はそれ以下)。最小の差も設けているので、プリントで見えない違いが決め手になることはありません。提案には理由が添えられ、何も削除されず、すべてがあなたのコンピューター上で、1枚17 ms未満、顔がある場合は28 ms未満で動きます。
正直であるために、実際の写真95枚を手作業で22の瞬間に分け、明確なベストがある6つの瞬間では残すべき写真を決めました。すべての改良をこれと比べて測っています:
| ステップ | 見つかった瞬間(22件中) | 誤った統合 | 妥当な選択 |
|---|---|---|---|
| 画像の指紋だけ | 3 | 0 | 2件中2 |
| +配置と色 | 13 | 0 | 4件中3 |
| +焦点距離から見たズーム | 15 | 0 | 6件中5 |
| +公平なシャープさと隠れた顔 | 15 | 0 | 6件中6 |
異なる2つの瞬間が同じグループになることはありません。余分な2つのグループは、手作業で「判断に迷う」と印をつけたペアです。まだ見逃している瞬間は、ポーズや構図が大きく変わるもの、たとえば料理を反対側からも撮った場合です。
数字の裏にある用語
写真とプリントの専門用語を、友だちに話すように説明します。
ΔE(デルタE)とは?16
ΔEは、2つの色が人の目にどれだけ違って見えるかを、私たちの見え方に合わせた色空間(CIELAB、2000年の式)で計算したものです。0は同一。約1は、慣れた目が並べて見て気づく最小の差。2〜3はたいていの人に見え、5を超えると違う色に見えます。Fotollectionのプリント用の書き出しは平均0.19です。
SSIMとは?17
SSIM(構造的類似性指標)は、個々のピクセルではなく2つの画像の形やテクスチャーを比べます。ぼけやブロック状の圧縮ノイズに私たちが気づく仕方に近い指標です。1は同一で、約0.98を超えると、たいていの人は拡大しない限り見分けられません。
JPEGはいくつの色を記録できますか?6,18
JPEGは赤・緑・青それぞれに8ビット、つまり各256段階、合計約1670万色を記録します。写真ラボもこれからプリントします。カメラのRAWファイルは12〜14ビット、最近のiPhoneは10ビットのHEICでも保存でき、編集のときに役立ちます。仕上がったプリントなら、きちんと作った8ビットのJPEGでトーンに段差は出ません。
JPGとJPEGの違いは?PNGを使うべき?
JPGとJPEGは同じ形式です。昔のWindowsが3文字の拡張子しか使えなかっただけです。PNGは可逆なので何も失われませんが、PNGで保存した写真は3〜5倍の大きさになることが多く、ほとんどのコピー機やラボはJPEGを求めます。Fotollectionがプリント用に書き出す、品質90以上・色の解像度フル(4:4:4)のJPEGなら、紙の上では元の写真と見分けがつきません。
4:4:4と4:2:0とは?
私たちの目は細部を主に明るさで見ていて、色ではそれほど見ていません。そのためJPEGは色を低い解像度で記録できます。4:4:4は色の解像度をすべて保ち、4:2:0は4分の1だけを保ちます。ファイルは小さくなりますが、赤い文字や葉の向こうの青空のような色の境界がにじみます。プリントには4:4:4がふさわしく、SNSはどのみちすべてを4:2:0に再圧縮します。
sRGB、Display P3、Adobe RGBとカラープロファイル19,20,21
カラープロファイルは、ファイルの中の数字が何を意味するかをソフトに伝えます。sRGBはWebで使われる標準的な色域です。iPhoneや最近のカメラが使うDisplay P3は、おもに赤と緑で約25 % 多くの色を表せます。P3の写真がプロファイルを失うと、その数字はsRGBとして読まれ、くすんで見えます。私たちが計測した13 % の彩度の低下がこれです。一部のカメラがプリント用に用意するAdobe RGBもsRGBより広く、おもに緑とシアンで差があります。Fotollectionはプリント用には写真のプロファイルを何であれそのまま保ち、SNS用にはきちんとsRGBに変換します。
プリントには何DPI必要?
DPIは用紙1インチあたりのピクセル数です。300 DPIなら近くで見てもシャープで、腕を伸ばした距離なら150〜200 DPIで十分です。10 × 15 cmのプリントなら300 DPIで1800 × 1200ピクセルが必要なので、スマートフォンやカメラの写真ならどれでも足ります。アプリのサイズ提案が、それぞれの写真をどこまで大きくできるかを教えてくれます。
Facebookで写真がきれいに見えないのはなぜ?
Facebookはすべての写真を最大2048 pxにリサイズし、低めの品質と半分の色解像度で再圧縮して、カラープロファイルを捨てます。大きすぎる写真は、あなたとFacebookで2回リサイズされます。最初から2048 px、sRGB、軽くシャープにして送れば、Facebookの再圧縮は1回だけで、色も最初から正しいままです。
計測を自分で再実行
どれも自分の写真で繰り返せます。スクリプトが写真をアップロードしたりコピーしたりすることはなく、残るのは数字だけです。すべての実行を含む表の全体はRESULT.mdにあります。
bench/run.sh ~/Pictures/some-folder 3
uv run bench/quality/audit.py ~/Pictures/some-folder /tmp/out
uv run bench/quality/share_audit.py ~/Pictures/some-folder /tmp/share