はじめに:人間には簡単、コンピュータには激ムズ?
突然ですが、以下の写真を見てください。
これらが「同じ風景」や「同じ猫」であることは、私たち人間なら一瞬で分かりますよね。
しかし、これをコンピュータに判別させるとなると、話は別です。
画像処理の世界では、以下のような変化が大きな障壁となります。
- スケール(大きさ)が違う
- 回転している
- 明るさ(照明)が違う
- 同じ対象でもピクセル単位で等しくない
これらを乗り越えて、画像の中から「変わらない特徴」を見つけ出す技術。それが今回紹介する SIFT(Scale-Invariant Feature Transform) です。
この記事では、大学のゼミで作成した講義スライドをベースに、SIFTの仕組みと実装方法を分かりやすく解説します。
全スライドまとめ
本記事のベースとなったスライド資料はこちらです。
1. SIFT(Scale-Invariant Feature Transform)とは?
SIFTは、画像のスケール、回転、明るさの変化に影響されずに、画像中の特徴点(キーポイント)を検出・記述するアルゴリズムです。
ディープラーニングが流行する前は、物体認識や画像合成の「王様」のような存在でした。現在でも、学習データが用意できない場合や、計算資源が限られる環境では非常に強力な選択肢です。
SIFTのすごいところ
SIFTが画期的だったのは、以下の「堅牢性(Robustness)」を兼ね備えていた点です。
| 特徴 | 説明 |
|---|---|
| スケール不変性 | 対象の大きさが変わっても特徴量は変化しない |
| 回転不変性 | 対象が回転しても大丈夫 |
| 照明変化への堅牢性 | 明るさやコントラストが変わっても認識可能 |
2. Python + OpenCVで3分実装
理屈の前に、まずは動かしてみましょう。
SIFTはかつて特許の壁がありましたが、現在は特許が切れ、OpenCVの標準機能として誰でも手軽に使えます。
import cv2 as cv
# 1. 画像の読み込み
img = cv.imread('cake.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 2. SIFTオブジェクトの作成
sift = cv.SIFT_create()
# 3. 特徴点の検出と特徴量の計算
# kp: 特徴点のリスト, des: 特徴量記述子(128次元のベクトル)
kp, des = sift.detectAndCompute(gray, None)
# 4. 結果の描画
img_sift = cv.drawKeypoints(
img, kp, None,
flags=cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)
# 表示(Colab等の場合)
# from google.colab.patches import cv2_imshow
# cv2_imshow(img_sift)
たったこれだけのコードで、画像から堅牢な特徴点を抽出できます。
3. SIFTの仕組み:なぜそんなに強いのか?
ここからは、SIFTがどのようにして「回転しても、大きさが変わっても大丈夫」な特徴量を作り出しているのか、そのアルゴリズムを4つのステップで図解します。
全体像
SIFTの処理は大きく分けて 「特徴点の検出」 と 「特徴量の記述」 の2段階、細かく見ると以下の4ステップになります。
- 候補点の探索(スケール空間の極値検出)
- 候補点の絞り込み(キーポイントのローカライズ)
- 方向の検出(オリエンテーションの割り当て)
- 特徴量の記述(記述子の生成)
ここからは各ステップを詳しく見ていきます。
Step 1: 候補点の探索(スケール不変性の獲得)
画像の中から「特徴的な点」を探す工程ですが、SIFTの最大の特徴は 「わざと画像をぼかして、様々なスケールの画像を用意する」 点にあります。
具体的には、DoG (Difference of Gaussian) 画像というものを作ります。
これは、「少しぼかした画像」と「もっとぼかした画像」の差分をとった画像です。こうすることで、エッジなどの変化が激しい部分が浮かび上がります。
これを様々なスケール(ぼかし具合)で行い、その中で極値(周囲と比べて際立って値が大きい/小さい点) を探します。
これによって、「遠くから見ても(小さいスケール)」、「近くで見ても(大きいスケール)」特徴的である場所を見つけ出すことができます。これがスケール不変性の正体です。
Step 2: 候補点の絞り込み
Step 1で見つかった点には、ノイズや、特徴としては弱い「エッジ(線)上の点」も含まれています。
そこで、ヘッセ行列という数学的な道具を使って、コーナー(角)のように 「縦横どちらの方向に動かしても変化が大きい点」 だけを厳選して残します。
💡 深掘り:なぜ「ヘッセ行列」でエッジとコーナーが見分けられるのか?
SIFTのアルゴリズムの中で、数学的に最も面白いのがこの「絞り込み」のプロセスです。ここを直感的に理解するために、視点を少し変えてみましょう。
「画像を2次元の平面ではなく、輝度を高さ(標高)と見立てた3次元の地形として捉える」 のです。
1. 画像を「地形」として見る
まず、以下の図を見てください。明るい画素を「高い山」、暗い画素を「低い谷」としてプロットすると、画像はこのようなデコボコした地形になります。

図:輝度(Brightness)を地形の高さ(Height)として可視化したイメージ
SIFTにおける「特徴点探し」とは、この広大な地形の中から、「他と区別しやすい特別な場所(ランドマーク)」 を見つける旅のようなものです。
そのために使われるヘッセ行列は、足元の地面が「どの方向に、どれくらい曲がっているか(曲率)」を教えてくれるコンパスの役割を果たします。ここから得られる2つの固有値(曲がり具合の強さ)を見ることで、足元の形状が分かります。
2. エッジ(Edge)=「かまぼこ型の屋根」
エッジ上の点は、立体的には「かまぼこ型の屋根」や「トンネル」のような形状をしています。
図の矢印に注目してください。
- 🟥 赤い矢印(STEEP CURVE): 横方向には急激に曲がっています(=固有値 $\alpha$ が大きい)。
- 🟦 青い矢印(FLAT DIRECTION): しかし、尾根に沿った縦方向は真っ平らです(=固有値 $\beta$ が小さい)。
この場所に立った時、青い矢印の方向に少し移動しても、景色(数値)はほとんど変わりません。つまり、「位置ズレに弱い(どこにいるか特定しにくい)」 のです。
そのため、SIFTはこの点を「不安定」とみなして削除します。
3. コーナー(Corner)=「尖った山頂」
一方、SIFTが探し求めているコーナーは、「尖った山頂」のような形状です。
こちらも矢印を見てみましょう。
- 🟥 赤い矢印(STEEP SLOPE): どの方向に降りようとしても、急な坂になっています。
これは、2つの固有値が共に大きい($\alpha$ も $\beta$ も大きい) 状態です。
この場所に立てば、どの方向に少し動いても景色が劇的に変わります。つまり、「位置を一点に特定しやすい」 ということです。
SIFTはヘッセ行列を使ってこの「山頂」のような形状だけを厳選することで、ノイズや位置ズレに負けない強固な特徴点を抽出しているのです。
Step 3: 方向の検出(回転不変性の獲得)
特徴点の場所が決まったら、その点が「どっちを向いているか」を決めます。
特徴点の周囲の画素を見て、勾配(明るさの変化方向)を集計します。最も強い勾配の方向を、その特徴点の 「主方向」 として定義します。
この後、画像を回転させても、この「主方向」を基準に特徴量を記述すれば、回転の影響をキャンセルできるわけです。
Step 4: 特徴量の記述(128次元ベクトル)
最後に、特徴点の特徴を数値化(ベクトル化)します。
特徴点の周囲を16個のブロック(4×4)に分け、それぞれのブロックで8方向の勾配情報を集計します。
$$4 \times 4 \times 8 = 128$$
これにより、1つの特徴点は128次元のベクトルとして表現されます。これがSIFT特徴量です。
この際、光の強さの影響を受けないように正規化を行うことで、照明変化への堅牢性も獲得しています。
4. まとめ:SIFTの強さの秘密
SIFTがなぜこれほどまでに使い勝手が良いのか、各ステップがどのように堅牢性に寄与しているかをまとめました。
| 堅牢性の種類 | 実現しているステップ | 理由 |
|---|---|---|
| スケール不変性 | Step 1 | DoG画像を用いて適切なスケールを探索しているから |
| 回転不変性 | Step 3, 4 | 特徴点の「主方向」を基準に記述しているから |
| 照明変化への堅牢性 | Step 4 | 勾配情報を正規化しているから |
| ノイズ・ズレへの堅牢性 | Step 2, 4 | 不安定な点を除去し、情報を大まかに(ヒストグラム化)集計しているから |
深層学習全盛の時代ですが、学習データ不要で、数行のコードでこれだけ堅牢な特徴抽出ができるSIFTは、現在でも非常に強力なツールです。
ぜひ、皆さんの画像処理アプリケーションでも活用してみてください!
参考文献
資料作成の際に、こちらの資料を大変参考にさせていただきました。ありがとうございます。


















