勉強しないとな~blog

ちゃんと勉強せねば…な電気設計エンジニアです。

OpenCVやってみる-20. 特徴点のマッチング(FLANN)

前回のやり残しで、FLANNでの特徴点マッチングをやります。

OpenCV: Feature Matching

特徴点のマッチング — OpenCV-Python Tutorials 1 documentation

概要

前回のおさらいですが、FLANNはFast Library for Approximate Nearest Neighborの略で、近似的に特徴量空間での最近傍点を探索する手法です。総当たりマッチングより高速で実施することができます。

やること

前回はcv2.BFMatcher()でマッチングしましたが、今回はcv2.FlannBasedMatcher()を使います。

これは2つのdict型オブジェクトを引数に取ります。
dictが何なのか分かっていないのでググる

Pythonで辞書を作成するdict()と波括弧、辞書内包表記 | note.nkmk.me

dictは辞書オブジェクトで、キーと値をペアで保持するものとのこと。
キー、値の型はある程度制限はあるものの、文字列および整数でないといけない、ということはなさそう。

【Python】 辞書(dict)の使い方の基本 | Hbk project

【Python】辞書型変数(dictionary) - Qiita

なぜcv2.FlannBasedMatcher()の引数をdict型で与えないといけないかはわかりませんが、とりあえず使ってみます。

使用画像

前回と同じシャルトル大聖堂です。

img_both = cv2.imread('Chartres_both.JPG')
img_right = cv2.imread('Chartres_right.JPG')
img_left = cv2.imread('Chartres_left.JPG')
img_both = cv2.resize(img_both, None, fx=0.25, fy=0.25, interpolation=cv2.INTER_AREA)
img_right = cv2.resize(img_right, None, fx=0.25, fy=0.25, interpolation=cv2.INTER_AREA)
img_left = cv2.resize(img_left, None, fx=0.25, fy=0.25, interpolation=cv2.INTER_AREA)
cv2.imshow('Image both', img_both)
cv2.imshow('Image right', img_right)
cv2.imshow('Image left', img_left)

f:id:nokixa:20210822102202p:plain:w400
シャルトル大聖堂両サイド

f:id:nokixa:20210822102317p:plain:w400
シャルトル大聖堂 向かって右側

f:id:nokixa:20210822102445p:plain:w400
シャルトル大聖堂 向かって左側

実施

SIFTで特徴点マッチングして、前回の総当たりマッチングと比較します。

sift = cv2.SIFT_create()
kp_both, des_both = sift.detectAndCompute(img_both, None)
kp_right, des_right = sift.detectAndCompute(img_right, None)
kp_left, des_left = sift.detectAndCompute(img_left, None)

FLANNのオブジェクトは、SIFTを使う場合は以下のように生成します。

FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

index_paramsアルゴリズムの選択、および関連パラメータのよう。 使用する特徴点検出器によって変えるといいようです。今回のSIFTでは1を選択していますが、ORBだと6(FLANN_INDEX_LSH)が良いようです。

search_paramsは、「インデックス中の木構造再帰的にたどっていく回数」とのこと。 これを増やすと精度が上がりますが、実行時間が伸びます。

あとはマッチングを実施しますが、チュートリアルではratio testをやっていました。
今回はこれに倣います。

matches_right = flann.knnMatch(des_both, des_right, k=2)
good_matches_right = []
for m,n in matches_right:
    if m.distance < 0.7*n.distance:
        good_matches_right.append([m])

最後に結果を表示します。

img_matches_right = cv2.drawMatchesKnn(img_both, kp_both, img_right, kp_right, good_matches_right[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('Matches right', img_matches_right)

f:id:nokixa:20210828014728p:plain

結果は前回より悪くなってしまった…
シャルトル大聖堂向かって左側は、

matches_left = flann.knnMatch(des_left, des_both, k=2)
good_matches_left = []
for m,n in matches_left:
    if m.distance < 0.7*n.distance:
        good_matches_left.append([m])

img_matches_left = cv2.drawMatchesKnn(img_left, kp_left, img_both, kp_both, good_matches_left[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('Matches left', img_matches_left)

f:id:nokixa:20210828015435p:plain

こちらはまだ上の結果よりましですが、1つ明らかな誤検出があるので、前回と比べれば精度は落ちています。

扱う画像ごとにパラメータを調整したりしないといけないのか?

以上

前回総当たりマッチングをやっていましたが、その際は特に体感的に処理が遅い、ということはなく、実行してすぐに終わっていました。なのでFLANNのメリットを得ることができず。

次はチュートリアル通りで、特徴点マッチングとHomographyでの物体検出にします。