はじめに
前回のQiitaの記事ではAkazaのおかげで特徴点マッチングを実現することができた。今回は、その特徴点の座標を取得し、より数学的に画像を扱えるように加工していく。
環境
OS : Ubuntu 20.04 LTS
Python : 3.8.10
OpenCV-Python : 4.6.0
特徴点の詳細データを取得
前回のプログラムの続きから説明します。前回のプログラムに関する記事はこの記事の「はじめに」に書かれています。
kp1,des1 = detector.detectAndCompute(gray_image1,None)
kp2,des2 = detector.detectAndCompute(gray_image2,None)
bf = cv2.BFMatcher()
matches = bf.match(des1,des2)
matches = sorted(matches,key = lambda x:x.distance)
# 追加ここから
for x in range(len(matches[:20])):
print(kp1[matches[x].queryIdx].pt)
print(kp2[matches[x].trainIdx].pt)
image1list.append(kp1[matches[x].queryIdx].pt)
image2list.append(kp2[matches[x].trainIdx].pt)
print("---------------------------------------------")
# 追加ここまで
では一行ずつ説明していきたいと思います。
1.for文のmatchesについて
みなさんに嫌がらせをします。この星の数を数えてください。(しなくていいです)
この答えはほぼ無限にありますよね。実は特徴点マッチングでも同じことが言えて、特徴点は無限にあります。
無駄に多くの特徴点を捉えるとプログラムの動作を重くしたり、人間が理解しにくくさせたりするので厄介です。今回は”20”という値を設定しましたが、これはあくまで私が理解しやすい数値です。
for x in range(len(matches[:20])):
みなさんが開発するときに適宜数字を変えて開発を進めてください。
2.kp1[],kp2[]について
K~P~(乾杯)のノリではありません。(多分、K~P~は3年後は死語)
kp1は[des1,des2]で処理された類似点データをもとに座標やサイズなどのデータを取り出しやすくするための変数という感覚で捉えてください。
print(kp1[matches[x].queryIdx].pt)
print(kp2[matches[x].trainIdx].pt)
x
という変数にはfor
で繰り返された回数の数字が代入されています。したがってmatches
のx個目を取得しています。
次に.queryIdx
と.trainIdx
についですが、これは元画像と比較対象画像のデータを取得するOpenCVの変数です。(detectAndComputeで処理されたキーポイントのインデックスです)
百聞は一見に如かず、どんな値が帰ってくるのかを実際に見てみましょう
print(matches[0].distance)
print(matches[0].trainIdx)
print(matches[0].queryIdx)
print(matches[0].imgIdx)
# -----出力-----
121.76616668701172
214
207
0
3. [~queryIdx].ptのptってなんですか?
keypointオブジェクトは以下の属性を持っています。
- pt:キーポイントの座標(ヒント:タプルで(x,y)が戻り値として返ってきます)
- size:キーポイント周辺の重要領域の直径
- angle:計算されたキーポイントの方向(計算できない場合は -1 )
- response:最も強いキーポイントが選択されたときの応答
- octave:キーポイントが抽出されるオクターブ(ピラミッドの階層)
- class_id:オブジェクトクラス
pt以外今のところまだ使ったことがないので、使い次第、上のリストにヒントを追記していきます。
これも百聞は一見に如かず、例を見てみましょう
print(kp1[0].pt)
print(kp1[0].size)
print(kp1[0].angle)
print(kp1[0].response)
print(kp1[0].octave)
print(kp1[0].class_id)
# -----出力-----
(60.0, 129.0)
31.0
276.7517395019531
0.001297724898904562
0
-1
4.最後にndarrayに変換!
ndarrayはnumpy
の変数の一つです。プログラムの先頭にインポートすることをお忘れなく...
import cv2
# 追加ここから
import numpy as np
# 追加ここまで
次に必ずプログラムの先頭らへんにimage1list
とimage2list
というリストを準備しておきましょう。
理由は、for
のプログラムで処理したタプルの座標データを二つのimage{}list
リストに.appendしているからです。全体プログラムを見てみてください
最後にPythonのリストをndarrayに変換するためfor文の外で以下のプログラムを実行するだけです。
resultbefore = np.array(image1list,dtype=float)
resultafter = np.array(image2list,dtype=float)
長い記事を読んでいただきありがとうございました。
貫徹。