2. ディジタルカメラモデルとディジタル画像
第1章の最後で、絵は画素で出来ていて、映像はフレームで出来ていて、そして誰かがカメラを持たなければならない、と書きました。
此の章では其れを文字通りに受け取ります。
CGの殆ど全ては「コンピュータの中にしか存在しないシーンを、カメラで撮影する事」として説明出来ます。
其の為、先ず本物のカメラの仕組み(ピンホール、レンズ、絞り、シャッター、センサー)を見て、次に其のカメラが作る絵の正体を見ます。
其の正体は数値の格子で、標本化と量子化によって作られます。
此れは検定の為だけの話ではありません。
ギザギザの輪郭、ちらつくテクスチャ、暗い空に出る縞、JPEGのぼやけたノイズ、全て此の章の考え方から生まれます。
原因が分かれば、対策も分かります。
CGエンジニア検定では、此の章は出題範囲の1「CGとディジタルカメラモデル」に当たります:ディジタルカメラモデル、ディジタル画像の基礎、そしてCGと画像処理です。
2.1 カメラとしてのCG:ディジタルカメラモデル
写真家がする事を考えてみましょう。
カメラの前に人や物を置き、照明を組み、位置とレンズを選び、シャッターを押し、後で現像してレタッチします。
被写体やカメラが動き、其れを連続で撮れば映像になります。
CGも全く同じ事をしますが、全ての段階がコンピュータの中で行われます。
CGを此の様に捉える考え方をディジタルカメラモデルと言います。
現実の各段階にはCG側の対応する段階があり、其の一つ一つが大きな分野です:
- モデリングは被写体を作ります。形状、材質、そして全ての物の配置です。
- ライティングとシェーディングは、光がどこから来て、表面が其の光にどう反応するかを決めます。
- レンダリングは「シャッターを押す事」です。仮想カメラに見える画像を計算します。
- 画像処理は暗室です。色の調整、ぼかし、シャープ化、画像の合成等を行います。
- アニメーションはシーンやカメラを時間と共に変え、フレームを次々に作ります。
但し、仮想カメラは少しずるいです。
重さも、ノイズも、埃も無く、点と同じ大きさにも出来て、壁もすり抜けられます。
其の反面、本物のレンズが「勝手に」してくれる事(ピントの外のぼけ、モーションブラー、レンズフレア)は、欲しければわざわざ計算しなければなりません。
両方を理解する為に、先ずは本物のカメラを見てみましょう。
2.2 ピンホールカメラ
一番単純なカメラにはレンズが有りません。
暗い箱の一面に小さな穴を開け、反対側の面にスクリーン(又はセンサー)を置きます。
シーンの各点からの光は穴を通ってしかスクリーンに届かないので、シーンの1点はスクリーンのちょうど1点に写ります。
此れがピンホールカメラで、殆ど全てのCGソフトウェアが使うカメラのモデルです。
図で注目して欲しい点が2つあります。
1つ目は、光線が穴で交差する為、センサー上の像は上下逆さま(そして左右も反転)になる事です。
2つ目は、穴から画像面までの距離を焦点距離 と呼ぶ事です。
CGでは此処で小さな技を使います。
同じ距離 だけ穴の前に想像上のスクリーンを置くと、光線は軸から同じ距離の所を通りますが、像は正立します。
本物のカメラでは出来ません(スクリーンが光を遮ってしまいます)が、仮想カメラには関係無いので、CGでは常に此の仮想の画像面を使います。
第5章では、此れが透視投影の投影面になります。
式:相似な三角形
ピンホールを原点に置き、軸に沿って見ます。
カメラの前の距離 、高さ にある点と、距離 の画像面上の高さ にある其の像は、2つの相似な三角形を作ります。
従って比が等しくなります:
遠くの物( が大きい)は小さくなります。
此れが正に遠近感です。
線型代数シリーズの第12章では此の での割り算を行列にしました。
此のシリーズでは第5章でCGの立場から投影を見ます。
計算例。
身長1.7 mの人が、 mmのカメラの10 m前に立っています。
全てミリメートルで計算します:、。
センサー上では8.5 mmの高さになります。
5 mまで近付くと が半分になるので、像は2倍の17 mmになります。
画角
シーンのどれだけが写るかは、センサーの大きさと焦点距離で決まります。
画角(CGでは視野角、英語でfield of view、略してFOVと呼ぶ事が多いです)は、センサーの両端に届く光線の間の角度です:
軸は図を、辺が と で、ピンホールでの角度が の2つの直角三角形に分けます。
従って となり:
計算例。
「フルサイズ」のセンサーは36 mm × 24 mmで、レンズは mmとします。
センサーの対角線は mmなので、対角線の画角は です。
カメラメーカーは普通対角線の画角を書き、ゲームやCGソフトウェアは普通垂直又は水平の画角を求めるので、数値がどれを意味するか必ず確認して下さい。
焦点距離だけを変えると(センサーの幅は36 mm):
| 焦点距離 | 水平画角 | レンズの種類 |
|---|---|---|
| 24 mm | 73.7° | 広角 |
| 50 mm | 39.6° | 標準 |
| 100 mm | 20.4° | 望遠 |
焦点距離が短い程広く写り、長い程ズームした様になります。
CGでは逆向きに使う事も多いです。
視野角と画像の幅(画素数)を決めて、画素単位の焦点距離が欲しい場合です。
幅を 画素として、式を について解きます:
、水平視野角90°なら、 なので 画素です。
何故CGのカメラはピンホールなのか
本物のピンホールカメラは実用的ではありません。
穴からは僅かな光しか入らないので露光に数秒から数分掛かりますし、像をシャープにしようと穴を小さくしていくと、小さな穴の縁で光が曲がる(回折)為に、或る所から逆にぼやけ始めます。
仮想のピンホールには此れらの問題が全く有りません。
数学的な点なので露光時間も要らず、シーンの全ての点が、近くても遠くても完璧にシャープに写ります。
其の為、CGの標準のカメラはピンホールで、「1画素に1本の光線を1点を通して飛ばす」事がラスタライズ(第6章)とレイトレーシング(第12章)の両方の中心にあります。
其の代わり、CGの絵は「シャープ過ぎる」様に見えます。
本物のレンズが加える物は全て真似しなければならず、真似する為にはレンズが何をしているかを知る必要があります。
2.3 実際のレンズとカメラの設定
レンズは広い範囲(開口部)から光を集め、シーンの1点から出た全ての光線を、レンズの後ろの1点に再び集まる様に曲げます。
ピンホールより遥かに明るい像が得られますが、完璧にシャープに写るのは或る特定の距離にある点だけです。
薄レンズの公式
一番単純なレンズのモデルは薄レンズです。
十分薄いので、全ての屈折が1つの面で起こると見なせるレンズです。
軸に平行な光線はレンズの後ろの距離 にある焦点 を通る様に曲がり、中心を通る光線は真っ直ぐ進み、前側の焦点 を通った光線は軸に平行になって出て行きます:
物体がレンズの前の距離 にあり、シャープな像がレンズの後ろの距離 に出来る時、レンズの公式(薄レンズの式)は次の通りです:
図は 、、(単位は何でも構いません)で描いています:。
像は物体の 倍の大きさで、ピンホールカメラと同じく上下逆さまです。
計算例。
50 mmのレンズで2 m(2000 mm)先の被写体にピントを合わせます。
センサーはレンズの後ろどれだけの所にあるべきでしょうか?
1 m先の被写体なら、同じ計算で mmです。
ピント合わせとは此れの事で、レンズをセンサーから1〜2 mm離すだけです。
被写体がとても遠い時は が0に近付き、 になります。
此れが焦点距離の本当の定義で、無限遠にピントを合わせた時のレンズとセンサーの距離です。
倍率は なので、2 m先の身長1.7 mの人はセンサー上で mmになります(24 mmのセンサーには収まらないので、上半身だけが写ります)。
ピンホールの式なら mmです。
被写体が遠い程 が に近付くので、2つのモデルはどんどん一致していきます。
絞りとF値
レンズの中には大きさを変えられる穴、絞りがあり、其の直径を とします。
絞りの大きさはF値で表します:
50 mmのレンズでF2なら開口は mm、F8なら mmです。
つまり、F値が大きい程穴は小さくなります。
最初は殆ど誰でも此処で混乱します。
通る光の量は穴の面積、つまり に比例するので、 に比例します。
其の為、標準的なF値は1.4、2、2.8、4、5.6、8、11、16と並んでいます。
各値は前の値の約 倍で、面積と光の量が半分になります。
此の1段階を「1段」と呼びます。
被写界深度と錯乱円
レンズが距離 にピントを合わせている時、別の距離 にある点はセンサー上で1点に集まりません。
其の光の円錐は頂点の手前か先でセンサーに切られ、点ではなく小さな円板になります。
此れが錯乱円です。
此の図の相似な三角形から(両方の点にレンズの公式を使うと)、円板の直径は次の様になります:
が最終的な絵で気付かない程小さければ、其の点はまだシャープに見えます。
シャープに見える距離の範囲を被写界深度と言います。
計算例。
50 mmのレンズをF2( mm)にして、 mmにピントを合わせます。
mmにある点のぼけはどれ位でしょうか?
フルサイズのセンサーでは、「シャープに見える」限界は約0.03 mmとするのが普通なので、此の背景の点は10倍以上大きな円板、はっきりとぼけています。
正確な被写界深度の式は覚えなくても良いですが、傾向は知っておくべきです。
被写体が遠過ぎなければ、被写界深度全体は次の式で良く近似出来ます:
、 mm、 mm、 mmなら:
被写体の前後約19 cmしかシャープになりません。
F8なら同じ式で mmです。
(完全な式で計算した正確な値は約188 mmと776 mmなので、此処では近似が十分良く合っています。)
式を読むと:
- F値が大きい(絞りが小さい)程、被写界深度は深くなります。極端な例がピンホールで、全てがシャープです。
- 焦点距離が長い程、被写界深度は浅くなります(分母に があります)。
- 被写体が近い程、被写界深度は浅くなります(分子に があります)。
CGでは、被写界深度の効果は2通りの方法で作ります。
物理的には、ピンホールを薄レンズに置き換え、絞りのランダムな点から光線を飛ばします。
安価な方法では、完成した画像の各画素を、其の深度から計算した錯乱円の大きさでぼかします。
ゲームは殆ど後者、映画用のレンダラーは殆ど前者を使います。
シャッター速度とモーションブラー
シャッターはセンサーが光を集める時間を決めます。
此れがシャッター速度(露光時間) で、1/60秒や1/1000秒等です。
其の間に動いた物は、動いた経路に沿って引き伸ばされます。
此れがモーションブラーです。
計算例。
車が画像の中を毎秒1200画素の速さで横切り、シャッターは1/60秒開いています。
シャッターが開いている間に 画素動くので、20画素分引き伸ばされます。
1/1000秒なら1.2画素しか動かず、止まって見えます。
映画は伝統的に毎秒24フレームで、各フレームの半分の時間(1/48秒)シャッターを開けているので、映画には沢山のモーションブラーが含まれていて、あたし達の目は其れに慣れています。
CGのカメラは、指定しない限り露光時間がゼロです。
全てのフレームが完全に止まった一瞬です。
モーションブラーを加えるには、レンダラーは「シャッターが開いている時間」内の幾つかの時刻のシーンを平均するか、ポストプロセスで画素を其の動きに沿ってぼかします。
2.6節と2.7節で、此れが実は時間方向のアンチエイリアシングである事が分かります。
露出
絵の明るさを露出と言います。
3つの設定で決まります:
- 絞り:光の量は に比例します。
- シャッター速度:光の量は に比例します。
- 感度(ISO感度):2倍にすると信号が2倍になりますが、ノイズも増幅されます。
写真家は絞りとシャッター速度を1つの数値、露出値(EV)にまとめます:
F8で1/125秒なら 、つまり約EV 13です。
F5.6で1/250秒なら 、此れも約EV 13です。
絞りで1段明るく、シャッターで1段暗く。
露出は同じですが、被写界深度は浅く、モーションブラーは少なくなります。
露出の選択は全て、明るさ、被写界深度、モーションブラー、ノイズの間の取引です。
CGでの「露出」は、計算した光を表示出来る画素値に変換する前に掛ける1つの数値に過ぎません(トーンマッピング、第15章)。
但し、物理ベースのレンダラーでは、本物の写真と結果が合う様に、実際のF値、シャッター速度、ISO感度を入力出来る物も多いです。
レンズの歪みと周辺減光
本物のレンズは完璧ではありません。
一番目立つ欠点は歪曲収差(レンズの歪み)で、画面の端の方で直線が曲がります。
単純なモデルでは、全ての点を画像の中心からの距離 に沿って動かします:
なら隅が内側に引っ張られ(樽型歪み、広角レンズに多い)、 なら外側に押し出されます(糸巻き型歪み、望遠レンズに多い)。
次の格子は正に此の式( と )で計算しました:
他にも次の様な欠点があります:
- 周辺減光(ビネッティング):画面の隅が中心より暗くなります。理想的なレンズでも、軸からの角度の に大体比例して暗くなる自然な周辺減光があります。
- 色収差:ガラスは波長によって光の曲がり方が違うので、輪郭に細い色の縁が出ます。
- レンズフレア:明るい光がレンズの中で反射し、輪や筋を残します。
完璧な仮想カメラは人工的に見えるので、CGでは此れらを全て完成した画像へのポストエフェクトとして真似します。
逆方向では、コンピュータビジョンが本物のカメラをキャリブレーション( 等を測定)して歪みを取り除き、写真とCGを正確に合成出来る様にします(第14章)。
コードで試す(任意)
此の節の数値を計算する数行のC++です。
自分のレンズで試してみて下さい:
#include <cmath>
#include <cstdio>
#include <numbers>
// Angle of view (radians) of a sensor of size h behind a pinhole/lens of focal length f
double angleOfView(double h, double f) {
return 2.0 * std::atan(h / (2.0 * f));
}
// Thin lens: image distance b for an object at distance a (1/f = 1/a + 1/b)
double imageDistance(double f, double a) {
return 1.0 / (1.0 / f - 1.0 / a);
}
// Diameter of the circle of confusion for a point at distance a,
// when a lens with focal length f and aperture D is focused at distance af
double circleOfConfusion(double f, double D, double af, double a) {
return D * f * std::fabs(a - af) / (a * (af - f));
}
double degrees(double rad) { return rad * 180.0 / std::numbers::pi; }
int main() {
double f = 50.0; // mm
printf("horizontal: %.1f deg\n", degrees(angleOfView(36.0, f)));
printf("vertical: %.1f deg\n", degrees(angleOfView(24.0, f)));
printf("diagonal: %.1f deg\n", degrees(angleOfView(std::hypot(36.0, 24.0), f)));
printf("b = %.2f mm\n", imageDistance(f, 2000.0));
double N = 2.0; // f-number
double D = f / N; // aperture diameter
printf("c = %.3f mm\n", circleOfConfusion(f, D, 2000.0, 4000.0));
long bytes = 1920L * 1080L * 3L;
printf("1920x1080 RGB: %ld bytes (%.2f MiB)\n", bytes, bytes / (1024.0 * 1024.0));
}
horizontal: 39.6 deg
vertical: 27.0 deg
diagonal: 46.8 deg
b = 51.28 mm
c = 0.321 mm
1920x1080 RGB: 6220800 bytes (5.93 MiB)
最後の行は2.5節の予告です。
2.4 撮像素子
ディジタルカメラのレンズの後ろには撮像素子(イメージセンサー)があります。
フォトサイトと呼ばれる光を感じる小さなセルが何百万個も並んだチップです。
各フォトサイトは露光中に当たった光(光子)を電荷に変え、電荷は電圧になり、A/D変換器が其の電圧を整数(普通12ビット又は14ビット)に変えます。
此の瞬間に絵が数値になります。
(今のセンサーは殆どがCMOSセンサーです。古いCCDも原理は同じです。)
フォトサイトが測れるのは届いた光の量だけで、色は分かりません。
色を得る為、殆ど全てのカメラは各フォトサイトの上に小さな色フィルタを載せ、繰り返しのパターンで並べます。
此れをカラーフィルタアレイと言います。
一番一般的なのは、1976年にKodakのBryce Bayerが特許を取ったベイヤー配列です:
フォトサイトの半分が緑、4分の1が赤、4分の1が青です。
緑が2倍あるのは、あたし達の目が明るさと細部の感覚を主にスペクトルの緑の部分から得ているからです(第3章)。
つまりセンサーの生データはモザイクで、各画素は3色の内1色しか知りません。
足りない2色は周りの画素から推定します。
此れがデモザイクです。
一番単純な方法は平均です。
赤のフォトサイトの上下左右の4つは緑なので、其れらが100、104、96、108を測ったとすると:
単純な平均では鋭い輪郭に沿って色の縁が出てしまうので、実際のカメラは輪郭に沿う、もっと賢い方法を使います。
デモザイクの後、カメラはホワイトバランスと色を調整し、結果を圧縮して(多くはJPEG、2.10節)、見慣れたRGB画像になります。
レンダラーには此れらが一切ありません。
全ての画素の赤・緑・青を直接計算します。
其れでも知っておく価値はあります。
「リアルな」CGは、センサーの典型的な欠点をわざと足し戻す事が多いからです。
ノイズ、フィルムグレイン、そしてローリングシャッターの歪み(多くのCMOSセンサーは行を1行ずつ順に読むので、速く動く物が傾きます)等です。
2.5 ディジタル画像:標本化と量子化
いよいよ絵其の物です。
センサーに当たる光は連続な画像です。
明るさと色は全ての点で定義され、どんな値も取れます。
コンピュータは有限個の数値しか保存出来ないので、2つの物を離散的にしなければなりません:
- どこで測るか、そして
- どんな値を保存出来るか。
1つ目の段階が標本化(サンプリング)で、一定の間隔の位置の値だけを残します。
2つ目が量子化で、残した各値を決まった数の段階の何れかに丸めます。
1次元で見ると次の様になります。
曲線を13の位置で標本化し、其れを8段階に量子化しています:
画像は此れの2次元版です。
xとyの格子上で標本化し、値を量子化します。
結果がディジタル画像、つまり数値の長方形の配列です。
動画には3つ目の標本化の方向、時間が加わります。
毎秒24、30、60フレーム等です。
画素・解像度・アスペクト比
ディジタル画像の各標本が画素(ピクセル、picture elementの略)です。
画素を小さな色の付いた四角形と考えたくなりますし、画面は実際にそう表示しますが、数学的には画素は連続な画像の1点での標本です。
此れを覚えておくと、此の章の残りがずっと分かり易くなります。
画像の座標は普通左上の角から始まり、yは下向きです。
数学とは逆なので注意して下さい(第4章で扱います)。
解像度には2つの意味があり、どちらも検定対策として押さえておきたいです:
- 画素数:例えば1920 × 1080(幅 × 高さ)。
- 画素の密度:例えば印刷の300 dpi(1インチ当たりのドット数)や、画面のppi(1インチ当たりの画素数)。
1920 × 1080は 画素、約210万画素です。
300 dpiで印刷すると インチ × インチ、約16.3 cm × 9.1 cmになります。
同じ画素でも、物理的な大きさが決まります。
アスペクト比は幅:高さです。
1920と1080の最大公約数は120で、、 なので、1920 × 1080は16:9です。
640 × 480は昔のテレビの形の4:3です。
ビット深度と階調数
量子化はビット深度、つまり1つの値を何ビットで保存するかで表します。
ビットなら 段階、此れが階調数です:
| 1チャンネル当たりのビット数 | 階調数 | 主な用途 |
|---|---|---|
| 1 | 2 | 白黒のみ(FAX、単純なプリンター) |
| 8 | 256 | 普通の画像と画面 |
| 10 | 1024 | HDR映像、広色域ディスプレイ |
| 16 | 65,536 | 写真編集、科学画像 |
濃淡画像(グレースケール画像)は1画素に1つの値、明るさを持ちます。
カラー画像は普通1画素に赤・緑・青の3つの値、つまり3つのチャンネルを持ちます。
1チャンネル8ビットなら1画素24ビットで、
通りの色を表せます。
此れをフルカラー(トゥルーカラー)と呼びます。
4つ目のチャンネル、アルファには、各画素の不透明度(0 = 完全に透明、1 = 完全に不透明)を入れる事が多いです。
第14章の合成で必要になります。
画像の大きさ
画素数 × チャンネル数 × 1チャンネルのバイト数です。
1チャンネル8ビットの1920 × 1080のRGB画像なら:
約6.2 MB、又は MiBです。
アルファ付き(RGBA)なら バイトです。
そして毎秒60フレームの非圧縮の動画なら、 バイト、約373 MBが毎秒必要です。
其の為、圧縮(2.10節)は必須です。
量子化を数値で見る
値を0(黒)から1(白)の数で書く事にします。
段階の時、保存する整数 と、其れが表す値は次の通りです:
段階の間隔は なので、誤差は其の半分、 を超えません。
計算例。
を3ビット( 段階)で保存します:
誤差は で、最大値 より十分小さいです。
8ビット()なら間隔は しかないので、誤差は最大でも約0.002です。
2.6 標本化定理とエイリアシング
標本化は標本と標本の間の全てを捨てます。
其れが無害なのはどんな時でしょうか?
答えが此の章で一番大事な式です。
周波数と標本化定理
どんな信号も(画像の1行も)、様々な周波数の波の和として表せます。
ゆっくりした変化(滑らかな空)は低い周波数、速い変化(細かい縞、鋭い輪郭、文字)は高い周波数です。
標本化定理(ナイキスト・シャノンの定理とも言います)は次の事を言っています:
最も高い周波数が の信号は、標本化周波数が其の周波数の2倍より大きければ、標本から正確に復元出来る。
標本化周波数の半分 が、表せる一番高い周波数で、ナイキスト周波数と言います。
計算例。
人の耳は約20 kHzまで聞こえます。
音楽CDは44.1 kHzで標本化するので、ナイキスト周波数は kHzで、聞こえる範囲を少しだけ上回ります。
画像の場合、標本化周波数は1画素に1標本なので、ナイキスト周波数は1画素当たり0.5周期、つまり2画素で1周期です。
画像が持てる一番細かい模様は、白と黒の画素が交互に並ぶ物です。
其れより細かい物は保存出来ません。
エイリアシング
其れでもナイキスト周波数より高い周波数を標本化したらどうなるでしょうか?
単に消える訳ではありません。
低い周波数に化けて現れます。
別人の名前を名乗っている様な物です。
此れがエイリアシングで、偽の周波数をエイリアスと言います。
青い波は1標本当たり0.8周期で、ナイキスト周波数0.5を大きく超えています。
残るのは黄色の標本だけで、其れらは1標本当たり0.2周期しかないオレンジの波の上にぴったり乗っています。
標本だけからは、誰も2つを区別出来ません。
一般に、標本化周波数 で標本化した周波数 は、 以下になる様に整数 を選んだ に見えます。
此処では です。
標本を1つ確かめてみましょう。
で 、 です。
画像とアニメーションでは、エイリアシングは3つの有名な姿で現れます。
ジャギー:斜めの輪郭は、いくらでも高い周波数を含みます(急な段差だからです)。
1画素に1標本で標本化すると、滑らかな線が階段になります:
モアレ:細かい規則的な模様を粗く標本化すると、大きな、間違った模様になります。
左の図は「ゾーンプレート」で、外側に行く程細かくなる輪です。
中央は其れを48 × 48画素、1画素に1標本で標本化した物です。
輪が2画素より細かい所では、元の画像には無い全く新しい輪が現れています。
右は各画素で8 × 8個の標本を平均した物です(2.7節)。
細か過ぎる輪は殆ど一様な灰色になり、此れが正直な答えです。
テレビ画面、縞のシャツ、フェンスを撮った写真や、ゲームで遠くのフェンスや床のタイルがちらつくのを見た事があるでしょう。
其れがモアレです。
時間方向のエイリアシング:フレームは時間の標本なので、速い動きもエイリアシングを起こします。
古典的な例がワゴンホイール効果で、映画で車輪が止まって見えたり、逆回転して見えたりする現象です。
計算例。
同じ形のスポークが8本ある車輪は、 毎に同じに見えます。
毎秒24フレームで、1フレームに 回るとします(1秒で 、2.67回転)。
1フレーム後、前にスポークがあった位置に一番近いのは のスポークです。
目は一番近いスポーク同士を対応させるので、車輪は1フレームに 、1秒に 逆回転している様に見えます。
2.7 アンチエイリアシング
エイリアシングを減らす技術をアンチエイリアシングと言います。
標本化定理によれば、正直な方法は2つしかありません:
- 標本化の前に高過ぎる周波数を取り除く。そうすればエイリアシングを起こす物が残りません。
- もっと頻繁に標本化する。ナイキスト周波数が上がります。
本物のカメラは1つ目をハードウェアで行います。
多くのセンサーの前には光学ローパスフィルターがあり、フォトサイトが標本化する前に画像を少しだけぼかして、正にモアレを防いでいます。
CGでは此れをソフトウェアで行わなければなりません。
点サンプリング・エリアサンプリング・スーパーサンプリング
黄色の図形の輪郭が横切り、画素の左下の部分を覆っている1画素を考えます。
3つの方法は其の画素について次の様に計算します:
- 点サンプリングは画素の中心だけを見ます。中心は図形の外なので、画素は図形の色を0%受け取ります。輪郭が少し動くだけで100%に変わります。ジャギーの原因は此れです。
- エリアサンプリングは、画素の面積の内、図形が覆う割合を使います。覆われた部分は2辺が1と0.75の直角三角形なので、面積は です。
- スーパーサンプリングは画素の中で沢山の標本を取って平均します。4 × 4の格子なら16標本中6つが内側で、 です。
図形が黒地に白なら、画素は になり、8ビットでは です。
暗い灰色で、普通の距離から見ると輪郭が滑らかに見えます。
フィルタリングの言葉で言うと、エリアサンプリングはプリフィルタリングです。
1画素に1つの標本を取る前に、連続な画像を画素の面積で平均(ローパスフィルタ)します。
スーパーサンプリングはポストフィルタリングです。
先ず高い頻度で標本化し、其の後で標本をフィルタ(平均)して1画素1つの値にします。
等しい重みでの平均は一番単純なフィルタ、ボックスフィルタです。
レンダラーでは、隣の画素の標本にも少し重みを与える、もっと滑らかなフィルタ(テント、ガウス)も良く使います。
スーパーサンプリングの代償は速度です。
1画素に4 × 4標本なら作業は16倍で、1920 × 1080なら1フレームに 標本です。
其の為、GPUはMSAA等の安価な変種を使います(第6章の描画パイプラインで紹介し、第2部で掘り下げます。OpenGLシリーズの第20章では自分で有効にします)。
ゲームではポストプロセスのアンチエイリアシングも使います。
完成した画像の中から階段状の輪郭を探して滑らかにする方法です。
安価ですが、標本化で既に失われた細部を取り戻す事は出来ません(上の中央の図のモアレは直せません)。
時間方向のアンチエイリアシング
同じ2つの考え方は時間でも使えます。
時間方向のプリフィルタリングとは、シャッターが開いている間の平均、つまり正にモーションブラーです。
ちゃんとモーションブラーを付けて描いた車輪は、逆回転する代わりにぼけた円板になります。
毎秒24フレームの映画が滑らかに見えるのに、モーションブラー無しで毎秒24フレームのゲームがカクカクに見える理由の1つが此れです。
2.8 量子化の影響:疑似輪郭とディザリング
段階が少な過ぎると、別のアーティファクトが出ます。
滑らかなグラデーションが平らな帯の階段になり、帯と帯の間の段差が、シーンに無い輪郭に見えます。
此れが疑似輪郭で、バンディングとも言います。
同じ陰影の付いた球を2、4、8、256階調に量子化した物です:
8階調では、球が等高線図の様に見えます。
256階調なら、少なくとも此処では滑らかに見えます。
但し、256階調を幅1920画素のグラデーションに広げると、各段階は幅 画素の帯になります。
暗くて滑らかな場所(夜空、霧、影)では此の帯が見える事があります。
あたし達の視覚は平らな部分同士の境目を強調するからです(第3章のマッハバンドと同じ側抑制という仕組みです)。
HDR映像が10ビットを使う理由の1つです。
ディザリング
段階を増やせないなら、空間の解像度と引き換えにする事が出来ます。
ディザリングは、量子化の前にパターンやノイズを加え、各画素が白か黒だけでも、小さな範囲の平均が正しい明るさになる様にします:
- 組織的ディザ法は、各画素を小さな繰り返しの行列のしきい値と比べます。4 × 4のベイヤー行列(センサーとは関係無く、名前が同じだけです)では、16個のしきい値は に対して です。一様な灰色0.3は のしきい値を上回るので( ですが )、16画素中5画素が白になり、平均は です。
- 誤差拡散法(例えばFloyd–Steinberg法)は、各画素を丸め、其の丸め誤差をまだ処理していない隣の画素に(7/16、3/16、5/16、1/16の重みで)押し付けるので、誤差が範囲全体で打ち消し合います。
ディザリングは今でも至る所で使われています。
プリンター(インクが有るか無いかしか無い)、GIF画像、そして高品質なレンダリングでは、8ビットに変換する前に僅かなノイズを加えて、空や霧のバンディングを隠します。
次は、色を1チャンネル levels 段階に減らすシェーダー関数で、組織的ディザの有無を選べます:
static const float bayer4[16] = { 0.0, 8.0, 2.0, 10.0, 12.0, 4.0, 14.0, 6.0,
3.0, 11.0, 1.0, 9.0, 15.0, 7.0, 13.0, 5.0 };
// Round c to `levels` levels per channel. With dither, add an ordered-dither offset first.
float3 quantize(float3 c, float levels, uint2 pixel, bool dither) {
float offset = 0.0;
if (dither) {
offset = (bayer4[(pixel.y % 4) * 4 + (pixel.x % 4)] + 0.5) / 16.0 - 0.5;
}
return round(c * (levels - 1.0) + offset) / (levels - 1.0);
}const float bayer4[16] = float[16](0.0, 8.0, 2.0, 10.0, 12.0, 4.0, 14.0, 6.0,
3.0, 11.0, 1.0, 9.0, 15.0, 7.0, 13.0, 5.0);
// Round c to `levels` levels per channel. With dither, add an ordered-dither offset first.
vec3 quantize(vec3 c, float levels, uvec2 pixel, bool dither) {
float offset = 0.0;
if (dither) {
offset = (bayer4[(pixel.y % 4u) * 4u + (pixel.x % 4u)] + 0.5) / 16.0 - 0.5;
}
return round(c * (levels - 1.0) + offset) / (levels - 1.0);
}static const float bayer4[16] = { 0.0, 8.0, 2.0, 10.0, 12.0, 4.0, 14.0, 6.0,
3.0, 11.0, 1.0, 9.0, 15.0, 7.0, 13.0, 5.0 };
// Round c to `levels` levels per channel. With dither, add an ordered-dither offset first.
float3 quantize(float3 c, float levels, uint2 pixel, bool dither) {
float offset = 0.0;
if (dither) {
offset = (bayer4[(pixel.y % 4) * 4 + (pixel.x % 4)] + 0.5) / 16.0 - 0.5;
}
return round(c * (levels - 1.0) + offset) / (levels - 1.0);
}オフセットは常に1段階の−0.5から+0.5の間なので、結果は0から1の間に収まり、4 × 4のタイル全体で丸め誤差が平均されます。
2.9 ラスタ画像とベクタ画像
此処までの話は全てラスタ画像、つまり画素の格子についてでした。
絵を保存するもう1つの方法があります。
形を記述しておき、必要な時にコンピュータに描かせる方法です。
此れがベクタ画像です。
左のベクタの円は、3つの数値(中心のx、中心のy、半径)と色で保存されています。
右のラスタの円は144画素で、各画素は内側か外側のどちらかです。
中心が円の内側にある画素が塗られています。
| ラスタ画像 | ベクタ画像 | |
|---|---|---|
| 保存する物 | 画素の値 | 形:点、線、曲線、塗り |
| 拡大すると | ブロック状になるか、ぼやける | どんな大きさでもシャープなまま |
| 向いている物 | 写真、レンダリング画像、テクスチャ | ロゴ、フォント、図、UI、CAD図面 |
| 形式 | PNG、JPEG、GIF、BMP、TIFF、WebP、EXR | SVG、PDF、EPS |
此のシリーズの図は全てベクタ画像(SVG)で、今読んでいるフォントも曲線で出来たベクタのアウトラインです(曲線は第8章で扱います)。
但し、画面は画素しか表示出来ないので、ベクタ画像も最後には必ずラスタ画像に変換しなければなりません。
此の変換がラスタライズ又はスキャン変換で、GPUが三角形に対して行っている事其の物です(第6章)。
3DCGは3次元のベクタグラフィックスです。
モデルは形で、画像は其のラスタライズ結果です。
2.10 画像ファイル形式と圧縮
フルHDの1フレームは約6 MBでした。
圧縮は其れを小さくします。
方法は2通りです:
- 可逆圧縮:ファイルは小さくなりますが、展開すると元の画素が其のまま戻ります。
- 非可逆圧縮:一部の情報を永久に捨てます。理想的には、どうせ気付かない部分です。ファイルはずっと小さくなります。
可逆圧縮の小さな例がランレングス符号化です。
WWWWWWBBBWWWW(13画素)という行は「W 6個、B 3個、W 4個」と保存出来ます。
13個の代わりに6個の記号で済み、復号すれば全く同じ行が戻ります。
実際の形式はもっと賢い方法を使いますが、考え方は同じで、繰り返しを保存する代わりに繰り返しを記述します。
| 形式 | 圧縮 | 備考 |
|---|---|---|
| BMP | 普通は無し | 単純、ファイルが大きい |
| PNG | 可逆 | 1チャンネル16ビットまで、アルファ有り。スクリーンショット、UI、輪郭が鋭いテクスチャ |
| GIF | 可逆だが最大256色 | パレット画像、単純なアニメーション |
| JPEG | 非可逆 | 写真。アルファ無し |
| WebP、AVIF | 非可逆又は可逆 | 圧縮率の良い新しいウェブ用形式 |
| TIFF | 普通は可逆 | 印刷とスキャン、1チャンネルのビット数が多い |
| OpenEXR、Radiance HDR | 可逆又は非可逆、浮動小数点 | 映画やレンダリング用のHDR画像 |
GIFの落とし穴に注意して下さい。
圧縮自体は可逆ですが、フルカラーの写真は先ず256色に減らさなければならず、其処で情報が失われます。
JPEGが捨てる物
JPEGは此の章の考え方の上に作られているので、理解しておく価値があります:
- RGBをYCbCr、つまり明るさのチャンネルYと2つの色差チャンネルCb、Crに変換します(式は第3章)。
- 目は細部を主に明るさで見ていて、色ではあまり見ていません。其の為、色のチャンネルは低い解像度で保存します。此れがクロマサブサンプリングです。一般的な4:2:0では、2 × 2画素に1つのCbと1つのCrしか残さず、此れだけでデータが半分になります(具体的な数と他の方式は第3章で計算します)。
- 各チャンネルを8 × 8のブロックに分け、各ブロックをDCT(離散コサイン変換)で64個のコサインパターンの和に書き換えます。
- 各パターンの量を量子化します。高い周波数は粗く、低い周波数は細かく。高い周波数の量の多くは0になります。本当に情報が失われるのは此処で、「品質」の設定が其の粗さを決めます。
- 沢山の0は、普通の可逆符号化でとても良く圧縮出来ます。
次が64個のパターンです。
左上の平らな物から、右下の一番細かい市松模様まで並んでいます:
JPEGの典型的なアーティファクトは此処から直接説明出来ます。
品質が低いと見える8 × 8のブロックノイズ、高い周波数を削った鋭い輪郭の横に出るリンギング(薄い波紋、「モスキートノイズ」)、そして鋭い色の境目での色のにじみです。
其の為、文字、UI、ドット絵、法線マップはJPEGで保存すべきではありません。
予告:HDR画像
普段の使い方では、上の形式は(最後の行以外)0から1の値、つまり「画面が表示出来る範囲の明るさ」を保存します。
現実の世界の範囲は遥かに広く、太陽は影の何千倍も明るいです。
HDR画像(ハイダイナミックレンジ画像)は、本物の光の値を浮動小数点数で保存します。
例えばOpenEXRは1チャンネル16ビット又は32ビットの浮動小数点数です。
レンダラーは内部ではHDRで計算し、HDRを画面が表示出来る範囲に落とす段階がトーンマッピングです。
HDRには第15章と第2部で戻って来ます。
2.11 CGと画像処理
最後に、出題範囲の3つ目、CGと隣の分野の関係です。
何が入って何が出るかで3つの分野を区別する規則は、第1章で既に見ました。
CGはモデル → 画像(ディジタルカメラモデルです)、画像処理は画像 → 画像(第15章)、そしてコンピュータビジョンと画像認識は画像 → モデル又は記述です。
ビジョンはCGを逆に辿るので、「逆グラフィックス」と呼ばれる事もあります。
実際の仕事では、此れらは常に出会います:
- 写真からのテクスチャ:本物の表面の写真を、継ぎ目無く並ぶ様に加工してモデルに貼ります(第11章)。
- イメージベーストレンダリング:3Dモデルではなく写真から直接新しい視点の絵を計算したり、実在の場所のHDR写真をCGシーンの光として使ったりします(レンダリングの第11章と第12章)。
- 合成:CGと実写映像を組み合わせます。コンピュータビジョンが映像から本物のカメラの動きを追跡し(マッチムーブ)、CGのカメラが其れを正確に真似出来る様にして、画像処理がレイヤーを混ぜ合わせます(第14章)。
- 3Dスキャンとフォトグラメトリ:沢山の写真やスキャナーからモデルを復元し、其れをレンダリングします(第17章)。
- モーションキャプチャ:カメラで俳優のマーカーを追跡し、其の動きでCGキャラクターを動かします(第13章)。
- ゲームのポストプロセス:ブルーム、被写界深度、モーションブラー、トーンマッピング、アンチエイリアシングは、レンダリングしたフレームに毎フレーム掛ける画像処理です。
- コンピュテーショナルフォトグラフィ:スマートフォンは3つの分野を全て使って、沢山の写真を1枚にまとめます(HDR合成、夜景モード、背景ぼかし)(第16章)。
つまり、境界は壁ではありません。
検定の為には入出力の規則を、実践の為には現代のパイプラインが3つ全てを使う事を覚えておいて下さい。
検定のポイント
確実に区別出来る様にしておきたい点です:
- 標本化は位置を離散的にします(どこで測るか)。量子化は値を離散的にします(どれだけ細かく保存するか)。解像度は標本化に、階調数とビット深度は量子化に関係します。
- 標本化が粗過ぎるとエイリアシング(ジャギー、モアレ、ワゴンホイール効果)が起こります。階調が少な過ぎると疑似輪郭が出ます。混同しない様にしましょう。
- 標本化定理:最も高い周波数の2倍より大きい周波数で標本化します。ナイキスト周波数は標本化周波数の半分です。
- ビットで 階調:8ビットで256、24ビットカラーで16,777,216色。画像の大きさ = 幅 × 高さ × チャンネル数 × 1チャンネルのバイト数。
- アンチエイリアシング:エリアサンプリング = プリフィルタリング(フィルタしてから標本化)、スーパーサンプリング = ポストフィルタリング(細かく標本化してからフィルタ)。モーションブラーは時間方向のアンチエイリアシングです。
- :F値が大きい程絞りは小さく、光は少なく、被写界深度は深くなります。ピンホールカメラでは全てにピントが合います。
- 薄レンズ:、無限遠にピントを合わせると 。画角:、焦点距離が長い程画角は狭くなります。
- PNGとGIFは可逆(GIFは256色まで)、JPEGは非可逆(YCbCr、クロマサブサンプリング、8 × 8のDCT、量子化)。
- CG:モデル → 画像、画像処理:画像 → 画像、コンピュータビジョン・画像認識:画像 → モデル又は記述。
2.12 まとめ
- CGはディジタルカメラモデルとして捉えられます。モデリング、ライティング、レンダリング、画像処理、アニメーションが、被写体、照明、撮影、現像、カメラを動かす事に対応します。
- ピンホールカメラはシーンの全ての点を1点を通して投影します:。像は上下逆さまで、CGではピンホールの前に仮想の画像面を置きます。画角は 。
- 本物のレンズは に従います。F値 、シャッター速度、感度が露出を決め、被写界深度(錯乱円)、モーションブラー、ノイズをもたらします。レンズは歪みと周辺減光も起こします。CGは其れらを全て意図的に真似します。
- センサーはベイヤー配列の下のフォトサイトで光を測り、デモザイクで足りない色を補います。
- ディジタル画像は、連続な画像を標本化(位置 → 画素、解像度)し、量子化(値 → 階調)した物です。大きさ = 幅 × 高さ × チャンネル数 × バイト数。
- 標本化定理は を求めます。破るとエイリアシング(ジャギー、モアレ、ワゴンホイール)が起こります。アンチエイリアシングはプリフィルタリング(エリアサンプリング)するか、多く標本化してポストフィルタリング(スーパーサンプリング)します。時間方向ではモーションブラーが其の役目です。
- 階調が少な過ぎると疑似輪郭が出ます。ディザリングは解像度と引き換えに見かけの階調を増やします。
- ラスタ画像は画素を、ベクタ画像は形を保存し、ベクタ画像は表示する為にラスタライズが必要です。
- 可逆(PNG)と非可逆(JPEG)の圧縮。JPEGは色の細部と高い周波数を取り除きます。HDR画像は本物の光の値を保存します。
- CG(モデル → 画像)、画像処理(画像 → 画像)、コンピュータビジョン(画像 → モデル)は、テクスチャ、イメージベーストレンダリング、合成、スキャン、ポストプロセスで出会います。
2.13 用語
| 英語 | 日本語 |
|---|---|
| digital camera model | ディジタルカメラモデル |
| pinhole camera | ピンホールカメラ |
| focal length | 焦点距離 |
| angle of view / field of view | 画角/視野角 |
| thin lens | 薄レンズ |
| aperture | 絞り |
| f-number | F値 |
| depth of field | 被写界深度 |
| circle of confusion | 錯乱円 |
| shutter speed | シャッター速度 |
| motion blur | モーションブラー |
| exposure | 露出 |
| lens distortion (barrel, pincushion) | 歪曲収差(樽型、糸巻き型) |
| vignetting | 周辺減光 |
| image sensor | 撮像素子 |
| Bayer filter | ベイヤー配列 |
| demosaicing | デモザイク |
| digital image | ディジタル画像 |
| sampling | 標本化 |
| quantization | 量子化 |
| pixel | 画素(ピクセル) |
| resolution | 解像度 |
| aspect ratio | アスペクト比 |
| bit depth | ビット深度 |
| number of gray levels | 階調数 |
| grayscale image | 濃淡画像(グレースケール画像) |
| channel / alpha | チャンネル/アルファ |
| sampling theorem | 標本化定理 |
| Nyquist frequency | ナイキスト周波数 |
| aliasing | エイリアシング |
| jaggies | ジャギー |
| moiré | モアレ |
| anti-aliasing | アンチエイリアシング |
| supersampling | スーパーサンプリング |
| area sampling | エリアサンプリング |
| false contour | 疑似輪郭 |
| dithering | ディザリング |
| raster image / vector image | ラスタ画像/ベクタ画像 |
| lossless / lossy compression | 可逆圧縮/非可逆圧縮 |
| image processing | 画像処理 |
| computer vision / image recognition | コンピュータビジョン/画像認識 |
| image-based rendering | イメージベーストレンダリング |
2.14 課題
- ★ 幅36 mmのセンサーと35 mmのレンズのカメラがあります。水平画角を度で求めて下さい(小数点以下1桁)。
- ★ mmの薄レンズで3 m先の被写体にピントを合わせます。センサーはレンズの後ろどれだけの所にあり、倍率 は幾らですか?
- ★ 1チャンネル8ビットで3840 × 2160のRGBA画像を非圧縮で保存すると何バイト必要ですか?又、其の様なフレームを毎秒30フレームで10秒分保存すると何バイトですか?
- ★ 0.1、0.45、0.8を で4階調(2ビット)に量子化し、其れぞれの誤差を求めて下さい。どれも半段階を超えない事を確かめて下さい。
- ★★ 1.6画素毎に繰り返す縞模様を、1画素に1回点サンプリングします。画像にはどの周波数(1画素当たりの周期数)が現れ、其のエイリアスの1周期は何画素ですか?
- ★★ 同じ形のスポークが8本ある車輪を毎秒24フレームで撮影します。どの回転速度(1秒当たりの回転数)の時に止まって見えますか?遅い方から3つ答えて下さい。
- ★★★ ピンホールのCGカメラでは何故被写界深度が全く出ないのか、其れを得るにはレンダラーに何を加えなければならないか、そして本物のピンホールカメラの穴をどこまでも小さくしても、像がどこまでもシャープにならないのは何故かを説明して下さい。
選択問題
問1 ★ 次のうち、ディジタル画像の量子化について正しく説明している物はどれか。
| あ | 連続な画像を測定する位置を決める事 |
| い | 各フォトサイトの足りない色を周りから推定する事 |
| う | 高い周波数を取り除いてファイルサイズを小さくする事 |
| え | 測定した各値を有限個の段階の何れかに丸める事 |
| お | 各画素の中の幾つかの標本を平均する事 |
問2 ★★ 或る音声信号は15 kHzまでの周波数を含む。エイリアシング無しで復元出来る標本化周波数はどれか。
| あ | 40 kHz |
| い | 25 kHz |
| う | 20 kHz |
| え | 15 kHz |
| お | 10 kHz |
問3 ★★ 他の条件を全て変えずに、カメラの被写界深度を深くする変更はどれか。
| あ | 絞りを開く(F値を小さくする) |
| い | 焦点距離の長いレンズに替える |
| う | シャッター速度を遅くする(露光時間を長くする) |
| え | 同じ絞りでISO感度を上げる |
| お | 絞りを絞る(F値を大きくする) |
2.15 実践課題
自分がカメラになる。
此の課題では、1枚の「写真」を完全に手で撮ります。
カメラを設計し、図形を標本化し、アンチエイリアシングし、量子化し、ファイルの大きさを計算します。
必要な物は方眼紙(5 mm方眼が理想)、定規、分度器、鉛筆、電卓です。
パートA:カメラ。
- 手順1:幅36 mmのセンサーについて、、50、100 mmの水平画角を で計算します。
- 手順2:各カメラを横から見た図を縮尺通りに描きます(1 mm = 1 mm、又は方眼1マス = 2 mm)。ピンホールを点で、センサーを距離 の所に36 mmの線で描き、両端からピンホールを通る2本の光線を反対側まで延ばします。
- 手順3:分度器で光線の間の角度を測ります。
確認:測った角度は計算した角度と約1°以内で一致し、「焦点距離が短い程画角が広い」順になっている筈です。
パートB:標本化とアンチエイリアシング。
- 手順4:8 × 8画素の格子を描きます。1画素を方眼4 × 4マスにします(全体で32 × 32マス)。画素単位で、原点を左上の角、yを下向きにします。
- 手順5:頂点が 、、(画素単位)の三角形を、尖った鉛筆と定規で描きます。
- 手順6:点サンプリング:全ての画素の中心に印を付け、中心が三角形の内側にある画素を塗ります。其の数を数えます。
- 手順7:スーパーサンプリング:各画素で、16個の小さなマスの中心(4 × 4の標本の格子)を調べ、三角形の内側にある数(0〜16)を画素に書き込みます。
- 手順8:三角形の正確な面積を、靴紐公式 で計算します。
確認:全ての数の合計を16で割った値が、スーパーサンプリングによる面積の推定値です。
此の三角形では、手順8の面積とちょうど等しくなる筈です(辺の上にちょうど乗る標本はありません)。
合わなければ、辺に沿った画素を確認し直して下さい。
其の後、点サンプリングの絵と数を比べてみましょう。
点サンプリングの絵のどこに階段があり、数がどの様に其れを和らげているでしょうか?
パートC:量子化と大きさ。
- 手順9:各画素の被覆率を で4階調(2ビット)に量子化し、4つの鉛筆の濃さ(0 = 白、3 = 一番濃い)で塗ります。
- 手順10:1画素2ビットで其の画像に何バイト必要か、そして24ビットカラー画像なら何バイト必要かを計算します。
確認:完全に覆われた画素(数が16)は必ず3に、空の画素は必ず0になり、2ビットの画像は24ビットの画像のちょうど1/12の大きさになる筈です。
最後に、紙を腕を伸ばした距離に持って、点サンプリングの三角形と4階調の三角形を比べてみて下さい。
アンチエイリアシングが自分の目で働いているのが分かります。
コメント(0)
まだコメントはありません。
ログインするとコメント出来ます。