38  点群の前処理

線レーザプロファイルメータや構造化光カメラを金属ワークピースに向け、取得ボタンを押しても、得られるのが整ったきれいな3次元曲面になることは決してない。生データには3種類の不具合が混在している。各サンプル点の高さ値がランダムに変動する(2次元画像のノイズと起源は同じだが、今回は輝度ではなくZ値が変動する)。表面には「ブラックホール」のパッチが散在している——レーザが急峻な壁、深い穴、鏡面反射部に当たって戻ってこないため、これらのサンプル点は高さ値を取得できず無効ピクセル(invalid pixel)となる。さらに、真の表面から数百マイクロメートル突出した孤立した「スパイク」が時折出現するが、これは2次反射や異常なマッチングによって残されたアーチファクトである。同時に、1フレームの距離画像(range image)は数十万から数百万点に容易に達し、これを直接位置合わせやマッチングに入力すると計算量が瞬時に爆発する。ノイズがあり、穴だらけで、密度が高すぎる——これが下流の計測と検査が対処しなければならない原料である。点群の前処理(point cloud preprocessing)は計測前の最初の工程であり、その内容はPart IIIの2次元画像強調と1対1に対応する。すなわちノイズ除去、穴埋め、ダウンサンプリング、セグメンテーションであり、戦場がグレースケール画像から3次元表面に移っただけである。本章は2次元強調の3次元版とみなすことができる。

図 38.1 は本章全体を通して用いる合成シーンである。320×240=76800ピクセルの距離画像で、ベース高さは1000μm、x方向に緩やかな勾配があり、+400μmの凸台と-300μmの溝が配置されている。これにσ=5μmの高さ方向ガウスノイズ、5%の無効ピクセル(合計3858個の無効点。図中の黒い斑点)、さらに245個のスパイク(図中の白い斑点)を重畳している。この1枚の画像に3種類の典型的な欠陥がすべて含まれており、以降の各節はこれを出発点とする。

図 38.1: 生の合成距離画像(2.5D高さマップ)。輝度は高さを符号化している。左上のベース面は暗く、凸台(中央の矩形)は明るく、溝(右側の縦縞)は最も暗い。散在する黒い斑点は5%の無効ピクセル、白い斑点は真の表面から突出した245個のスパイクである。

38.1 距離画像 vs 点群:どちらで処理するか

3次元データには2種類の保存方法があり、前処理はどちらでも実施できるが、コストと再利用性は大きく異なる。

1つ目は距離画像であり、デプスマップまたは2.5D高さマップとも呼ばれる。本質的には規則的な格子上の画像であり、各ピクセルは1つの高さ値(Z)を格納し、横座標と縦座標はピクセル位置によって暗黙的に与えられる(チャプター 37 )。最大の利点は「規則性」である——Part IIIのピクセル近傍に基づくすべての2次元アルゴリズム(メディアンフィルタ、ガウシアンフィルタ、モルフォロジー、閾値セグメンテーション)を、「輝度値」を「高さ」に置き換えるだけで、ほぼそのまま移植できる。2つ目は順序のない点群(point cloud)である。格子に依存しない離散的な\((X,Y,Z)\)の3つ組の集合であり、任意のトポロジー(距離画像では表現できないオーバーハング、側壁、多層構造を含む)を忠実に表現できる。ただし、近傍探索にkd木を必要とする代償として、各処理ステップが規則格子上よりも著しく低速になる。

経験則:単一視点、単層の表面(大半のインライン検査はこれに該当する)では距離画像での処理を優先する。成熟した2次元アルゴリズムを直接再利用でき、高速でメモリ消費も少ない。物体にオーバーハングがある場合、多視点の合成が必要な場合、またはトポロジーが複雑で格子で表現できない場合に限り、順序のない点群の世界に進む(チャプター 39 )。

まさにこの理由から、ほとんどのSDKの3次元前処理操作は距離画像上で実施され、本章の主な処理領域もここに設定されている。ただし、2次元の世界には存在しない落とし穴を最初に明らかにしておかなければならない。無効ピクセルを0として計算に含めてはならない。距離画像では、無効点はしばしば0(または何らかのセンチネル値)でマークされるが、これは「ここにデータがない」ことを意味し、「ここの高さが0である」ことを意味しない。もしフィルタがこれを高さ値0として平均に含めると、穴の隣の真の高さがこの偽の0によって大きく引き下げられ、ノイズ除去が逆に偽の溝を作り出す結果となる。そのため、3次元フィルタとモルフォロジーのすべてのステップはNaN認識(NaN-aware)でなければならない。すなわち、有効な近傍点のみを計算に含め、無効点は計算に寄与せず、汚染もされない。本章のすべての手書き演算子はこの規則に従っており、その効果を以降で繰り返し確認することになる。

38.2 3次元フィルタリング

ノイズ除去は前処理の最初のステップであり、その考え方は@sec-spatial_filtering と完全に共通している。高さマップ上の各点について近傍を取得し、適切な「平均化」を行ってランダムな変動を抑圧する。距離画像上で2つの古典的なフィルタを比較する——3×3のメディアンフィルタ(median filter)と3×3のガウシアンフィルタ(Gaussian filter)であり、いずれもNaN認識版として実装する。中心が無効な場合は無効のままとし、中心が有効な場合は近傍内の有効な高さのみを対象として、ソートして中央値を求める(メディアン)か、重み付き平均を計算する(ガウシアン)。

ノイズ除去の効果を測定するため、平坦なベース面の部分領域について、真値平面に対する高さの二乗平均平方根(RMS、単位μm)を求める。結果は以下の通りである。生データのRMSは32.09μmと非常に高い——この値はノイズの標準偏差である5μmをはるかに超えているが、これは245個のスパイクによって強く汚染されているためである。メディアンフィルタはRMSを2.28μmに抑え、ガウシアンフィルタは12.08μmにしか抑えられない。一方、メディアン後にガウシアンを適用する(メディアンでスパイクを除去し、ガウシアンでランダムノイズを平滑化する)と1.61μmとなり、全体で最良の結果となる。

この差の根源はスパイクにある。チャプター 6 で述べた教訓——メディアンは外れ値を除去し、ガウシアンは外れ値を拡散させる——が3次元でもそのまま再現される。残存するスパイク(|測定高さ−真値| > 200μmとなる有効点)を計数すると、元々245個あったものがメディアンフィルタ後には5個しか残らないのに対し、ガウシアンフィルタ後には14個が残っている。メディアンフィルタは各スパイクを局所的な外れ値として扱い、ソート後にリストの末尾に押しやられて出力に選ばれないため、きれいに除去される。一方、ガウシアンフィルタはスパイクの数百マイクロメートルの高さを周囲の近傍点に拡散させるため、スパイクが消えるのではなく、高さが低く幅の広い「膨らみ」になって残る——スパイクのエネルギーは消えておらず、単に塗り広げられただけである。図 38.2 に3つの結果を並べて示す。生画像の白いスパイクがメディアン結果では完全に消えているのに対し、ガウシアン結果では薄いハローのパッチになっていることが目で見て明らかである。

図 38.2: 3次元フィルタリングの3連比較:生(左、白い斑点がスパイク)|メディアン(中央、スパイクが除去されエッジが鮮明)|ガウシアン(右、スパイクが薄い膨らみに拡散され凸台のエッジがわずかにぼやけている)。同じデータに対し、「メディアンはスパイクを除去し、ガウシアンはスパイクを拡散させる」という対立が3次元高さマップで再現されている。

本節では等方性のガウシアン/メディアンフィルタを使用している。ノイズを抑圧しつつ凸台と溝の急峻な壁を保持したい場合は、エッジ保存(edge-preserving)型の3次元フィルタ——バイラテラルフィルタ(bilateral)またはガイデッドフィルタ(guided filter)——に切り替えることができる。これらは「高さが近い場合に限り平均に参加する」という基準を重み付けに導入しており、その機構は@sec-spatial_filtering のバイラテラルフィルタと同じ系統に由来する。

そのため、最終的な出力にはメディアン+ガウシアンの縦続接続を採用する(図 38.3)。最初のメディアン処理でスパイクと見逃される可能性のあるインパルスノイズを除去し、2番目のガウシアン処理で残存するランダムな変動をさらに平滑化する。この組み合わせにより、凸台と溝のエッジを保持しつつ、平坦領域のRMSを2μm未満に抑えることができ、後続の計測のためのきれいな基盤が整う。

図 38.3: メディアン+ガウシアンの縦続フィルタ後の距離画像:スパイクが除去されランダムノイズが平滑化されている。凸台と溝のエッジは鮮明なままである。無効ピクセル(黒い斑点)はまだ処理されておらず、次節のモルフォロジーに委ねられる。

38.3 3次元モルフォロジー:穴埋め

フィルタリングは「変動」と「スパイク」に対処したが、3858個のブラックホール——無効ピクセルはまだ穴のままである。穴埋めはモルフォロジー(morphology)の役割であり、その考え方は@sec-morphology の2次元モルフォロジーと共通している。閉演算(closing、膨張の後に収縮を行う)を用いて小さなサイズの穴を埋める。高さマップ上で、各無効ピクセルについて8近傍を調べ、有効な近傍点の数が閾値に達した場合にそれらの有効な近傍点の中央値で埋め、数回反復する——これは有効領域を穴の内部に数輪「成長」させ、孤立した小さな穴を徐々に閉じつつ、大きな連続した隙間には手をつけないことと等価である。

実験結果は極めて明確である。無効ピクセルは3858個から1個に減少した——閉演算によって3857個の小さな穴が埋められた(図 38.4)。5%の無効ピクセルの大半は1~3ピクセルの散在した穴であり、数回の閉演算ですべてを閉じることができる。

図 38.4: 穴埋めのためのモルフォロジー閉演算後の距離画像:元々散在していた黒い無効ピクセル(3858個)はほぼすべてが有効な近傍点の中央値で埋められ(残り1個)、表面が連続性を回復している。

なぜ「開」ではなく「閉」なのか?閉演算は前景(有効領域)内部の暗い穴を埋めるため、まさに埋めたい無効ピクセルに対応する。一方、開演算は小さな明るい点を消去するものであり、全く別の用途である。モルフォロジー演算子の選択は常に、「穴」と「スパイク」のどちらが消去したい対象であるかに依存する。

ただし、穴埋めは警戒して実施しなければならない。小さな穴は埋めてよいが、大きな穴を埋めると偽のデータになる。閉演算による穴埋めは周囲の有効点から補間するものであり、「この穴の下の表面は周囲と連続している」という暗黙の仮定に基づいている。数ピクセルの散在した穴については、この仮定は基本的に成立し、埋められた高さは十分に信頼できる。しかし、連続した大きな隙間——例えば深い溝や急峻な壁によってレーザが完全に遮られた死角——に遭遇した場合、周囲の高さから強引に補間することは、測定されなかった表面を作り出すことに等しい。これは@sec-laser_triangulation の「欠落は作り出すよりまし」というジレンマと同じ論理である。欠落そのものがしばしば情報(ここに深い構造がある、ここに異常な反射がある)を運んでおり、それを何も考えずに平らに埋めると、真の信号が消去されてしまう。そのため本節の閉演算では「有効な近傍点の数が閾値に達した場合に限り埋める」という制約を意図的に設け、小さな穴だけを埋めて大きな穴はそのままにしている——残った1個の無効点は、まさにこの抑制の現れである。

38.4 3次元サンプリング

ノイズ除去と穴埋めの後、表面はきれいになったが、点の数はまだ多すぎる。本節では「密度が高すぎる」問題に対処する。ボクセルグリッドダウンサンプリング(voxel grid downsampling)は点群のダウンサンプリングに最も一般的に用いられる手法である。3次元空間を辺の長さが固定された小さな立方体(ボクセル、voxel)に分割し、同じボクセルに入るすべての点を1つの代表点(通常は重心)で置き換えることで、点の密度を均一に薄める。利点は「空間的均一性」である——元の点群の密度が場所によって異なっても、出力の点間隔はボクセルの辺の長さによって均一に制約され、局所的に密度が高すぎることがない。

ボクセルの辺の長さを0.4mmとした場合、本章の距離画像の有効点は76799個から4901個に減少し、15.7倍の削減となった図 38.5)。重要な点は、この削減が構造にほとんど影響を与えないことである。平坦なベース面上の密な点はもともと高さが近く、同じバッチのボクセルに入るため、代表点に縮退しても情報はほとんど失われない。一方、凸台と溝のエッジは高さが異なるZボクセル層にまたがるため、点が保持され、エッジの密度が相対的に際立つ。図 38.5 ではこれが明確に見て取れる。平坦領域の点は疎であるのに対し、溝と凸台の輪郭線は密なままであり——構造情報が完全に保持されている。

図 38.5: ボクセルグリッドダウンサンプリングの結果(ボクセル辺長0.4mm):76799点が4901点に減少(15.7倍)。平坦領域の点は疎、構造のエッジ(溝、凸台の輪郭)の点は密であり、ダウンサンプリングは点数を大幅に削減しつつ構造を保持している。

ダウンサンプリングはボクセルだけではない。一様サンプリングは固定されたストライドでn点おきに取得する単純な手法だが、詳細を見逃す可能性がある。ボクセルサンプリングは空間格子ごとに代表点を取得し、密度が均一になる。曲率適応サンプリングは平坦領域を強く間引き、高曲率領域(エッジ、コーナー)に多くの点を残すため、最も点数を節約しつつ構造を最もよく保持するが、法線と曲率を事前に推定する必要があるという代償がある。3つの手法は「詳細を保持する必要があるか」「事前計算のコストを負担できるか」に応じて選択される。

なぜ3次元では必ずダウンサンプリングを行う必要があるのか?それは下流のアルゴリズムが点数に極めて敏感だからである。位置合わせ(チャプター 39 )のICPは各ラウンドですべての点の最近傍探索を行う必要があり、百万点規模の点群でICPや特徴マッチングを実行すると、1ラウンドごとに百万回のkd木クエリが発生し、数十ラウンド後には計算量が完全に爆発する。テンプレートマッチングや表面位置合わせも同様である。これらの重い処理を行う前に点数を1~2桁削減しておくことは、多くの場合「実行不能」を「リアルタイム」に変える重要なステップとなる。もちろんダウンサンプリングはシーンに依存する。位置決めや位置合わせでは、ダウンサンプリングした結果は高速かつ安定である。ただし、高精度な体積や寸法の計測を行う場合は、完全な解像度を使用すべきである——このトレードオフは次節の産業事例で再び登場する。

38.5 3次元閾値処理とセグメンテーション

前処理の最後のステップは多くの場合、「関心領域」を背景から分離し、後続の計測に渡すことである。最も単純で直接的な3次元セグメンテーションは高さ閾値処理(height thresholding)であり、その考え方は@sec-thresholding の2次元輝度閾値処理と全く同じである。高さの閾値を設定し、それを超えるものを目標、下回るものを背景と分類する。本章では「高さ > 1200μm」で凸台をベース面から分離する——ベース面は1000μm前後、凸台は400μm高く約1400μmであり、1200μmの線は両者の間にきれいに収まる。

結果はほぼ完璧である。セグメンテーションによって7197ピクセルが得られ、凸台の真値(GT)は7200ピクセルである。誤検出(FP)は0個、見落とし(FN)は3個で、交差結合比はIoU = 0.9996となった(図 38.6)。3個の見落としはすべて凸台のエッジにある——そこの高さは丁度閾値付近にあり、フィルタによってわずかに平滑化された後に閾値を下回ったものであり、許容可能な境界効果である。このような精度を達成できたのは、前節までの下準備の賜物である。まずフィルタによって大量の誤分類の原因となるスパイクが除去され、次に穴埋めによって凸台内部の背景と誤判定されるはずの穴が埋められたため、閾値セグメンテーションがこれほどきれいに実行できたのである。

図 38.6: 高さ閾値セグメンテーションの結果:高さ > 1200μmで分離された凸台がグレースケール高さベースマップ上に緑色で強調表示されている。セグメンテーション結果7197ピクセル vs 真値7200ピクセル、FP=0、FN=3、IoU=0.9996。

高さ閾値処理は3次元セグメンテーションの出発点に過ぎない。目標と背景の高さ差が明確でない場合、または分離したい領域が同一平面上にある場合は、より高度な手法が必要となる。領域成長(region growing)は法線または曲率の連続性によって隣接点をパッチにクラスタリングし、平面セグメンテーション(RANSAC平面フィッティング)は点群から平面プリミティブを1つずつ直接抽出する(チャプター 41 のプリミティブフィッティングと対応する)。ただし、「一段高い凸台/一段低い溝」という最も一般的な産業用目標に対しては、多くの場合1本の高さ閾値で十分であり、単純かつ信頼性が高い。

38.6 SciVision 実装

本章に対応するSciVision 3Dモジュールは、本機での実測における可用性が大きくばらつくため、実態を忠実に記録し、工学的なトレードオフの参考とする。

  • SciSv3DFilterMedian / Gaussian使用可能であり、かつNaN認識型である(無効ピクセルを正しくスキップする)。手書き実装の結果と一致する。
  • SciSv3DMorphologyClose(穴埋めのための閉演算)は使用可能である。
  • SciSv3DThreshold は本機では不活性である——ManualThreshold はリターンコード rc=0 を返すが出力が空であるため、セグメンテーションは自前で実装する必要がある。
  • SciSv3DSampling の距離画像に対する Sampling オーバーロードは失敗する(123403001を返す)。また、点群の VoxelSampling に切り替えても実行ごとに非決定的である(同一入力に対し3回の実行で4821/4821/0というドリフトが生じる)ため、信頼できない。

このため、本章の本線ではすべて手書きのNaN認識型かつ決定的な実装を用いて図と数値を生成し、SDKの各3Dモジュールは隔離されたサブプロセスにプローブとして配置し、そのリターンコードと可用性を傍証とする(本機の3Dモジュールは稀に0xC0000005のアクセス違反を発生させるため、メインフローを崩壊させないよう隔離する)。以下に最も重要な2つの手書きコードスニペットを示す。NaN認識型メディアンフィルタは、中心の画素が無効な場合は無効のままとし、有効な場合は有効な隣接点のみから中央値を算出する。

// 3x3 NaN 認識型メディアン:スパイクを抑圧しエッジを保存、無効点は演算に関与せず汚染もされない
for (int dy = -r; dy <= r; ++dy)
  for (int dx = -r; dx <= r; ++dx) {
    double v = h[(yy)*W + xx];
    if (valid(v)) w.push_back(v);   // 有効な隣接点のみを収集
  }
std::sort(w.begin(), w.end());
out[y*W + x] = w[w.size() / 2];     // 中央値

ボクセルグリッドダウンサンプリングは、\((X,Y,Z)\) を量子化してボクセルキーとし、各ボクセルに1つの代表点を保持する。

long long ix = floor(X / L), iy = floor(Y / L), iz = floor(Z / L);
long long key = (ix*100003LL + iy)*100003LL + iz;   // ボクセルキー
Vox& g = grid[key];                                 // 同一ボクセルに入る点を統合
if (g.n == 0) { g.rx = x; g.ry = y; }               // 最初の点を代表点とする
g.sx += X; g.sy += Y; g.sz += Z; ++g.n;

完全な実行可能プロジェクトは code/point_cloud_preprocessing/ に配置されている。読者はノイズ強度、ボクセルの辺長、セグメンテーション閾値を変更することで、すべての図と数値を自身で再現できる。

産業事例:3Dはんだペースト検査における穴とダウンサンプリング

SPI(はんだペースト印刷検査)では、3Dカメラを用いて各パッド上のはんだペーストの体積を測定する。はんだペーストの鏡面反射によりレーザーの反射光が取得できず、多数の無効ピクセルが残る——穴のあるデータを直接積分すると、穴は高さ0として扱われるため体積が系統的に過小評価され、「はんだ不足」の誤報が多発する。正しい手法は、まず形態学的閉演算で測定による穴を埋めてから積分することである。ただし穴埋めには鉄則がある:「測定による穴」のみを修復し、「プロセスによる穴」を埋めてはならない——はんだペーストが全く印刷されていない箇所(印刷漏れ)は真のプロセス欠陥であり、穴埋めアルゴリズムで埋めては絶対にならない。2種類の穴の区別は、サイズ、位置、周辺の形状を総合的に判定して行う。ダウンサンプリングについては、体積測定には精度を保つため全解像度が必要である一方、大きな基板上のパッド位置を特定する際にはダウンサンプリングした点群で十分高速かつ正確である。教訓は一言に尽きる:前処理のあらゆる段階で、「測定欠陥の修復」と「真の信号の消去」を区別しなければならない。

38.7 まとめ

本章の要点は以下の通り要約できる。

  • 前処理は2D強調の3D版に相当する。 ノイズ除去、穴埋め、ダウンサンプリング、セグメンテーションの4段階は、それぞれ空間フィルタリング、形態学、サンプリング、閾値処理に対応する——「濃度値」を「高さ」に置き換えれば、2Dの成熟したアルゴリズムの大半を距離画像に直接移植して再利用できる。
  • 無効ピクセルを0として演算に入力してはならない。 3Dのすべての演算子ステップはNaN認識型でなければならず、有効な隣接点のみを計算対象とする。そうしなければ、1つの穴が周囲の真の高さを偽の谷へと引き下げてしまう。
  • メディアンはスパイクを除去し、ガウシアンはスパイクを塗りつぶす。 チャプター 6 の教訓が3Dでも再現される:メディアンはスパイクを5個まで抑圧し(RMS 32.09→2.28μm)、ガウシアンはスパイクを隆起に塗りつぶす(14個が残留)。メディアン+ガウシアンのカスケードでは1.61μmを達成する。
  • 穴埋めでは測定欠陥と真の信号を区別しなければならない。 閉演算は小さな穴を埋めるのに非常に有効(3858→1)であるが、大面積の欠落を強制的に補間して埋めたものは偽のデータである——オクルージョン箇所における「偽データを作るより欠落のままが良い」と同じジレンマである。
  • ダウンサンプリングは3D処理が実行可能となる前提条件である。 ボクセルグリッドは76799点を4901点に削減(15.7倍)しつつ構造のエッジを保持する。百万点規模のICP/マッチングは事前にダウンサンプリングしなければ処理が破綻するが、高精度測定には依然として全解像度が必要である。

産業検査における3Dデータのフィルタリング、形態学、セグメンテーションについてより体系的な解説は、Stegerらの著作(Steger, Ulrich, と Wiedemann 2018)を参照されたい。本章で用いた「近傍の平均距離 \(\mu+t\sigma\)」基準による統計的外れ値除去(SOR)は、Rusuらが家庭内シーン向けの点群物体地図を構築する際に提案したノイズ除去パイプラインに由来する(Rusu ほか 2008)。ボクセルグリッドダウンサンプリングおよび上記の各演算子のオープンソース参照実装は、点群ライブラリ(PCL)の概要(Rusu と Cousins 2011)で概観されている。