画像中の意味のある構造を自動で抽出・関連付ける技術は、コンピュータビジョンの基盤となる。本稿では、OpenCVを用いた代表的な角点検出アルゴリズム(Harris、Shi-Tomasi、FAST)の原理と実装を、数学的直感と実用性の両面から解説する。
Harris法:自己相関行列に基づく局所変化の評価
Harris検出器は、各画素近傍における輝度変化の方向依存性に着目する。その核となるのは、勾配ベクトルの外積から構成される自己相関行列 M である:
M = Σ [Iₓ², IₓI_y; IₓI_y, I_y²]
ここで Iₓ, I_y はx・y方向の画像勾配。この行列の固有値がともに大きい場合、その位置は「すべての方向で輝度が急変する」角点と判断される。実装上は、行列式とトレースを用いた近似スコア R = det(M) − k·tr(M)² を計算し、閾値処理と非極大抑制により候補を絞り込む。
以下はOpenCVによる再構成コード(パラメータ名を明示的に再命名し、処理フローを可視化可能にした):
import cv2
import numpy as np
def detect_harris_corners(image_path: str, threshold_ratio: float = 0.01):
src = cv2.imread(image_path)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY).astype(np.float32)
# Harrisスコアマップ生成(ブロックサイズ=2、Sobelカーネル=3、k=0.04)
harris_map = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
# スコアの正規化と膨張(検出点の視認性向上)
harris_map = cv2.normalize(harris_map, None, 0, 255, cv2.NORM_MINMAX)
harris_map = cv2.dilate(harris_map, kernel=np.ones((3,3)))
# 閾値付きマスク作成(最大値のthreshold_ratio倍以上)
mask = harris_map > (threshold_ratio * harris_map.max())
# 元画像への赤色マーカー描画
result = src.copy()
result[mask] = [0, 0, 255]
return result, harris_map
# 使用例
output_img, score_map = detect_harris_corners("scene.jpg")
cv2.imwrite("harris_output.png", output_img)
Shi-Tomasi法:固有値最小値による厳密な角点判定
Shi-TomasiはHarrisの改良版であり、「最も小さい固有値」を直接スコアとして利用する。これは「少なくとも一つの方向で変化が小さい=エッジではない」という物理的直感に基づき、より信頼性の高い角点選択を実現する。OpenCVでは cv2.goodFeaturesToTrack() で実装されており、検出数・品質閾値・最小間隔を制御可能である。
def detect_shitomasi_corners(image_path: str, max_count: int = 30, quality: float = 0.02):
src = cv2.imread(image_path)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# Shi-Tomasi検出(固有値最小値ベース)
corners = cv2.goodFeaturesToTrack(
gray,
maxCorners=max_count,
qualityLevel=quality,
minDistance=12,
blockSize=7
)
# 検出点を円で可視化
result = src.copy()
if corners is not None:
for corner in corners:
x, y = map(int, corner.ravel())
cv2.circle(result, (x, y), radius=4, color=(0, 255, 0), thickness=-1)
return result
# 使用例
shitomasi_result = detect_shitomasi_corners("scene.jpg")
cv2.imwrite("shitomasi_output.png", shitomasi_result)
FAST法:16点リングテストによる高速検出
FASTは、中心画素を囲む16点の離散円周上で「連続する12点以上が中心より明るいか暗いか」を判定するシンプルなルールに基づく。計算量が極めて少ないため、リアルタイムアプリケーションに適している。ただし、単独では方向不変性やスケール不変性を持たないため、通常ORBパイプラインの一部として利用される。
def detect_fast_keypoints(image_path: str, suppress_nonmax: bool = True):
src = cv2.imread(image_path)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# FAST検出器の初期化
detector = cv2.FastFeatureDetector_create(
threshold=20,
nonmaxSuppression=suppress_nonmax
)
# キーポイント検出
keypoints = detector.detect(gray, None)
# 可視化(赤色ドット)
result = cv2.drawKeypoints(
src, keypoints, None,
color=(255, 0, 0),
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)
return result, len(keypoints)
# NMS有無の比較
with_nms, n_with = detect_fast_keypoints("scene.jpg", suppress_nonmax=True)
without_nms, n_without = detect_fast_keypoints("scene.jpg", suppress_nonmax=False)
print(f"NMS有: {n_with}点, NMS無: {n_without}点")
cv2.imwrite("fast_with_nms.png", with_nms)
cv2.imwrite("fast_without_nms.png", without_nms)
アルゴリズム選択の指針
- Harris:幾何的整合性が求められるタスク(例:ホモグラフィ推定)で安定。ノイズ耐性は中程度。
- Shi-Tomasi:検出点の品質優先(例:光流追跡)。Harrisより厳密だが、検出数がやや少ない傾向。
- FAST:速度重視のリアルタイム系(例:モバイルAR)。後処理(BRIEF記述子+FLANNマッチング)との組み合わせが必須。