1  デジタル画像基礎

レンズが光をセンサーの撮像面に集光した瞬間、「画像」はまだ連続した物理量である。像平面上の各点にはそれぞれ照度があり、輝度は任意の実数値を取りうる。一方、産業用コンピュータ上の画像処理プログラムが受け取るのは整数の行列である。前者から後者への変換の間に、カメラ内部では2つの離散化が行われる。サンプリング(標本化)——センサーの画素アレイが連続した像平面を有限個の格子点に分割し、画像が空間的に「どれだけ細かく見えるか」を決定する。量子化——アナログデジタルコンバータが各画素上の連続した電荷を有限段階の整数に圧縮し、画像がグレースケールで「どれだけ精細に分割されるか」を決定する。この2段階の処理により、それぞれ一部の情報が失われる。失われた情報が無視できる場合と、視覚システム全体を破壊する可能性がある場合の違いが、本章で解明すべき課題である。

2種類の離散化の影響を肉眼で確認できるように、本章では480×360の8ビットグレースケールテストシーンを作成した(図 1.1)。水平方向に40から160まで線形に変化するグラデーション背景とランバート(Lambert)球面は、量子化に最も敏感な滑らかで連続したグレースケールを提供する。入れ子になった階調矩形(暗い輝度20の内側に明るい輝度235の矩形)は急峻なエッジを提供する。幅がそれぞれ1、2、3画素の縦線グループと、周波数が左から右に連続的に上昇するチャープ(chirp)縞帯は、サンプリングに最も敏感な微細構造を提供する。以降のすべての実験図はcode/digital_images/下のプログラムによって実際に生成されている。

図 1.1: ベースラインテストシーン(480×360、8ビット)。左上:暗い矩形に明るい矩形が埋め込まれた(階段エッジ);右上:ランバート球面(連続したグレースケール曲面);背景は40→160の水平グラデーション;左下:幅1/2/3 pxの縦線グループ;下部:周波数が右に向かって増加するチャープ縞帯。

1.1 画像を2次元信号として扱う

レンズがセンサー上に投影した連続画像を\(f_c(x, y)\)と記す。サンプリングにより、整数格子上でのみ定義される離散画像に変換される。

\[ f[n, m] = f_c(m \Delta_x,\ n \Delta_y), \]

ここで\(n\)は行インデックス(下向きに増加)、\(m\)は列インデックス(右向きに増加)、\(\Delta_x, \Delta_y\)はサンプリング間隔——物理的には画素のピッチである。量子化により、各\(f[n,m]\)の値は有限段階の整数に制限される。こうしてデジタル画像は最終的に整数の行列となり、本章のテストシーンは正確に360行×480列である。

ここから3つの最も基本的な指標が導かれる。解像度はサンプリング格子の規模、すなわち画像の縦横の画素数であり、空間的な詳細の上限を決定する。ビット深度は各画素を表現するために使用するビット数であり、グレースケールの段数を決定する——8ビットは\(2^8 = 256\)段階に対応し、産業用カメラの最も一般的な出力フォーマットである。ダイナミックレンジはセンサーが同時に記録できる最も明るい信号と最も暗い信号の比であり、ビット深度はこの範囲を表現するために何段階に分割するかを決定する。これら3つは互いに独立している:高解像度が高ビット深度を意味するわけではなく、ビット深度が高くてもセンサーが実際にそれだけ多くの有効なグレースケール段階を弁別できるわけではない。

産業用カメラの一般的なビット深度は8/10/12ビットである。多くの位置決め、検査タスクでは8ビットで十分である;しかし、アルゴリズムがグレースケール値を物理量として使用する場合——例えば照度差ステレオ(チャプター 34)による明暗からの表面法線の復元、バックライト(透過照明)の輝度均一性測定など——では、8ビットの256段階では不十分なことが多く、10ビットさらには12ビットの出力が必要となる。

1.2 量子化

256段階のグレースケールを\(L\)段階に再量子化するルールは単純である:ステップサイズ\(\Delta = 256 / L\)でグレースケール軸を\(L\)個の区間に分割し、画素値が第\(q\)番目の区間にあればレベル\(q\)と記録する:

\[ q[n, m] = \left\lfloor \frac{f[n, m]}{\Delta} \right\rfloor, \qquad \Delta = \frac{256}{L}. \]

量子化によって導入される誤差は最大でもステップの半分、すなわち\(\pm\Delta/2\)であり、各区間内でほぼ均一に分布する——これを画像に重畳された均一ノイズの一種と見なすことができる。これは@sec-spatial_filtering で議論するセンサーノイズと同じ「グレースケール値が摂動を受ける」カテゴリに属するが、これは自身のデジタル化によって決定され、平均化によって除去することはできない。\(L\)が小さいほどステップが大きくなり、この「ノイズ」が強くなる。図 1.2 は同じシーンを16段階(4ビット、ステップ16)、4段階(2ビット、ステップ64)、2段階(1ビット、ステップ128)に量子化した結果を示している。

(a) 16段階(4ビット)
(b) 4段階(2ビット)
(c) 2段階(1ビット)
図 1.2: グレースケール量子化実験。(a) 16段階:グラデーション背景に縦帯が現れ、球面に同心円が現れるが、矩形のエッジと縦線グループはほとんど影響を受けない;(b) 4段階:強いポスタリゼーションが発生し、画像は4段階のグレースケールしか残らない;(c) 2段階:白黒の二値になり、球面と右側の明るい背景が融合し、球の輪郭は細い輪郭線に縮小する。

量子化の影響が最初に現れるのはエッジではなく、滑らかなグラデーション領域である。図 1.2 (a) では、グラデーション背景にはっきりとした縦方向の帯状アーティファクト(バンディング)が現れ、球面は同心円に変化する。理由は簡単に理解できる:背景は480列にわたって40から160まで上昇するため、隣接する画素間のグレースケール値の差は量子化ステップの16よりはるかに小さい。このため連続した傾斜は一定グレースケールの階段状の平坦部に切断され、各平坦部の境界で完全なステップ分の跳躍が発生する——人間の眼は大面積のグレースケール段差に非常に敏感であるため、バンディングは明確に識別できる。球面は同じ現象の2次元版であり、一定グレースケールの平坦部がリング状になるため、同心円となる。さらに4段階に圧縮すると(図 1.2 (b))、画像全体が4段階のグレースケールに縮小され、典型的なポスタリゼーションが現れる。2段階になると(図 1.2 (c))、単一の閾値しか残らない:球面の大部分と右側の明るい背景は両方とも「白」に割り当てられて融合し、物体としての球の形状情報は本質的に失われる。

逆に矩形と縦線グループを見ると:4段階の量子化まで、それらは鮮明な輪郭を維持している。階段エッジを挟んだグレースケール値の差(20対235)はステップサイズよりはるかに大きいため、量子化がどのように分割点を設定してもそのコントラストを消すことはできない;背景に対する細い明るい線(245)についても同様である。エッジと微細構造は量子化に対して鈍感であり、滑らかなグラデーション領域が最も敏感である——この結論はエンジニアリングにおけるビット深度の選定に直接対応する:エッジ検出、位置決め、有無判定を中心とする検査タスクは高コントラスト構造に関心があるため、8ビットでほぼ常に十分である;緩やかなグレースケール変化から情報を読み取る必要のある測定系、照度系のタスクのみが、高ビット深度の費用対効果を正当化する。

1.3 サンプリングとエイリアシングの基礎

量子化はグレースケール値を失うのに対し、サンプリングは空間的な詳細を失う。直感的な基準は:周期的な構造を分解するには、各周期に少なくとも2つのサンプリング点が必要である——明るい半分と暗い半分にそれぞれ1つずつのサンプリング点があれば、構造が格子の隙間をすり抜けることはない。これはサンプリング定理の直感的な版であり、厳密な周波数領域での記述は@sec-fourier に譲る。構造がこの限界より微細な場合、単純に消滅するのではなく、存在しない粗い構造に偽装する——この現象をエイリアシング(折返し歪み)と呼ぶ。

実験ではシーンに空間的なアンダーサンプリングを施す:4個(または8個)に1個の画素を残し、一切のプレフィルタリングを行わず、比較のために画素複製で元のサイズに拡大する。等価な解像度はそれぞれ120×90と60×45である。結果を@fig-di-sample に示す。

(a) 1/4サンプリング(等価120×90)
(b) 1/8サンプリング(等価60×45)
図 1.3: 空間的アンダーサンプリング実験(プレフィルタリングなし;画素複製により元のサイズに拡大)。(a) 1/4サンプリング:1 pxと2 pxの縦線グループは消滅するか太い線に融合し、チャープ帯の右側の密な縞は疎な偽の太い縞に折り返される(エイリアシング);(b) 1/8サンプリング:画像全体が深刻なピクセル化を起こし、縦線グループは散在するパッチに退化し、球のエッジには明瞭なギザギザが現れる。

図 1.3 (a) では、2種類の微細構造は異なる運命をたどるが、いずれも同様に悪い結果となる。1 pxの縦線グループの周期はわずか2 pxであり、4 pxのサンプリング間隔で分解できる限界をはるかに下回る:サンプリング点が線上にあれば線は「存在」し、隙間にあれば線は消滅する。その結果、元の整然とした6本の細い線は消えてなくなるか、1本の太い線に融合する——これを解像度ターゲットとして使用した読者は完全に誤った結論に達するだろう。チャープ帯はさらに欺瞞的である:その真の周波数は右に向かって単調に上昇するが、アンダーサンプリングされた画像では、右側で最も密になるはずの縞がゆっくりと変動する太い縞に変化している。この「偽の低周波」はエイリアシングの典型的な姿である——サンプリング限界を超えた高周波構造が折り返され、低周波に擬態する。危険な点は、結果が完全に正常に見えることである:画像はぼやけているのではなく、単に内容が誤っており、事後的にアンダーサンプリングされたデータから元の内容を復元することはできない。図 1.3 (b) の1/8サンプリングは破壊を極限まで押し進める:縦線グループはほぼ完全に消滅し、画像全体は強いモザイク状のピクセル化となり、球の輪郭さえギザギザになる。

産業用レンズとカメラの選定における「画素分解能は最小欠陥サイズの少なくとも半分にすべき」(すなわち、最小欠陥は≥2画素をカバーする)という経験則は、「1周期あたり2サンプル」の基準に直接由来する:欠陥が少なくとも2画素をカバーして初めて、格子上のどの位置にあっても検出可能な痕跡を残すことが保証される。実際にはSNRの余裕を持たせるため、さらに3~5画素に緩和されることが多い。

本実験が意図的にプレフィルタリングを省略していることを強調しておく価値がある。実際のカメラでは、レンズのぼやけと各画素の面積積分が天然のローパスプレフィルタとして作用し、画素がサンプリングする前にサンプリング限界を超える詳細を減衰させるため、エイリアシングは部分的に抑制される。既存のデジタル画像を「k個ごとに1個の画素を取る」間引きによって縮小する場合には、このような保護は一切存在しない——これがまさにエンジニアリングにおける「縮小前に平滑化せよ」のルールの理由である。体系的な処理方法は@sec-fourier に記述する。

1.4 カラー画像とチャネル

カラー画像は構造的に新しい要素は何も含まない:RGB画像は単に同じサイズの3枚のグレースケール画像——赤、緑、青の3つのチャネル——を重ね合わせたものである。図 1.4 の合成シーンは各チャネルごとに描画されている:青チャネルは上から下に60→220の垂直グラデーション背景、緑チャネルは輝度200の矩形、赤チャネルは輝度220の円板である。円板と矩形の重なり領域では赤と緑が両方とも明るく、加法混合により黄色に見える;3つのチャネルを個別に取り出すと、それぞれが通常のグレースケール画像となる。

(a) カラー合成シーン
(b) Rチャネル
(c) Gチャネル
(d) Bチャネル
図 1.4: カラー画像とそのチャネル分解。(a) 青のグラデーション背景上の赤い円板と緑の矩形、重なり領域は黄色に見える;(b) Rチャネルは円板のみを含む;(c) Gチャネルは矩形のみを含む;(d) Bチャネルはグラデーション背景であり、円板と矩形の占める領域は0(黒い穴)となる。

3つのチャネルをメモリ上に配置する方法には2つの方式がある。インターリーブ(交番)格納は各画素の3つの成分を連続して配置し、画素ごとに並べるため、1行のバイト数は幅の3倍となる;プレーナ(平面)格納は各チャネルをそれぞれ1つの連続したグレースケールブロックとして保存し、3つのブロックを順番に並べる。インターリーブフォーマットは「1画素の完全な色」を取り出すのに便利であり、カメラ出力とほとんどの画像ライブラリのデフォルトである;プレーナフォーマットは単一のチャネルに対して全体的な演算を行うのに便利である。

インターリーブ格納にはもう1つ注意すべき詳細がある:3つの成分の順序である。本書全体で使用するSciVision SDKでは、3チャネルSciImageのインターリーブ順序はBGR(0バイト目が青)である——これはOpenCVのデフォルトの規約と同じであり、「RGB」の文字通りの順序とは逆である。これはSDKのヘッダーファイルには記載されておらず、プローブ実験により実測で確認したものである。本章のカラーシーンを最初に生成したとき、円板が青になり背景が赤になった——これはチャネル順序の仮定が誤っている典型的な症状である。チャネル順序を逆にしてもエラーは発生せず、クラッシュもせず、画像は「正常」に見える——単に赤と青が入れ替わるだけ——であるため、色に依存する選別アルゴリズムにとっては致命的である。

プローブ検証法:単一のチャネルのみが非ゼロの画像を作成し(例えば0バイト目のみに書き込む)、保存した後、チャネル順序が既知のツール(OpenCVや任意の画像ビューワ)で開いて表示される色を確認すれば、ドキュメントに記載のないSDKがRGBとBGRのいずれを使用しているかを確定できる。1回の実験が、いかなる推測にも勝る。

最後に「カラーを使用するかどうか」の選択について。色が運ぶ情報は人間の眼には直感的であるが、アルゴリズムにとっては3倍のデータ量と帯域幅を意味する。ほとんどの産業タスク——エッジ検出、位置決め、寸法測定、欠陥検出——は色相ではなく輝度構造に依存するため、グレースケールカメラと適切な照明の組み合わせが通常最適解である;カラーが真に代替不可能なのは、目標間に色の違いしかないタスクであり、例えば抵抗のカラーコード認識、カラーケーブルの選別、印刷物の色差検査などである。カラーカメラを使用した場合でも、多くのアルゴリズムの最初のステップは、最もコントラストの良いチャネルを1つ選んでグレースケール画像として使用することである。

1.5 画像データ構造とSciVision

本章の実験におけるすべての画像は、メモリバッファ上でSciImageを介して構築されている。グレースケール画像とカラー画像の構築文はそれぞれ以下の通りである(code/digital_images/main.cppから抜粋):

SciImage img(copy.data(), W, H, W, 1, SCI_IMAGE_8U);        // グレースケール:step = W
SciImage color(inter.data(), W * 3, H, W, 3, SCI_IMAGE_8U); // カラー:step = W*3

コンストラクタの完全なシグネチャはSciImage(unsigned char* data, int step, int rows, int cols, int channel, SciImageType depth)であり、6つのパラメータを1つずつ説明する:

  • data:画素バッファの先頭アドレス。SciImageはデータをコピーしないため、バッファのライフタイムは画像オブジェクトの使用期間全体をカバーしなければならない。
  • step1行あたりのバイト数(ラインストライド)。これは「1行あたりの画素数」ではない——1チャネル8ビット画像では偶然にも幅Wに等しくなるが、3チャネル画像ではW * 3となる;バッファの各行の末尾にアライメント用のパディングバイトがある場合は、stepにはパディングも含める必要がある。ライブラリ間で画像を受け渡す際にエラーが発生した場合、十中八九はstepの誤りである。
  • rowscols:画像の行数(高さH)と列数(幅W)。コンストラクタの引数の順序は、step、rows、colsの順であることに注意。
  • channel:チャネル数——グレースケールは1、カラーは3;3チャネルの場合、データはBGR順にインターリーブされる(前節の実測で確認された事実)。書き込みコードは以下の通り:
for (int i = 0; i < W * H; ++i) {       // BGRインターリーブ(SDKの順序、プローブで検証済み)
    inter[i * 3 + 0] = cb[i];
    inter[i * 3 + 1] = cg[i];
    inter[i * 3 + 2] = cr[i];
}
  • depth:画素タイプの列挙型(SciDataDef.hで定義)。SCI_IMAGE_8U = 0はチャネルあたり8ビット符号なし整数を意味し、本章全体で議論してきた8ビット画像に対応する;より高いビット深度のデータは同じ列挙型の他の値に対応する。

SciImageと対になるもう1つのコア構造はSciROI——関心領域(region of interest, ROI)である。生産ラインの画像では、実際に処理が必要なのは通常小さな一部のみである;アルゴリズムをROI内に制限することで時間を節約できるだけでなく、無関係な干渉を回避できるため、本書の以降のほぼすべての章のアルゴリズムインタフェースにはROIパラメータが含まれている。ワークの実際の位置から動的にROIを生成する方法(位置補正)については、チャプター 19 で詳述する。

本章のすべての実験画像を生成する完全な実行可能プロジェクトはcode/digital_images/に配置されている;読者は量子化段数とサンプリング間隔を変更して、結果を自身で再現することができる。

工業ケース:8ビットか12ビットか?

バックライトパネルの輝度均一性測定プロジェクトで、当初8ビットカメラが選定された。パネルの周辺減光領域ではグレースケール値がすべて十数段階の階調に集中しており、隣接する階調の変化だけで測定レンジの数パーセントが消費され、輝度計算の分解能は要求仕様を大幅に下回り、繰り返し測定のデータも収束しなかった。12ビットカメラに交換したところ、同じ暗部で16倍の階調数が得られ、測定分解能は直ちに仕様を満たし、問題は解決した。ただし代償も現実のものである:12ビットの画素は1.5倍の記憶容量と伝送帯域を必要とし、カメラのフレームレートはそれに応じて低下し、ライン全体の画像バッファも再計算しなければならなかった。事後検証の結論は以下の通りである:検査系タスクで高位深度を盲目的に採用するのは純粋な無駄であり、ビット深度は「高ければ高いほど良い」という原則ではなく、タスクのグレースケール分解能に対する要求に応じて選択すべきである。

1.6 小結

  • デジタル画像 = 標本化 + 量子化:標本化は空間分解能を、量子化はグレースケール数(ビット深度)を決定する。両者は独立して情報を損失し、損失後はいずれも回復不可能である。
  • 量子化は最初に平滑な勾配領域に影響を与える(バンディング、同心輪)一方、階段状エッジや高コントラストの微細構造にはほとんど影響を与えない。検査系タスクでは通常8ビットで十分であり、グレースケール値を物理量として使用する測定系・測光系タスクでのみ10/12ビットが必要となる。
  • 微細構造には1周期あたり少なくとも2つの標本点が必要である。信号が不十分に標本化された場合、限界を超えた高周波は消失せず、見分けのつかない偽の低周波構造にエリアシング(折り返し歪み)として現れ、事後的に修復することはできない。縮小前には平滑化を行い、ハードウェア選定時には最小の欠陥が少なくとも2画素を覆うことを保証すること。
  • カラー画像は3枚のグレースケール画像である。インターリーブ(交错)記憶の場合、必ずチャネル順序を確認すること:SciVisionの3チャネルSciImageは実測でBGRであり、ヘッダーには記載がない。いかなるSDKと接続する場合でも、1回のプローブ実験は推測に勝る。
  • SciImagestepは1行あたりのバイト数であり、画素数ではない。多チャネルと行アライメントの両方により、その値は幅の値からずれるため、ライブラリ間で画像を受け渡す際の最も一般的な失敗点となる。

標本化、量子化、および色空間に関する体系的な解説は(Gonzalez と Woods 2018)に記載されており、特に測色と各種色モデルの扱いが充実している。画像形成とデジタル化プロセスの現代的な視点は(Szeliski 2022)を参照できる。標本化定理の「1周期あたり少なくとも2つの標本点」の厳密な出典はShannonの基礎的な論文(Shannon 1949)である。画像取得、センサ特性、および産業用カメラのデジタル化経路に関するより工学寄りの解説については、Stegerらの著作(Steger, Ulrich, と Wiedemann 2018)をさらに参照できる。