Edge detector
エッジとは、輝度が1方向で急激に変化する画像上の位置である。エッジ検出は基本的な画像処理操作であり、その中核をなす要素 — 画像勾配 — は、コーナー検出、オプティカルフロー、そして直接法SLAMの基盤となっている。
まずグレースケール化とスムージング
エッジ検出は(ほとんどのSLAMフロントエンド処理と同様に)グレースケール画像上で行われる。勾配計算には輝度のみが必要であり、1チャンネルは3チャンネルより3倍高速に処理でき、色は照明条件によって一貫性がない。標準的な変換は輝度公式 である。
微分は雑音を増幅するため、勾配計算の前にガウシアンブラーで画像を平滑化する — これは以下のカーネルとの畳み込みである:
の選択が検出するエッジのスケールを決める。小さい は細かい詳細(と雑音)を保持し、大きい は粗い構造だけを残す。
Sobel演算子
Sobel演算子は、2つの カーネルとの畳み込みによって画像勾配を計算する:
勾配の大きさは であり、勾配の方向は である。Sobelは微分(パターン )とそれに垂直な方向のスムージング(重み )を組み合わせており、これにより単純な差分よりも雑音への耐性が高くなる。
Cannyエッジ検出器
Canny検出器は、生の勾配を細く、良く局在化されたエッジ曲線に変換する多段階アルゴリズムである:
- ガウシアンスムージングで雑音を抑制する。
- Sobel勾配(大きさと方向)を計算する。
- 勾配方向に沿った非最大値抑制により、リッジを1ピクセル幅に細くする。あるピクセルが残るのは、その大きさが勾配方向に沿った両隣のピクセルの大きさを超える場合に限られる。
- 高い閾値と低い閾値を用いたヒステリシス閾値処理: 強いエッジ(高い閾値を超えるもの)は保持され、弱いエッジ(低い閾値と高い閾値の間)は強いエッジに接続されている場合のみ保持される。これにより連続した輪郭を保持しつつ、孤立した雑音応答を排除する。
import cv2
edges = cv2.Canny(gray, threshold1=50, threshold2=150) # low, high
両方の検出器はOpenCVでは1行で呼び出せる(cv::Sobel、cv::Canny)が、畳み込みと勾配がどのように機能するかを内面化するために、一度は自前で実装してみる価値がある。
よくある落とし穴
- ブラーを省略すること: 雑音の多い生画像に対してCannyを適用すると、まだら模様の断片化されたエッジが生成される。(または組み込みの開口サイズ)を閾値と共に調整すること。
- 単一閾値の発想: 2つのCanny閾値こそがこのアルゴリズムの要点である。単一の閾値では輪郭が断片化するか、雑音を許容してしまう。低い閾値は高い閾値の一定割合に設定すべきである。
- エッジは特徴点ではない: エッジ上の点はその輪郭に沿って滑ることができる(アパーチャ問題)ため、幾何を1方向にしか制約しない — これがまさにキーポイントとしてコーナーがマッチングされ、エッジ点がマッチングされない理由であり、エッジベースのSLAMがエッジを1次元的な制約として扱う理由である。
SLAMにおける意義
Sobelによって計算される画像勾配は、ハリス構造テンソルとLucas-Kanadeオプティカルフローへの入力であり、そのためエッジ検出はSLAMフロントエンドの特徴点機構への足がかりである。エッジ自体も直接使用される。線/エッジ特徴は、テクスチャの少ない人工的な環境において点を補完する(例:PL-SLAM)。LSD-SLAMのような直接法は、測光的な位置合わせのために高勾配(エッジ的な)ピクセルに暗黙的に依存している。