そもそも、なぜ「特徴点」なのか
同じ被写体を写した二枚の写真があるとします。片方は少し離れて撮り、片方は近づいて、しかも数十度傾けて撮った。人間の目には同じ被写体だと一瞬でわかりますが、計算機にとって二枚は単なる数値の並びで、対応する画素の値はまるで一致しません。「一方の画像のこの点は、もう一方のどこか」を求める問題を対応点探索と呼び、コンピュータビジョンの多くの応用が結局のところここに帰着します。
素朴な方法として、画像を丸ごと重ねてずらしながら差を測る、という手が思いつきます。しかしこれは撮影条件が少しでも変わると破綻します。距離が変われば被写体の大きさが変わり、カメラを傾ければ画素の並びが回転し、日が翳れば全体の明るさが沈み、手前を人が横切れば一部が隠れる。画像全体をひとつの塊として扱う限り、これらすべてに耐えることはできません。
「全体」をやめて「点」で持つ
そこで発想を裏返します。画像全体を比べるのではなく、画像の中から少数の「目印になる点」だけを選び出し、その点の周囲の見え方だけを記録して比べる。目印が数百個あれば、そのうち何割かが隠れても、残りで対応が取れます。局所的に見ているので、視点が多少ずれても近傍の見え方は大きくは変わりません。これが局所特徴(local feature)という考え方です。
この方針を実行に移すには、性質の異なる二つの仕事が必要になります。
- 検出器(detector)… どこを目印にするかを決める。撮影条件が変わっても同じ物理的な場所が繰り返し選ばれることが命題です。この再現性を再現率(repeatability)と呼びます。
- 記述子(descriptor)… 選んだ点の周囲を数値の並びに翻訳する。同じ場所どうしは似た値になり、違う場所どうしはしっかり離れることが求められます。
SIFT の名が優れているのは、この二つを別々の道具の寄せ集めではなく、一本の設計思想で貫いた点にあります。検出の段階で「大きさ」と「向き」を確定させ、記述の段階ではその大きさと向きを基準に座標系を張り直す。だから記述子の側は、スケールや回転のことを一切気にしなくてよくなります。
Scale-Invariant Feature Transform ― 「スケール不変な特徴への変換」。名前そのものが設計目標の宣言になっています。ここでいうスケール不変とは、被写体が画像上で何倍の大きさで写っていても同一視できる、という意味です。
満たすべき四つの条件
Lowe が SIFT に課した要件は、はっきりしています。第一にスケール不変であること。第二に回転不変であること。第三に、照明の変化や小さな視点変化、画像ノイズに対して頑健であること。そして第四に、無数の点の中から正しい相手を一発で言い当てられる識別力があること。
この四つは互いに引っ張り合います。不変性を上げようと情報を捨てすぎれば識別力が落ち、識別力を求めて細かく記録すれば少しの変形で値が動いてしまう。以降で見ていく設計の一つひとつは、この綱引きのどこかに答えを出すために置かれています。SIFT を読むとは、この妥協点の選び方を読むことだと言い換えてもよいでしょう。
全体像 ― 四つの工程を順に通す
SIFT は、一枚の画像を入力として四つの処理を順番に通し、最終的に「座標・スケール・向き・128 次元ベクトル」の組を数百から数千個出力します。工程の順番には意味があります。前の工程が決めたものを、次の工程が前提として使うという依存関係で連なっているためです。
スケール空間の極値検出
画像を段階的にぼかした列を作り、隣り合うぼかしの差分の中で、位置とスケールの両方について尖っている場所を拾う。
→ 候補点 (x, y, σ)キーポイントの精査
候補を補間して画素より細かい精度に直し、コントラストの低い点とエッジ上の点を捨てる。
→ 確定点 (x, y, σ)向きの割り当て
周囲の勾配方向のヒストグラムを作り、そのピークをその点の基準方向 θ として与える。
→ (x, y, σ, θ)記述子の生成
σ と θ を基準に座標系を張り直し、周囲の勾配を 4×4×8 のヒストグラムに畳んで正規化する。
→ 128 次元ベクトルここで押さえておきたいのは、不変性が段階的に獲得されていくという構造です。Step 01 で拾った σ は「この点はどれくらいの大きさで見るべきか」という物差しであり、これが決まった時点でスケール不変性の準備が整います。Step 03 で決まる θ は「この点をどちらを上として見るか」であり、これで回転不変性の準備が整う。Step 04 はこの二つを使って座標系を正規化するだけなので、記述子そのものは不変性の心配をしなくて済みます。
逆に言えば、σ と θ の推定を誤ればその点は最後まで救えません。SIFT の精度の大部分は、実は最初の三工程の丁寧さで決まります。
スケール空間 ― 「どの大きさで見るか」を軸にする
写真に写った窓枠の角は、10 メートル離れて撮れば数画素の点ですが、1 メートルまで寄れば数十画素にわたる構造になります。同じ物理的な角が、画像上ではまったく違う大きさを持つ。だから「どのくらいの範囲を見て判断するか」を固定してしまうと、必ずどこかの距離で見落とします。
SIFT の答えは単純です。一つの倍率を選ぶのではなく、あらゆる倍率を同時に用意して、その中から自動的に一番合う倍率を選ばせる。この「あらゆる倍率を並べた表現」がスケール空間です。
ガウシアン関数だけが許される
画像 I をスケール σ でぼかしたものを L と書きます。ぼかしはガウシアン関数との畳み込みで行います。
ここで「ぼかすならガウシアンでなくてもよいのでは」という疑問が出ます。しかし答えはガウシアン以外は使えないです。Koenderink と Lindeberg の一連の研究により、解像度を落としていく過程で新しい構造を一切生み出さない核は、ガウシアン関数だけであることが示されています。他の核を使うと、ぼかした結果に元画像には無かった極大や極小が現れうる。それでは「ぼかしたら現れた点」を特徴として拾ってしまい、再現性が崩壊します。ガウシアンの採用は美的な選択ではなく、要請なのです。
なぜ差分(DoG)を取るのか
ぼかし列を用意したら、次はその中から「尖った場所」を探します。尖り具合の指標として理論的に正しいのは、スケール正規化されたラプラシアン σ2∇2G です。Lindeberg は、この量の極値がスケールに対して真に不変な応答を与えることを示しました。ただし二階微分の計算は重い。
そこで Lowe は迂回路を通ります。ガウシアン関数は熱拡散方程式を満たします。
左辺を差分で近似すると σ∇2G ≈ ( G(kσ) − G(σ) ) ⁄ ( kσ − σ ) となり、整理すれば次が得られます。
つまり二枚のぼかし画像を引き算するだけで、正規化ラプラシアンの近似が手に入る。これが Difference of Gaussian、略して DoG です。二階微分フィルタを畳み込む代わりに、どうせ作るぼかし列の隣接差を取るだけで済む。計算コストがほぼゼロで理論的に正しい量が近似できる、という設計上の勝ち筋です。
オクターブ ― σ が倍になったら画像を半分にする
σ を上げ続けると、いずれ σ は元の 2 倍に達します。このとき画像の情報量は 4 分の 1 以下になっているので、同じ画素数を保つ意味がありません。そこで σ が倍になった時点で画像を縦横それぞれ 1/2 に間引き、次の段(オクターブ)へ移ります。以後は小さい画像の上で同じ処理を繰り返す。
1 オクターブを s 段階に刻むなら k = 21/s です。Lowe の実験では s = 3 が再現率と計算量の折り合いが最もよく、このとき k ≈ 1.26。各オクターブで作るガウシアン画像は s + 3 = 6 枚、DoG は 5 枚、実際に極値を探すのは中央の 3 枚になります。
初期の σ は 1.6。また Lowe は入力画像をあらかじめ縦横 2 倍に拡大してから処理を始めることを推奨しています。撮影された画像には既に σ ≈ 0.5 相当のぼけが乗っていると仮定でき、拡大しないと最も細かいスケールの特徴を取りこぼすためです。この前処理だけで検出される安定な点の数はおよそ 4 倍になります。
極値の判定 ― 26 個の隣人と比べる
DoG が用意できたら、あとは「周りより飛び抜けている画素」を探すだけです。ある画素を、同じ DoG 画像内の 8 近傍と、上下のスケールにある 9 画素ずつ、合わせて 26 画素と比較します。そのすべてより大きい、またはすべてより小さいとき、その画素を極値候補とします。
この時点で取り出されるのは、画像中で局所的に明るい/暗い塊、いわゆるブロブの中心です。角や点状の模様、テクスチャの粒などがここに引っかかります。ただしこの段階の候補には、まだ使い物にならないものが大量に混ざっています。それを次の工程でふるいにかけます。
キーポイントの精査 ― 候補の大半を捨てる
26 近傍の比較で残った候補は、まだ「粗い格子の上でたまたま一番大きかった画素」に過ぎません。ここから三つの操作で、精度を上げ、使えない点を落とします。
画素より細かい位置へ ― 二次曲面を当てる
真の極値が、たまたま画素の中心に来ているとは限りません。DoG は本来なめらかな関数なので、離散的な標本点の周りを二次関数で近似すれば、極値の位置を小数点以下まで推定できます。候補点を原点として D をテイラー展開します。
これを x で微分してゼロと置けば、極値のオフセットが閉じた形で求まります。
もし x̂ のどれかの成分が 0.5 を超えていたら、それは本当の極値は隣の画素の側にあるという意味なので、候補点をその隣に移して計算をやり直します。この補正により、位置とスケールの推定精度が目に見えて改善し、結果としてマッチングの正解率が上がります。
コントラストの低い点を捨てる
のっぺりした領域や、ノイズがたまたま盛り上がっただけの場所も、極値としては検出されます。これらは照明やノイズで簡単に消えるので、特徴として役に立ちません。補間後の極値での DoG の値を評価します。
エッジの上に乗った点を捨てる
これが最も効く工程です。DoG はエッジに沿って強い応答を返します。しかしエッジ上の点は、エッジに垂直な方向にはよく定まるのに、エッジに沿った方向にはまったく定まりません。少しのノイズで位置が線に沿って滑ってしまう。こういう点を残すと、対応点探索でひどく不安定になります。
エッジらしさは、DoG の局所的な曲がり方で判定できます。位置に関する 2×2 のヘッセ行列を考えます。
コーナーのような良い点では二つの曲率がどちらも大きく、エッジ上では一方だけが極端に大きくなります。したがって「曲率の比」を見ればよい。ただし固有値そのものを計算する必要はありません。トレースと行列式だけで比が書けるからです。
Lowe は r = 10 を閾値としました。すなわち Tr2/Det が (10+1)2/10 = 12.1 を超える点は捨てる。曲率の比が 10 対 1 より偏っていたら、それはコーナーではなく線だ、という判断です。また Det が負のときは二つの曲率の符号が異なる鞍点なので、比を見るまでもなく破棄します。
500×500 画素程度の画像で、26 近傍比較の候補はおよそ数千から一万個。そこから低コントラスト除去とエッジ除去を通すと、最終的に残るのはおよそ 2,000 点です。半分以上が捨てられますが、残った点の再現率は劇的に上がります。
特徴点は多ければよいというものではありません。不安定な点を一つ残すことは、誤対応を一つ増やすことと同じだからです。
向きの割り当て ― 回転不変性の正体
ここまでで各キーポイントは (x, y, σ) を持っています。次に、その点に固有の「上」の方向を一つ決めます。これが決まれば、あとの記述はすべてその方向を基準に行えばよく、画像が回転しても記述子の中身は変わりません。
回転不変性というと難しく聞こえますが、やっていることは「その点の周りで一番強い勾配の向きを北と呼ぶ」だけです。画像が 30 度回れば、その一番強い勾配の向きも 30 度回る。だから北を基準にした相対的な配置は保たれます。
勾配を測る
まず、そのキーポイントの σ に最も近いガウシアン画像 L の上で勾配を計算します。元画像ではなくぼかした画像を使うのは、スケール不変性を保つためです。大きいスケールの点は大きくぼかした画像で、小さいスケールの点は細かい画像で見る。こうしないと「見る解像度」がスケールごとに揃いません。
方向のヒストグラムを作る
キーポイントの周囲にある各画素の θ を、10 度刻みの 36 個のビンに投票させます。ただし全員が平等に一票ではありません。投票の重みは、その画素の勾配の強さ m に、キーポイントからの距離に応じたガウシアン窓を掛けたものです。窓の広がりは 1.5σ、つまりその点のスケールに比例させます。遠い画素ほど発言権が小さくなる、という設計です。
最も票を集めたビンの方向が、そのキーポイントの向き θ です。ここでさらに一手間かけます。ビンは 10 度刻みなので、そのまま使うと最大 5 度の誤差が残る。そこでピークとその両隣、計 3 点に放物線を当てはめて頂点を補間し、より細かい角度を得ます。
一つの点に向きを一つだけ割り当てると、二番手とほぼ同じ高さのピークがあったときに、ノイズ次第でどちらが選ばれるかが揺らぎます。二枚の画像で別々のピークが選ばれれば、その点は永久にマッチしません。
ならば迷うときは両方作ってしまえばよい。80% という閾値はそのための線引きです。点数は増えますが、後段のマッチングは「似ていないものは弾く」仕組みなので、余分な向きは実害なく無視されます。
128 次元記述子 ― 見え方を数字に翻訳する
最後の工程です。各キーポイントは (x, y, σ, θ) を持っており、これはその点だけのローカルな座標系を定義しています。原点が (x, y)、単位長が σ、基準軸が θ。この座標系の上で周囲を記述すれば、画像がどう写っていようと同じ数字になるはずです。
座標系を張り直す
まずキーポイントの周囲 16×16 画素分の領域を取り、その中の勾配の向きすべてから θ を引きます。同時に座標そのものも θ だけ回転させる。これで領域は「基準方向が真上を向いた状態」に正規化されました。領域の大きさも σ に比例させるので、スケールの正規化も同時に済んでいます。
次に、この領域を 4×4 の 16 個のサブ領域に区切ります。各サブ領域には 4×4 画素分の勾配が含まれます。サブ領域ごとに 8 方向(45 度刻み)のヒストグラムを作り、そこに含まれる勾配を投票させる。
境界のがたつきを消す ― 三線形補間とガウシアン重み
素朴に実装すると問題が起きます。ある勾配がサブ領域の境目にあったとき、画像がほんの 1 画素ずれただけで、その票が隣のマスへ丸ごと移動してしまう。記述子の値が不連続に飛び、マッチングが不安定になります。
そこで各票を、隣接するビンへ距離に応じて分配します。x 方向・y 方向・角度方向の三つについて按分するので、三線形補間と呼ばれます。境目にある勾配は両側に半分ずつ入るので、少々ずれても値はなめらかに変化します。
加えて、領域全体に広がりが記述子窓の幅の半分にあたるガウシアン重みを掛けます。これは中心から遠い勾配の影響を抑えるためで、視点変化などで周辺部の見え方が変わっても、記述子が大きく揺れないようにする保険です。
照明の変化に効かなくする
ここで一度立ち止まると、記述子は既に明るさの加算には不変です。勾配は差分から作られているので、画像全体に一定値を足しても勾配は変わりません。残るのはコントラストの変化、つまり画素値が定数倍される場合です。これは記述子ベクトルを単位長に正規化すれば消えます。
しかし現実の照明変化は、そんなに素直ではありません。カメラの飽和、光沢面の反射、影の落ち方などにより、特定の方向の勾配だけが極端に強くなることがあります。この場合、正規化しても一部の要素だけが突出したままです。
Lowe の対処はきわめて実際的です。
- 128 次元ベクトルを長さ 1 に正規化する
- 0.2 を超える要素をすべて 0.2 に切り詰める
- もう一度、長さ 1 に正規化する
これにより「一部の方向が突出している」という情報の影響が抑えられ、勾配の大きさよりも、勾配の向きの分布のほうが重視されるようになります。0.2 という値は理論から導かれたものではなく、実験によって選ばれた数字です。SIFT にはこうした経験的な定数がいくつも含まれており、それらは論文中で実データによる評価とともに正当化されています。
Lowe はサブ領域の分割数と方向ビン数を変えて性能を測っています。2×2×8 = 32 次元では表現力が足りず、4×4×8 = 128 でほぼ飽和。それ以上細かくすると、次元が増えるだけでなく視点変化に対する耐性がかえって落ちます。細かく刻むほど、少しの変形で票が別のビンへ逃げるからです。
128 は「識別力」と「変形への耐性」の交点として選ばれた数字であり、切りのよい数だから採用されたわけではありません。
照合 ― 似ているだけでは足りない
二枚の画像からそれぞれ数千個の 128 次元ベクトルが取れました。あとは似たもの同士を結べばよい……のですが、ここに SIFT のもう一つの重要な発明があります。
素朴な方法は、片方の各記述子について、もう片方の中からユークリッド距離が最小の相手を探し、その距離がある閾値より小さければ対応とみなす、というものです。しかしこれは実際にはうまくいきません。記述子の識別しやすさは、点によって大きく違うからです。特徴的な模様の上にある点は明確な最近傍を持ちますが、ありふれた模様の上の点は、多数の候補と似たような距離を持ってしまいます。全点に同じ距離閾値を当てても、良い線は引けません。
比率テスト ― 一位と二位を比べる
Lowe の答えは、絶対的な距離ではなく相対的な差を見ることでした。最近傍までの距離 d1 と、二番目に近い点までの距離 d2 の比を取ります。
考え方はこうです。もし一位が本物の対応なら、それは他のどの点よりも明確に近いはずで、二位は大きく離れる。一方、一位が偶然の一致に過ぎないなら、二位もだいたい同じくらいの距離にいるはずです。接戦なら信用しないという判断基準です。
探索を速くする
比率テストには最近傍と第二近傍が要るので、総当たりだと計算量は点数の積になります。数千点どうしなら実用範囲ですが、大規模な画像検索では厳しい。実務では kd 木やその近似版である BBF(Best-Bin-First)、あるいは FLANN のような近似最近傍探索ライブラリを使います。128 次元は kd 木にとっては高次元なので、厳密解を諦めて近似で速度を稼ぐのが定石です。
幾何で最後の仕上げをする
比率テストを通っても、まだ誤対応は残ります。ここで効くのが幾何的整合性です。正しい対応は、二枚の画像の間の一つの変換で説明できるはずですが、誤対応はてんでばらばらの方向を向きます。
- 相互最近傍… A から見て B が一位、かつ B から見て A も一位である対応だけを残す。実装が簡単で効果があります。
- RANSAC… 対応の中からランダムに少数を選んで変換(平面ならホモグラフィ)を推定し、その変換に合う対応の数を数える。これを繰り返し、最も多数派を得た変換を採用して、残りを外れ値として捨てます。
- ハフ変換によるクラスタリング… Lowe の原論文の方式。各対応はキーポイントの位置・スケール・向きから、物体の姿勢を粗く一票投じられます。同じ姿勢に 3 票以上集まったところだけを候補とする。これにより、対応の 99% が誤りでも物体を見つけられます。
SIFT のパイプラインは「疑わしきは捨てる」の連続です。低コントラストで捨て、エッジで捨て、比率テストで捨て、RANSAC で捨てる。各段階で大量の情報を失いますが、残ったものの信頼度は段階的に上がっていきます。この「歩留まりを犠牲にして純度を取る」方針が、SIFT を実用的なものにしました。
不変性の内訳 ― 何に強く、何に弱いか
ここまでの設計が、どの変化にどう効いているかを一覧にします。SIFT を使うか使わないかの判断は、たいていこの表のどこかに書いてあります。
| 変化の種類 | 効いている仕組み | 到達度 |
|---|---|---|
| 平行移動 | キーポイントを原点とする相対座標 | 完全 |
| スケール変化 | スケール空間の極値として σ を自動決定 | 完全 |
| 面内回転 | 勾配ヒストグラムのピーク θ で座標系を回す | 完全 |
| 明るさの加算 | 勾配(差分)を使うので定数は消える | 完全 |
| コントラスト変化 | 記述子ベクトルの L2 正規化 | 完全 |
| 非線形な照明変化 | 0.2 でのクリップと再正規化 | かなり強い |
| 画像ノイズ | ガウシアン平滑化とコントラスト閾値 | 強い |
| 部分的な遮蔽 | 点の集合として扱う設計そのもの | 3 点残れば可 |
| 視点変化(面外回転) | ガウシアン重みと三線形補間による緩衝 | 30〜50 度程度 |
| 大きなぼけ・被写体ぶれ | — | 弱い |
| 繰り返しパターン | 比率テストが機能しなくなる | 弱い |
| 模様のない平坦面 | — | 点が出ない |
下から三行が SIFT の限界です。ぼけた画像は勾配そのものが失われるので手の打ちようがありません。タイル張りの壁や整列した窓のような繰り返しパターンは、一位と二位が本当に同じくらい似ているため、比率テストが正しい対応まで棄却してしまいます。白い壁や空のような領域には、そもそも極値が立ちません。
視点変化については、面外回転が 50 度を超えたあたりから急速に崩れます。局所領域を平面として扱い、その平面が正対しているという暗黙の前提があるためです。この点を改善する試みが ASIFT(視点変換を明示的にシミュレートする手法)や、アフィン共変な領域検出器の系譜になります。
実装のツボ ― OpenCV で動かす
SIFT を自前で実装する機会は多くありませんが、パラメータの意味を知らないまま使うと、検出数が期待と合わずに悩むことになります。OpenCV の実装を例に、論文との対応を確認しておきます。
# SIFT で二枚の画像を対応づける最小構成
import cv2
import numpy as np
img1 = cv2.imread("scene_a.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("scene_b.jpg", cv2.IMREAD_GRAYSCALE)
sift = cv2.SIFT_create(
nfeatures=0, # 0 なら上限なし
nOctaveLayers=3, # 探索する DoG の枚数 s
contrastThreshold=0.04, # 内部で s で割られる点に注意
edgeThreshold=10, # 曲率比 r
sigma=1.6, # 第 0 層のぼかし
)
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# 各記述子について最近傍を 2 つ取る
matcher = cv2.BFMatcher(cv2.NORM_L2)
pairs = matcher.knnMatch(des1, des2, k=2)
# 比率テスト
good = [m for m, n in pairs if m.distance < 0.75 * n.distance]
# RANSAC でホモグラフィを当て、幾何に合わない対応を落とす
src = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
dst = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
H, mask = cv2.findHomography(src, dst, cv2.RANSAC, 3.0)
print("良い対応:", len(good), "/ 幾何整合:", int(mask.sum()))
つまずきやすい点
- contrastThreshold は論文の 0.03 と直接対応しません。 OpenCV は内部でこの値を nOctaveLayers で割ってから使います。既定の 0.04 と s = 3 なら実効閾値は約 0.0133。検出数が多すぎると感じたらここを上げます。
- 記述子は float32 で、値域は 0〜512 程度です。論文の単位ベクトルを 512 倍して整数域に載せた形なので、そのまま L2 距離を取って構いません。ただし他の実装と数値を比べるときはスケールの違いに注意が必要です。
- メモリは 1 点あたり 128 × 4 = 512 バイト。2,000 点で約 1 MB です。数万枚の画像を扱うなら、PCA による次元圧縮やプロダクト量子化が現実的な選択肢になります。
- 速度は概ね、640×480 の画像で数十ミリ秒から百数十ミリ秒(CPU 一コア)。リアルタイム用途では ORB などのバイナリ特徴に置き換えるのが一般的です。
- 入力はグレースケールが前提です。色情報は使われません。色を活かしたい場合はチャンネルごとに記述子を作る拡張(CSIFT、Opponent-SIFT など)があります。
SIFT の米国特許 6,711,293 は 2020 年 3 月に失効しました。これを受けて OpenCV 4.4.0 以降、SIFT は contrib(追加モジュール)から本体側へ移され、追加ビルドなしで利用できます。古い解説記事にある cv2.xfeatures2d.SIFT_create() という呼び方は、現在は cv2.SIFT_create() です。
他の手法との距離感
SIFT の登場後、より速い手法、よりコンパクトな手法が次々に提案されました。それぞれが SIFT のどこを引き継ぎ、どこを削ったのかを見ると、設計の勘所がはっきりします。
| 手法 | 年 | 検出の仕組み | 記述子 | 距離 | 速度の目安 |
|---|---|---|---|---|---|
| SIFT | 2004 | DoG の極値 | 128 次元 float | L2 | 基準(1×) |
| SURF | 2006 | ヘッセ行列式を積分画像で近似 | 64 次元 float | L2 | 3〜5 倍速 |
| ORB | 2011 | FAST + Harris で選別 | 256 bit バイナリ | Hamming | 数十倍速 |
| BRISK | 2011 | スケール空間上の FAST | 512 bit バイナリ | Hamming | 十数倍速 |
| AKAZE | 2013 | 非線形拡散のスケール空間 | 486 bit バイナリ | Hamming | 5〜10 倍速 |
| SuperPoint | 2018 | CNN による同時検出 | 256 次元 float | L2 | GPU 前提 |
SURF は、ガウシアン畳み込みを箱型フィルタで置き換え、積分画像を使って定数時間で計算する、という速度重視の再設計です。ORB はさらに割り切り、記述子を「二点の明るさ比較の結果を並べたビット列」にしました。ビット列なら XOR とビットカウントだけで距離が測れます。AKAZE は逆に、線形なガウシアンぼかしがエッジまでぼかしてしまう点を問題視し、非線形拡散でエッジを保ったスケール空間を作ります。
そして 2018 年前後から、検出も記述も学習で置き換える手法が実用段階に入りました。SuperPoint は畳み込みネットワークで検出と記述を同時に行い、LoFTR のように検出器自体を持たず、二枚の画像から直接密な対応を求める手法も現れています。これらは特にテクスチャの乏しい場面や、大きな視点変化のもとで SIFT を明確に上回ります。
それでも SIFT を学ぶ理由
- 今も現役で使われています。 三次元復元の標準的な実装である COLMAP をはじめ、多くの Structure-from-Motion パイプラインが既定の特徴量として SIFT を採用しています。
- 学習データもモデルも要りません。 どんな被写体、どんなドメインでも同じ性能で動きます。学習ベースの手法は訓練分布から外れると急に崩れることがあり、この安定性は今なお貴重です。
- CPU だけで完結します。 組込み機器やオフライン処理では、GPU を前提にできないことが珍しくありません。
- 比較の基準になります。 新しい特徴量の論文はほぼ必ず SIFT との比較を載せます。基準を理解していなければ、その比較の意味も読めません。
- 設計の教科書として優れています。 理論的な要請(ガウシアン核の一意性)、計算の工夫(DoG による近似)、経験的な調整(0.8 や 0.2 という定数)が一つの手続きの中に同居しており、実用的なアルゴリズムがどう組み立てられるかの見本になっています。
使われている場所
SIFT は単体で何かを解くアルゴリズムではなく、「二枚以上の画像の間に対応をつける」という基盤操作を提供します。その上に多くの応用が積み上がっています。
パノラマ合成
複数の写真をつなぎ合わせて広角画像を作る処理は、SIFT の最も直接的な応用です。Brown と Lowe による AutoStitch は、順序も指定されていない写真の束から、どれとどれが重なるかを SIFT の対応数だけで判定し、自動的に一枚に合成しました。スマートフォンのパノラマ機能の系譜はここに始まります。
三次元復元と SLAM
多数の写真から三次元形状とカメラ位置を同時に復元する Structure-from-Motion では、画像間の対応が入力そのものです。ロボットやドローンが自己位置と地図を同時に作る Visual SLAM でも、フレーム間の対応づけと、以前訪れた場所を再認識するループ閉じ込みの両方で局所特徴が使われます。
物体認識と画像検索
大量の記述子をクラスタリングして「視覚的な単語」の辞書を作り、画像を単語の出現頻度で表現する Bag of Visual Words は、深層学習以前の画像検索の主力でした。美術館の展示物を撮ると解説が出るアプリや、書影から書籍を特定する仕組みは、この系統の技術です。
位置合わせ全般
医用画像で撮影時期の異なる断層像を重ねる、人工衛星の画像から地表の変化を検出する、顕微鏡画像をタイル状につなぐ。「同じものを違う条件で撮った二枚を重ねたい」という問題は分野を問わず現れ、そのたびに局所特徴によるアプローチが検討されます。
よくある疑問
特許は今どうなっていますか
SIFT を保護していた米国特許 6,711,293(出願人はブリティッシュコロンビア大学)は、2020 年 3 月に存続期間が満了しました。したがって現在は商用利用を含めて自由に使えます。
この失効を受けて OpenCV は 4.4.0 で SIFT を本体モジュールへ移動しました。かつて「SIFT は特許があるので業務では避ける」という判断が一般的でしたが、その前提はすでに過去のものです。なお SURF については別途の特許があり、状況が異なります。
カラー画像はどう扱われますか
標準の SIFT はグレースケール画像だけを見ます。色の情報は完全に捨てられます。輝度の勾配だけで十分な識別力が得られること、そして色は照明の色温度で簡単に変わってしまうことが理由です。
色を活かしたい場合は、色空間の各チャンネルで記述子を作って連結する Opponent-SIFT や、色不変量を用いる CSIFT といった拡張があります。ただし次元が三倍になるため、得られる識別力の向上に見合うかどうかは用途次第です。
深層学習の時代に、SIFT を学ぶ意味はありますか
あります。実務上の理由としては、学習不要で任意のドメインに使えること、CPU で動くこと、そして SfM のような確立したパイプラインで今も既定の選択であることが挙げられます。
教育上の理由はもっと大きいかもしれません。SIFT には、理論から導かれた必然(ガウシアン核以外は使えない)、計算のための巧妙な近似(DoG)、実験で決めた妥協(0.8、0.2、r = 10)が、一つの手続きの中に整然と並んでいます。アルゴリズムを設計するとはどういう営みかを、これほど見通しよく示す例は多くありません。
何点くらい検出できれば十分ですか
目的によります。二枚の画像の間のホモグラフィを求めるだけなら、幾何的には正しい対応が 4 組あれば足り、実用上も数十組あれば安定します。Lowe は物体認識について、正しい対応が 3 組あれば姿勢を推定できると述べています。
一方、検出された総数が数十点しかない場合は、その画像に模様が乏しいというサインです。閾値を緩めて無理に増やすより、撮影条件を見直すか、密な対応を求める別の手法を検討したほうが早いことが多いです。
比率テストの閾値は 0.8 のままでよいですか
出発点としては妥当ですが、調整の余地はあります。誤対応を極力避けたい用途、たとえば RANSAC を回す余裕がない場面では 0.7 前後まで下げます。逆に、重なりが少なく対応がそもそも希少な場面では 0.85 程度まで緩め、幾何的検証で選別する構成が有効です。
繰り返しパターンを含む被写体では、閾値をどう動かしても比率テストが機能しません。この場合は空間的な整合性を先に使う、あるいは対応の一対一制約を明示的に課すといった別の対策が必要になります。
用語のおさらい
- スケール空間
- 同じ画像をさまざまな強さでぼかしたものを並べた表現。「どの大きさで見るか」を連続的な軸として扱うための道具立て。
- オクターブ
- ぼかしの強さ σ が 2 倍になるまでの一区切り。次のオクターブでは画像を縦横 1/2 に間引いて計算量を抑える。
- DoG
- Difference of Gaussian。ぼかしの強さが異なる二枚の差分画像。正規化ラプラシアンの安価な近似として使われる。
- キーポイント
- 特徴点。位置 (x, y)、スケール σ、向き θ を持つ点。SIFT の検出段階の出力。
- 記述子
- キーポイント周辺の見え方を表す数値ベクトル。SIFT では 128 次元。
- 再現率
- Repeatability。撮影条件を変えたときに、同じ物理的な位置が再び検出される割合。検出器の良さを測る基本的な指標。
- 比率テスト
- 最近傍距離と第二近傍距離の比で対応の信頼度を判定する手法。Lowe's ratio test とも呼ばれる。
- インライア
- 推定した幾何変換に整合する対応。整合しないものはアウトライア(外れ値)。
- ホモグラフィ
- 平面どうしを結ぶ射影変換。3×3 行列で表され、4 組の対応から推定できる。
- RANSAC
- ランダムに選んだ少数の対応から仮説を立て、支持数の最も多い仮説を採用することで外れ値に強い推定を行う枠組み。
おわりに
SIFT を一文にまとめるなら、「どの大きさで見るかを画像自身に決めさせ、どちらを上とするかも画像自身に決めさせ、その座標系の上で勾配の分布を記録する」手続きです。不変性は魔法ではなく、決められるものを先に決め切ってしまう、という地道な段取りから生まれています。
二十年以上前に提案された手法が今も参照され続けているのは、それが単に速かったからでも、精度が高かったからでもありません。解くべき問題を正しく分解し、各部分に理由のある答えを置いたからです。新しい手法を読むときにも、この分解の仕方は物差しとして役に立ちます。
higuchi
Public Relations Tokyo ‒ Developer
画像処理と個人開発を軸に活動しています。古典的なアルゴリズムは、論文を読んで理解したつもりになっても、実際に手を動かして動かしてみるとまるで違う顔を見せる。その落差が面白くて、理屈と実装の両方を行き来しながらアプリを作っています。
この解説ページは、Android アプリ「Camera de SIFT」を作る過程で調べ直した内容をまとめたものです。数式を追うだけでは腑に落ちなかった部分こそ、丁寧に図にする価値があると考えて構成しました。同じところでつまずいた方の助けになれば嬉しく思います。
- Focus画像処理 / コンピュータビジョン / モバイルアプリ開発
- WorksCamera de SIFT(Android)ほか
- Contactpccsoftware@gmail.com
紙の上の数式を、レンズの向こうで確かめる
ここまで読んだ手続きが実際に動く Android アプリ「Camera de SIFT」が Google Play で公開されています。スケール空間から 128 次元記述子まで、図と式で追ってきたものが手元の端末でどう振る舞うのか。一度動かしてみると、定数の一つひとつが選ばれた理由も違って見えてきます。
Google Playアプリを入手する