特徴点検出
動画チュートリアル16 - 特徴点の検出と保存: https://singtown.com/learn/50021/
テンプレートマッチングと特徴点検出の比較:
テンプレートマッチング (find_temolate) は ncc アルゴリズムを使用しており、基本的にテンプレート画像と同じサイズ・角度のパターンしかマッチングできません。この制限は比較的大きく、視野内の 対象パターンがテンプレート画像よりわずかに大きい、または小さいだけでもマッチングが成功しない場合があります。
テンプレートマッチングは、カメラと対象物体との距離が一定で、動的な動きを想定しない状況に適しています。例えば組立ラインでの特定物体の検出には 適していますが、動くバレーボールを車で追跡するような用途には適していません(動くバレーボールとカメラとの距離は常に変化するため、カメラに映る バレーボールのサイズも変化し、テンプレート画像と完全には一致しなくなるためです)。
多角度・多サイズのマッチングを行いたい場合は、複数のテンプレートを保存しておき、複数テンプレート マッチング を使用してみてください。
特徴点検出 (find_keypoint): プログラムの実行を開始したばかりの場合、このルーチンは最初のフレームの画像を対象物体の特徴として抽出し、kpts1 に対象物体の特徴を保存します。 デフォルトでは、特徴を保存した時点のサイズ・角度だけでなく、対象特徴の複数のスケールと角度でマッチングを行います。テンプレートマッチングより 柔軟で、複数テンプレートマッチングのように複数のテンプレート画像を保存しておく必要もありません。
特徴点検出でも、対象特徴を事前に保存しておくことができます。以前は、周囲光などの影響でプログラムを実行するたびに照明条件が異なり、抽出される 特徴も変化してマッチング度が低下する恐れがあったため、この方法は推奨されていませんでした。しかし最新版のファームウェアでは、露出、ホワイト バランス、自動ゲイン値の調整機能が追加され、露出値とホワイトバランス値を手動で指定できるようになったため、光の影響を相対的に抑えられるように なりました。事前に対象特徴を保存する方法も試してみる価値があります。
特徴点検出
このルーチンは 09-feature-Detection-keypoints.py です。\ このルーチンは特徴抽出とターゲット追跡に FAST/AGAST アルゴリズムを使用しており、グレースケール画像のみをサポートします。
注:このルーチンは、プログラム開始後最初の10秒間にカメラに映った物体を対象特徴として使用します。プログラム開始時には対象物体を カメラの中央に配置し、特徴のコーナー点が表示されるまでそのままにしてください。コーナー点が表示されれば、対象特徴が識別・記録された ことを示します。
マッチング処理中に画面上に十字と矩形の枠が表示されれば、マッチングが成功したことを示します
# 特徴点検出を利用して特定の物体を検出するルーチン。
# カメラに対象物を映してからこのスクリプトを実行してください。キーポイントの集合が一度だけ抽出され、
# 以降のフレームで追跡されます。新しいキーポイントの集合が欲しい場合は、スクリプトを再実行してください。
# 注意:find_keypoints と match_keypoints の調整については、ドキュメントを参照してください。
import csi, time, image
csi0 = csi.CSI()
# センサーをリセットする
csi0.reset()
# センサーの設定
csi0.framesize(csi.VGA)
csi0.window((320, 240))
csi0.pixformat(csi.GRAYSCALE)
csi0.snapshot(time = 2000)
csi0.auto_gain(False)
# 特徴点を描画する
def draw_keypoints(img, kpts):
if kpts:
print(kpts)
img.draw_keypoints(kpts)
img = csi0.snapshot()
time.sleep_ms(1000)
kpts1 = None
# kpts1 には対象物体の特徴を保存する。ファイルから特徴をインポートすることもできるが、推奨されない。
#kpts1 = image.load_descriptor("/desc.orb")
#img = csi0.snapshot()
#draw_keypoints(img, kpts1)
clock = time.clock()
while (True):
clock.tick()
img = csi0.snapshot()
if (kpts1 == None):
# プログラムを実行し始めたばかりの場合、最初の画像を対象物体の特徴として抽出し、kpts1 に対象物体の特徴を保存する
# デフォルトでは、特徴を保存した時点のサイズだけでなく、対象特徴の複数のスケールでマッチングを行うため、テンプレートマッチングより柔軟である。
# 注:デフォルトでは find_keypoints は画像ピラミッドから抽出したマルチスケールのキーポイントを返す。
kpts1 = img.find_keypoints(max_keypoints=150, threshold=10, scale_factor=1.2)
#image.find_keypoints(roi=Auto, threshold=20, normalized=False, scale_factor=1.5, max_keypoints=100, corner_detector=CORNER_AGAST)
# roi は認識する領域を表し、タプル(x, y, w, h)で指定する。デフォルトでは framesize と同じ大きさになる。
# threshold は 0~255 のしきい値で、特徴点検出におけるコーナー点の数を制御する。デフォルトの AGAST 特徴点検出ではこのしきい値は概ね 20、FAST 特徴点検出では概ね 60~80 である。しきい値が低いほど、得られるコーナー点は多くなる。
# normalized は真偽値で、デフォルトは False であり、対象特徴の複数のサイズにマッチングできる(ncc テンプレートマッチングより柔軟)。True に設定すると、特徴点検出のマルチスケール結果が無効になり、対象特徴の1つのサイズのみにマッチングするようになる(テンプレートマッチングに近い挙動になる)が、その分演算速度は速くなる。
# scale_factor は 1.0 より大きい浮動小数点数である。この値が大きいほど検出速度は速くなるが、マッチング精度は低下する。一般的には 1.35~1.5 前後が最適である。
# max_keypoints は1つの物体から抽出できる特徴点の最大数である。物体の特徴点が多すぎて RAM メモリが不足する場合は、この値を小さくする。
# corner_detector は特徴点検出に使用するアルゴリズムで、デフォルトは AGAST アルゴリズムである。FAST アルゴリズムはより高速だが、精度は低下する。
draw_keypoints(img, kpts1)
# このときの対象特徴を描画する
else:
# 最初の対象特徴とマッチングする際は、デフォルトで normalized=True に設定し、対象特徴の1つのサイズのみとマッチングする。
# 注:最初のディスクリプタとマッチングするためのキーポイントを抽出する際は、normalized=True を使用して
# 最初のスケールのみからキーポイントを抽出し、最初のディスクリプタ内のいずれかのスケールとマッチングさせる。
kpts2 = img.find_keypoints(max_keypoints=150, threshold=10, normalized=True)
# 特徴物体が検出された場合
if (kpts2):
# 現在見つかった特徴と最初の対象特徴との類似度をマッチングする
match = image.match_descriptor(kpts1, kpts2, threshold=85)
# image.match_descriptor(descritor0, descriptor1, threshold=70, filter_outliers=False)。この関数は kptmatch オブジェクトを返す。
# threshold しきい値はマッチングの精度を設定し、あいまいなマッチングを除外するために使用する。この値が小さいほど精度は高くなる。しきい値の範囲は 0~100 で、デフォルトは 70 である。
# filter_outliers はデフォルトで無効になっている。
# match.count は kpt1 と kpt2 の間でマッチングした近似特徴点の数である。
# 10 より大きければ、2つの特徴が類似しており、マッチングが成功したことを示す。
if (match.count>10):
# 少なくとも n 個の「良好なマッチング」がある場合
# バウンディングボックスと十字を描画する。
# マッチングした対象特徴の中心に十字と矩形枠を描画する。
img.draw_rectangle(match.rect)
img.draw_cross((match.cx, match.cy), size=10)
# match.theta はマッチングした特徴物体の対象物体に対する回転角度である。
print(kpts2, "matched:%d dt:%d"%(match.count, match.theta))
# draw_keypoints で特徴コーナー点を描画することは推奨されない。
# 注:キーポイントを描画したい場合はコメントを解除する
#img.draw_keypoints(kpts2, size=KEYPOINTS_SIZE, matched=True)
# FPS を描画する
# フレームレートを表示する。
img.draw_string((0, 0), "FPS:%.2f"%(clock.fps()))
プログラムを実行した際の効果:

