学習不要で特徴点のマッチング LightGlue 【Python】

AI
スポンサーリンク
スポンサーリンク

はじめに

前回は Mask3D のデモを動かしてみました。

今回は、学習無しで特徴点のマッチングを行うことができる LightGlue を動かしてみます。

githubはこちらです。

前提条件

前提条件は以下の通りです。

  • Windows11
  • Python3.10
  • pytorch==1.13.1+cu117

LightGlue のインストール

インストールは簡単です。

git clone https://github.com/cvg/LightGlue.git && cd LightGlue
python -m pip install -e .

torchがインストールされてしまうかもしれないので、この後にtorchのGPUを確認するのをお勧めします。

デモプログラム

デモプログラムを以下のようにします。

demo.py

from lightglue import LightGlue, SuperPoint, DISK, SIFT, ALIKED, DoGHardNet
from lightglue.utils import load_image, rbd
from lightglue import viz2d
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt

# SuperPoint+LightGlue
extractor = SuperPoint(max_num_keypoints=2048).eval()  # load the extractor
matcher = LightGlue(features='superpoint').eval()  # load the matcher

# load each image as a torch.Tensor on GPU with shape (3,H,W), normalized in [0,1]
image0 = load_image('./A.png')
image1 = load_image('./B.png')

# extract local features
feats0 = extractor.extract(image0)  # auto-resize the image, disable with resize=None
feats1 = extractor.extract(image1)

# match the features
matches01 = matcher({'image0': feats0, 'image1': feats1})
feats0, feats1, matches01 = [rbd(x) for x in [feats0, feats1, matches01]]  # remove batch dimension

kpts0, kpts1, matches = feats0["keypoints"], feats1["keypoints"], matches01["matches"]
m_kpts0, m_kpts1 = kpts0[matches[..., 0]], kpts1[matches[..., 1]]

axes = viz2d.plot_images([image0, image1])
viz2d.plot_matches(m_kpts0, m_kpts1, color="lime", lw=0.2)
viz2d.add_text(0, f'Stop after {matches01["stop"]} layers', fs=20)

viz2d.save_plot("C.png")

A.png と B.png は以下の画像を用意しました。

上記のプログラムを実行すると、C.png が出力されます。

スマホで適当に撮影した画像ですが、しっかり特徴点のマッチングができていますね。

特徴点の集合から矩形を作成

続いて、特徴点の集合から矩形を作成していきます。

こちらの github に掲載がありました。

以下のプログラムを追加してください。

tl = m_kpts1.min(dim=-2).values  # top-left corner
br = m_kpts1.max(dim=-2).values  # bottom-right corner
axes = plt.gcf().axes
axes[1].add_patch(Rectangle(tl, br[0] - tl[0], br[1]-tl[1], fill=False, color="lime"))
viz2d.save_plot("C.png")

出力画像は、以下のようになります。

マッチングスコアを抽出

続いて、特徴点の一致度を抽出します。

scores = matches01['scores']
top_k_int = 50
top_k = torch.topk(scores, top_k_int).indices
m_kpts0, m_kpts1 = m_kpts0[top_k], m_kpts1[top_k]

axes = viz2d.plot_images([image0, image1])
viz2d.plot_matches(m_kpts0, m_kpts1, color="lime", lw=0.2)
viz2d.add_text(0, f'Stop after {matches01["stop"]} layers', fs=20)

viz2d.save_plot("C.png")

以下のような画像が出力されます。

意外と RealSense の一致度は高くないみたいです。
RGBのエッジが効いてるところがメインみたいですね。

特徴点から回転行列を作成し、画像を回転

こちらのサイトを参考にさせていただきました。

query_kp = np.reshape(m_kpts0.numpy(), (-1, 1, 2))
train_kp = np.reshape(m_kpts1.numpy(), (-1, 1, 2))

A, inliers = cv2.estimateAffinePartial2D(train_kp, query_kp)

M = A[:2, :2]
t = A[:, 2]

degree = np.rad2deg(-np.arctan2(A[0, 1], A[0, 0]))
print({"angle": degree, "M": M, "t": t})

image0_cv2 = cv2.imread("../A.png")
image1_cv2 = cv2.imread("../B.png")

h, w = image0_cv2.shape[:2]
center = (int(w/2),int(h/2))
trans = cv2.getRotationMatrix2D(center, degree , 1)
out = cv2.warpAffine(image0_cv2, trans, (w, h))

out = cv2.resize(out, center)
image0_cv2 = cv2.resize(image0_cv2, center)
image1_cv2 = cv2.resize(image1_cv2, center)

cv2.imshow("source_out", out)
cv2.imshow("source", image0_cv2)
cv2.imshow("target", image1_cv2)
cv2.waitKey(0)
cv2.destroyAllWindows()

出力画像は以下のようになります。

いい感じに回転できていますね!

おわりに

今回は LightGlue についてデモを試してみました。

これを使えば常に同じ姿勢で物体の検査に活用できそうです。

コメント

タイトルとURLをコピーしました