19 ROI 生成と位置補正
これまでの章では「ワークを見つける」ことを解決してきた:テンプレートマッチング(チャプター 16)、形状マッチング(チャプター 17)、幾何プリミティブによる位置決め(チャプター 14)がそれぞれの手法を発揮し、最終的に1つの位置と角度を出力する。しかし、生産ラインで本当の問題が生じるのは、多くの場合ここからである——見つけた後はどうするのか? 典型的な検査ステーションでは、1つのワークに対して十数個から数十個にも及ぶ測定項目(孔径、エッジ間距離、文字、欠陥など)を計測する。各測定項目にはそれぞれROI(region of interest:関心領域)があり、ワークが到着するたびに位置は異なる。だからといって、測定項目ごとに位置決めを行う必要はあるだろうか? 産業用ラインでの標準的な答えは、はるかにエレガントなパターンである:1回位置決めすれば、すべての箇所で恩恵を受けられる——1回の位置決めでワークの現在の姿勢を取得し、すべての測定用ROIを同じ変換でワークの新しい位置に「移動」させるのである。この機構を位置補正(fixturing)と呼ぶ。本章では実際のサンプル画像セットを用いてこれを実装する:被検体は発光する円環と1つの円弧状の凸耳(tab)からなる剛体部品であり(図 19.1 (a)、Smart3「ROI補正サンプルレシピ」より)、凸耳の表面には傷があり、これが検出対象となる。図 19.1 (b) は同じ部品を画面内の別の場所に移動し、全体を約90°回転させたものである。白い十字は位置決めされた円環の中心で、細い線は凸耳を指している。検査用ROI(白い円)は参照画像上で凸耳を囲んでいる——これからのすべての作業は、この円形ROIが234 px移動した凸耳に自動的に追いつくようにすることである。
このサンプル画像セットは計7枚で、いずれも同じ剛体部品を異なる投入姿勢で撮像したものである:円環の内孔半径は全7枚で安定して 74.0 px、凸耳の重心から円環中心までの距離は安定して 116 px、輝点の総数は約29565で一定——これらの不変量が「同じ剛体」の指紋となる。部品は3つの向きで現れる:001/006(凸耳が左上、両者は実質的に同じ画像の複製)、002–005(凸耳が右上に回転、4枚は純粋な平行移動)、007(凸耳が左下に回転)。
19.1 ROI の種類と生成
ROIはこれまでの各章で繰り返し登場してきたが、ここで体系的に整理する。SciVision の SciROI は Gen* という一連のメソッドを通じてさまざまな形状を生成する:矩形(GenRect1、軸に平行)が最も汎用的で、閾値処理、フィルタリングなどの領域操作ではほぼすべてに用いられる;回転矩形は傾いたエッジや文字列行を囲むのに用いられる;円(GenCircle)は穴、軸、はんだ接合部といった円形特徴に自然に適合し、本章の検査用ROIも凸耳を囲む円である——チャプター 14 の放射状探索線も円形ROI内に配置される;円環(GenTorus)は探索帯を内外半径の間に制約するため、Oリングやガスケットの計測に適している;多角形は不規則な輪郭に沿わせるために用いられる。1つの工学的事実として確認しておく価値がある:GenRect1 の右下隅は排他的端点であるため、全画面ROIは (W−1, H−1) ではなく (W, H) を渡すべきであり、そうしないと最外周の1行と1列が処理されないままになる(チャプター 7)。
ROIはワークと共に移動する必要があるため、次の問いが生じる:各ROI種は剛体変換の下でどうなるか? 中心は移動し半径は変わらないため、円は円のままである——本章の円形検査用ROIは角度付きの補正後も円のままである(実測値は後述);円環も同様である。軸に平行な矩形は回転後は軸に平行ではなくなる——回転矩形に変化する。これが位置補正のパイプラインで回転矩形ROIが随所に見られる理由である:参照画像上で適当に描いた正の矩形は、角度付きの補正を1回経るとすべて姿勢を持つようになる。多角形は頂点ごとに変換され、形状は変わらない。言い換えれば、これらすべてのROI種は剛体変換の下で閉じている(アフィン変換の下では円は楕円になるが、位置補正ではそのような一般的な変換は必要ない)ため、ROIがワークに追従する上で幾何学的な障壁はまったく存在しない。
ROIには2つの役割があり、初心者は多くの場合最初の役割しか見ていない。1つ目の役割は計算範囲の制限である:640×480の画像は30万画素あるのに対し、凸耳周囲の半径46の円形ROIは7000画素に満たない——アルゴリズムはROI内でのみ実行されるため、速度は1~2桁異なる。2つ目の役割はより重要である:ROIは測定の意味付けを束縛する——「この円形ROI内には凸耳があるはずで、その表面に傷がないか検査する」。アルゴリズムのパラメータ(期待されるグレースケール値、極性、閾値)はすべて「ROI内に何があるか」に基づいて設定されている;一度ROIがカバーすべき特徴を覆わなくなると、これらのパラメータは前提を完全に失い、アルゴリズムは失敗するか、あるいは——より危険なことに——間違った内容に対して一見正常に見える結果を算出してしまう。本章の実験では後者のケースを意図的に示す。
19.2 姿勢と剛体変換
姿勢(pose)は「位置+向き」を合わせた呼称である:平面上の剛体ワークの姿勢は、基準点の座標 \(\mathbf{p}=(x, y)\) と角度 \(\theta\) の3つの量によって完全に決定される。基準点はマッチングアルゴリズムが報告するテンプレート原点でもよいし、本章のように円形特徴の中心でもよい;角度は何らかの方向基準に沿って定められる。本章では円環内孔の中心を基準点(平行移動の原点)、その中心から凸耳重心への方向を角度として用いる——中心が平行移動を、凸耳が回転を与え、両者が合わさって部品全体の姿勢を固定する。ワークの局所座標系における1点 \(\mathbf{f}\)(例えば凸耳の重心)について、画像中の位置は姿勢によって決まる:
\[ \mathbf{x} = R(\theta)\,\mathbf{f} + \mathbf{p}, \qquad R(\theta)=\begin{bmatrix}\cos\theta & -\sin\theta\\ \sin\theta & \cos\theta\end{bmatrix}. \]
参照姿勢 \((\mathbf{p}_r, \theta_r)\) と現在の姿勢 \((\mathbf{p}_c, \theta_c)\) から、同じ点に対する2つの画像座標 \(\mathbf{x}_r\) と \(\mathbf{x}_c\) が得られる。\(\mathbf{f}\) を消去すると、参照画像座標から現在の画像座標への剛体変換(rigid transform)が得られる:
\[ \mathbf{x}_c = R(\Delta\theta)\,(\mathbf{x}_r - \mathbf{p}_r) + \mathbf{p}_c, \qquad \Delta\theta = \theta_c - \theta_r. \]
これを同次行列で書くと、チャプター 2 でおなじみの \(3\times 3\) 形式になる:回転部分 \(R(\Delta\theta)\) と、平行移動部分 \(\mathbf{p}_c - R(\Delta\theta)\,\mathbf{p}_r\) である。位置補正の数学全体はこの1つの行列で表される:この行列は参照画像上の任意の点について成立するため、1回の位置決めで任意の数のROIを駆動できる。
ここに非常に実用的な性質が隠されており、本章の「粗い」角度推定がそれを裏付けている。我々の角度は高精度なエッジフィッティングから得られたものではなく、凸耳領域の輝点の重心方向——照明むらや傷の分布によって数度引きずられる系統的バイアスを持つ推定量である。しかし、このバイアスがワーク座標系で近似的に一定である限り(同じ凸耳、同じ撮像条件)、これを \(\hat{\mathbf{p}} = \mathbf{p} + R(\theta)\,\mathbf{b}\) と書き、相対変換に代入して参照画像上の真の特徴点について展開すると:
\[ R(\Delta\theta)\,(\mathbf{x}_r - \hat{\mathbf{p}}_r) + \hat{\mathbf{p}}_c = R(\theta_c)\,\mathbf{f} - R(\theta_c)\,\mathbf{b} + \mathbf{p}_c + R(\theta_c)\,\mathbf{b} = \mathbf{x}_c . \]
2つの \(R(\theta_c)\,\mathbf{b}\) 項は厳密に相殺される——バイアスがワークと共に移動する限り、位置補正にはまったく影響を与えない。実験はこれを裏付けている:角度推定自体は粗い重心方向であるにもかかわらず、参照画像と現在の画像で同じ推定量を用いているため、補正後のROI中心と現在の画像で独立に測定された凸耳重心との残差は常に 0.27 px以下 である(最悪のケースはサンプル004で0.266 px)。これは位置補正で最も見過ごされやすい教育的ポイントである:位置補正は相対的な変換を用いるため、位置決め特徴の系統的バイアスは「両側で同じだけ誤る」ことになり、減算でゼロになる;真に精度を損なうのは角度のランダムな揺らぎと部品自体の非剛性である。
「fixturing」という単語は機械加工の治具(fixture)に由来する:治具はワークを固定された姿勢にロックし、工具経路がワークを感知する必要をなくす。視覚による位置補正はその逆を行う——ワークを自由に配置し、「工具経路」(ROI)をワークに適応させる、言わばソフトウェア治具である。
バイアスの相殺は、バイアスがワーク座標系で一定であることを前提とする。もしバイアスが照明方向やレンズ歪みといった画像座標系の要因に由来する場合、バイアスはワークと共に回転しないため相殺されない——これが、位置決め特徴にはコントラストが高く等方性の良い構造(本章の発光する円環内孔など)を選ぶべき理由の1つである。
19.3 位置決め実験
全体の処理フローは4段階からなる:位置検出 → 位置補正行列の算出 → ROIの変換 → 計測。位置検出は2つの要素に分かれる:円環の中心は内孔のエッジから求められ——径方向に角度ごとに走査して暗→明の変化点を検出して内孔のエッジ点を得た後、最小二乗法による円フィッティングを行うと、全7枚の画像で内孔半径は74.0 pxに安定して収束する;角度は中心から凸耳の重心(半径 [134, 210] の範囲内にある明るい画素の重心)に向かう方向とする。位置検出の範囲と計測用ROIの役割は異なることに注意されたい:位置検出は部品全体の大きな構造(直径が百画素を超える円環)を走査するため、どのような搬入位置でも部品を捉えられるだけの大きさを持つ。一方、検査用ROIは小さく高精度であり、位置補正によって移動させる必要がある対象である。サンプル画像001を参照とした場合、位置検出結果は中心 (255.56, 194.54)、凸耳の方向 −154.5° となる。検査用ROIは参照画像上で実測された凸耳の重心 (150.93, 144.67) を中心とする半径46の円として定義される——位置補正は「参照画像上で見えた位置」を移動させるものであり、ROIの定義を位置検出結果と一致させることは工学上の慣例である。
当初はSciVisionのSciSvEllipseLocatorを用いて内孔の円フィッティングを試みたが、このサンプルセットではエッジの選択が不安定だった:001/006では123501012が直接返され、002–005では内孔(74 px)ではなく外輪のエッジ(半径約87 px)にロックされ、中心が約24 pxずれた。画像ごとに中心が不一致だと相対的な位置姿勢が完全に崩れてしまうため、決定論的な「径方向エッジ検出 + 円フィッティング」に切り替えたところ、全画像で内孔半径が74.0 pxに安定した。
第2段階では、2つの位置姿勢をSciAxisTransform::Generate2DAlignMatrixに渡し、参照位置姿勢から現在の位置姿勢への \(3\times 3\) の位置補正行列を得る。前節の数式を用いて手計算した剛体行列と要素ごとに比較したところ、最大誤差は \(10^{-3}\) 以内であり——SDKが実行している処理はまさにその数学的な内容そのものである。さらにTransformPointAndAngleを用いた自己検証を行う:参照中心を行列で変換したところ、現在の中心との残差は0.0000 pxとなり、矛盾がないことが確認された。
第3段階のAlignROIは、検査用ROI(参照画像の凸耳に配置された半径46 pxの円)を現在の位置姿勢に変換する。剛体変換は形状を変化させないため、円形のROIは変換後も円形のままである。この一連の処理を全7枚のサンプル画像に実行したところ、復元された位置姿勢と位置合わせ残差は 表 19.1 の通りである:002–005は参照に対して約+90°の回転と様々な並進が合成されたもの、007は約−90°の回転、006は001と完全に一致(重複画像であり、恒等変換として復元された)。いずれの画像でも、位置補正後のROI中心は独立して計測された凸耳の重心とサブピクセル精度で一致しており——最悪の残差でもわずか0.266 pxである。
| サンプル | 復元された並進 (px) | 復元された回転 \(\Delta\theta\) | ROI→凸耳残差 | ROI内の明画素率(補正後/未補正) |
|---|---|---|---|---|
| 001 | (0.0, 0.0) | 0.00° | 0.000 px | 0.718 / 0.718 |
| 002 | (+78.9, +81.0) | +89.36° | 0.164 px | 0.718 / 0.000 |
| 003 | (+128.9, +81.0) | +89.84° | 0.097 px | 0.718 / 0.000 |
| 004 | (+128.9, +131.0) | +89.73° | 0.266 px | 0.718 / 0.000 |
| 005 | (+128.9, −19.0) | +89.80° | 0.202 px | 0.719 / 0.000 |
| 006 | (0.0, 0.0) | 0.00° | 0.000 px | 0.718 / 0.718 |
| 007 | (−51.0, −21.1) | −89.81° | 0.119 px | 0.720 / 0.388 |
核心的な比較は最後の列にある。サンプル画像002を例にとると、凸耳は参照位置から234 px移動している;位置補正後の円形ROI内の明画素率は0.718(凸耳がROI内に収まっている)であるのに対し、移動させなかったROIの明画素率は 0.000——画面左上の真っ暗な背景上に位置しており、発光した画素を1つも覆っていない。図 19.2 は両者の視覚的な比較である。
第4段階では位置補正後のROI内で検査を行う——本章では凸耳が適切な位置にあるかどうかの観測量として「明画素率」を用いる(実際の生産ラインではこのROI内でキズ検査や輪郭計測を行う):位置補正後のROIから得られた値は0.718であり、参照画像上の同じROIの値0.718と完全に一致しているため、位置補正は検査の誤差要因をほとんど発生させていない。
真に警戒すべきは未補正側の結果である。直感的にはROIが200画素以上ずれていれば検査は明らかに失敗してアラームが上がるはずだが、検査アルゴリズムが戻り値だけを確認する場合、その真っ暗な背景上で正常に結果が返されてしまう——明画素率0.000、「キズは検出されず」という、一見すると完全な合格判定が出力される。これは典型的な静かな失敗(silent failure):処理フローはエラーを出力せず、各項目には値が埋められているが、その値は誤った対象に対して計算されたものである。これは明確なエラーが発生する場合よりもはるかに危険である——エラーが発生すればラインは停止するが、静かな合格判定は不良部品をそのまま通過させてしまう。工学的な対策は、計測に構造的な閾値を設けることである:ROI内の有効信号量(例えば明画素率が低すぎる場合)、特徴が存在するかどうか、期待されるモデルからの偏差——いずれか1つでも閾値を超えた場合は計測を無効と判定し、戻り値だけを信用することは絶対にしない。本例における0.000と0.718の大きな差は、まさにこうした閾値のための既成の判定基準となる。
19.4 2つの手法:ROIを動かすか、画像を動かすか
位置補正には第2の手法が存在し、これは チャプター 10 で議論した「魅力的な誤った道」でもある:ROIを動かす代わりに、現在の画像全体を位置補正行列の逆変換で参照位置姿勢に戻し、元のROIを用いて通常通り計測する。本章では手書きの双線形逆写像を用いてこの手法を実装した(チャプター 10 の手書き回転と同様の実装である)。結果は 図 19.3 の通りである:サンプル画像002を逆回転させたところ、部品はほぼ参照画像001の配置を再現し、元のROIが再び凸耳を覆うようになった。
2つの手法による位置補正後のROI内の明画素率はほぼ等しい:ROIを動かした場合は0.718、画像を回転させた場合は 0.722——数学的には両者は同じ変換であり、差は補間によるノイズ(0.004)に過ぎない。しかし、計算コストは全く異なる:ROIを動かす場合は数個の幾何パラメータ(中心の座標2つ、半径1つ)を変換するだけであり、処理時間は無視できるほど小さい;画像を動かす場合は全画面の30万画素に対して再サンプリングを1回行う必要があり、さらに双線形補間がエッジに平滑化の層を重ねるため、エッジ位置の再現性が劣化する(チャプター 10 の事例でこの劣化は定量化されている)。結論は前章と同様である:ROIを動かせる場合は画像を動かしてはならない。画像を動かす価値があるのは以下の2つの場合のみである:アルゴリズムが軸に平行なROIしか受け付けず、姿勢を持つ検査領域を表現できない場合;あるいは複数の工程、複数のアルゴリズムが同一の基準座標系を共有する必要があり、各工程が個別に位置補正を行うよりも1回の統一された回転の方が制御しやすい場合。
19.5 SciVision 実装
補正の中核は SciAxisTransform の2つのインターフェースである:
SCIMV::SciAxisTransform xform;
SciMatrix M;
SciPoint refPt(poseRef.cx, poseRef.cy), curPt(poseCur.cx, poseCur.cy);
long rc = xform.Generate2DAlignMatrix(refPt, curPt,
(float)(-poseRef.deg), (float)(-poseCur.deg), &M); // 角度取負、後述
SciROI fixedROI;
rc = xform.AlignROI(inspROI, M, &fixedROI); // 円ROIは変換後も円のままGenerate2DAlignMatrix の4つの入力は順に、参照基準点 refPt、現在の基準点 curPt、参照角度、現在の角度であり、参照姿勢から現在の姿勢への \(3\times 3\) 行列 M を出力する。AlignROI は任意の SciROI をこの行列に通し、補正後のROIを得る。行列の正しさを検証するには TransformPointAndAngle が利用できる。この関数は点と角度を同時に変換するため、「参照円の中心は現在の円の中心に一致するはず」という自己チェックに適している。
本章では実際のサンプル画像で2つの落とし穴に遭遇したため、そのまま記録する。最初の落とし穴は最も強調する価値がある:角度の符号である。Generate2DAlignMatrix の角度の約束事は視覚的に反時計回りを正とするものである。一方、画素座標系はy軸が下向きであるため、atan2(dy, dx) で計算される角度は視覚的に時計回りを正とする——両者は符号が異なる。atan2 の結果をそのまま渡すと回転方向が逆になり、補正後のROIは数百画素もずれて補正なしよりも悪い結果となる。正しい方法は -poseRef.deg と -poseCur.deg を渡すことである。座標系のカイラリティの問題は チャプター 2 で強調したが、ここでそれが最も痛い形で顕在化した。
2番目の落とし穴は位置決め工程にある:この発光リングのサンプル画像群で SciSvEllipseLocator はエッジの選択が不安定であり、2枚の画像では 123501012 を直接返し、残り4枚では目標の内孔(74 px)ではなく外輪のエッジ(半径約87 px)にロックしてしまい、中心が約24 pxずれた。補正は2回の位置決めの差分を利用するため、画像ごとに位置決め元がドリフトして自己整合性が失われると、どれほど正確な行列でもゴミのような入力を受け取ることになる。そのため本章では、内孔の中心を求めるために決定論的な「放射方向の暗→亮エッジ点 + 最小二乗円フィッティング」に切り替えた。全7枚の画像が同じ半径74.0 pxに収束し、自己整合性が確保された。この教訓はどのような単点精度よりも重要である:補正システムの精度上限は、単フレームの位置決めの絶対精度ではなく、位置決めの再現性によって決まる。本章のすべての図と数値を生成する完全なプロジェクトは code/roi_and_fixturing/ にある。
産業事例:複数の測定項目が1回の位置決めを共有
あるコネクタ検査ステーションには23の測定項目があった:ピンピッチ、樹脂ハウジングの辺間距離、ラッチ輪郭……最初は各項目がそれぞれテンプレートマッチングによる位置決めを実行していたため、タクトタイムが大幅に超過し、各項目の位置決め誤差が独立していたことから「ピンからハウジングの辺まで」のような項目間の寸法のジッタが顕著だった。改造案では形状マッチングでコネクタ全体を1回位置決めし、23個の測定ROIをすべて同じ補正行列で統一的に変換した。タクトタイムは約60%減少し、さらに重要な点として、すべての項目が同じ座標基準を共有するようになった——項目間の相対関係がそれぞれの位置決め誤差によって汚染されなくなった。代償として、位置決めの品質がグローバルな単一点依存となった:位置決めが失敗またはドリフトすると、23の項目すべてが同時に失敗する。これはまさに本章のサンプルが教える教訓である——位置決めの再現性は補正システムの命綱である。実装時には位置決めにスコアの閾値と失敗時の再試行(パラメータの変更、探索領域の変更)を追加し、製品ロットごとの位置決めスコアの傾向も監視対象に組み入れた。
19.6 まとめ
- 位置補正の標準モデルは「1回位置決め、全体で利益を得る」である:1回の位置決めで現在の姿勢を求め、1つの剛体変換行列ですべての測定ROIをワークに追従させる——本章の7枚の実サンプルでは、補正後のROIと凸耳の残差はすべて ≤ 0.27 pxであるのに対し、補正なしのROIは完全に的外れとなった(凸耳が234 px移動し、ROI内の亮画素率が0.718から0.000に低下した)。
- 補正は相対変換を利用するため、位置決め特徴の系統的なバイアスは自動的に相殺される:本章の角度推定は単に凸耳の重心方向(系統的バイアスを含む)であるが、参照画像と現在の画像で同じ推定値を使用するため、バイアスは \(R(\theta_c)\mathbf{b}\) 項の減算でゼロになり、残差はサブ画素で安定する。
- 静かな失敗はエラーよりも危険である:補正なしのROIは全黒の背景上に位置するため、戻りコードのみを確認する検査では「正常」に「欠陥なし」と報告されてしまう。測定には信号量、特徴の存在、パラメータの妥当性などの構造的な閾値を設けて守り、戻りコードのみを信用してはならない——本例の0.000と0.718の隔たりは既成の判定基準である。
- ROIを動かせるなら画像を動かすな:ROIを動かす場合と画像を回転させる場合の検査結果は0.004まで一致するが、後者は全画像の再サンプリングと補間による平滑化の余分なコストが発生する。アルゴリズムが姿勢付きROIをサポートしない場合、または複数のステーションで基準系を共有する必要がある場合に限り画像を動かすべきである。
- 補正の精度上限は、単フレームの絶対精度ではなく位置決めの再現性である:
SciSvEllipseLocatorが画像間でエッジを一貫して選択できず(24 pxずれた)相対姿勢を汚染していたが、画像全体で自己整合性のある内孔の円フィッティング(半径は常に74.0 px)に切り替えた後、補正が安定した。角度の符号は別の落とし穴である——Generate2DAlignMatrixは視覚的な反時計回りを正とするため、画素のatan2の結果は符号を反転させてから渡す必要がある。
産業測定における姿勢推定、剛体およびアフィンアライメントの体系的な解説については、Stegerらの著作(Steger, Ulrich, と Wiedemann 2018)を参照されたい。アライメントと画像レジストレーションのより広範なアルゴリズムの背景については、Szeliskiの教科書(Szeliski 2022)を参照されたい。




