OpenCVのFeature2Dクラスを使った特徴点抽出とマッチング

概要

この記事ではOpenCVを使用したパターンマッチングについて紹介しています。OpenCVのFeature2Dクラスは、画像から特徴点を抽出し、それらを他の画像とマッチングするためのツールセットです。これは、物体認識、画像ステッチング、3D再構成など、様々なアプリケーションで使用されています。特に、異なる視点や照明条件から撮影された画像間で、共通の特徴を見つけることが必要な場合に有用です。 Feature2Dクラスは、SIFTやSURFなどのさまざまな特徴抽出アルゴリズムをサポートしており、それぞれが画像の特定の特性に対して最適化されています。ここではSIFTを例にしてサンプルプログラムを解説しています。

出力結果

OpenCVのFeature2Dクラスを使った特徴点抽出とマッチング

プログラム全体

# 解説1 import cv2 import matplotlib.pyplot as plt # 解説2 # 画像を読み込む img1 = cv2.imread('box.png',0) # クエリ画像 img2 = cv2.imread('box_in_scene.png',0) # トレーニング画像 # 解説3 # SIFT検出器を初期化する sift = cv2.SIFT_create() # SIFTを用いてキーポイントと記述子を見つける kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None) # デフォルトパラメータでBFMatcherを作成 bf = cv2.BFMatcher() matches = bf.knnMatch(des1,des2,k=2) # レシオテストを適用 good = [] for m,n in matches: if m.distance < 0.75*n.distance: good.append([m]) # 解説4 # cv2.drawMatchesKnnはマッチング結果としてリストのリストを期待する img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) plt.imshow(img3),plt.show() # 画像を表示

解説

解説1:ライブラリのインポート

import cv2 import matplotlib.pyplot as plt

この部分では、プログラムで必要となる下記のライブラリをインポートしています。cv2はOpenCV(Open Source Computer Vision Library)のことで、画像処理やコンピュータビジョンに関する機能を提供しています。 matplotlib.pyplotは、グラフ描画や画像表示のためのライブラリです。

解説2:画像の読み込み

# 'box.png'と'box_in_scene.png'をグレースケール画像として読み込む img1 = cv2.imread('box.png',0) # img1はクエリ画像(単独の箱) img2 = cv2.imread('box_in_scene.png',0) # img2はトレーニング画像(シーン内の箱)

ここでは、cv2.imread関数を使って2つの画像ファイルを読み込んでいます。引数の0は、画像をグレースケール(白黒)で読み込むことを指定しています。これは、特徴抽出アルゴリズムが色情報を必要としないためです。以下の記事でモノクロ化や二値化について軽く解説しているのでご覧ください。 →opencv_threshold.html(2値化記事 )

今回はimg2の中にimg1の画像と特徴が一致する物体を検知するプログラムのため、画像を2枚使用しています。

解説3:特徴点の抽出とマッチング

# SIFT特徴抽出器を初期化する sift = cv2.SIFT_create() # SIFTを用いて各画像からキーポイントと記述子を抽出する kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None) # デフォルトパラメータでBFMatcher(Brute-Force Matcher)を作成 bf = cv2.BFMatcher() # 2つの画像の記述子間でk-nearest neighbor matchingを行う matches = bf.knnMatch(des1,des2,k=2) # レシオテストを適用して良いマッチングを選ぶ good = [] for m,n in matches: if m.distance < 0.75*n.distance: good.append([m])

このプログラムは、2つの画像がどれだけ似ているかを調べるためのものです。まず、SIFT(Scale-Invariant Feature Transform)という方法を使って、各画像から特別な点(キーポイント)とその特性(記述子)を抽出しています。言い換えると、画像の中で何か特別なパターンや形がある場所を見つけています。 次に、Brute-Force Matcherという方法を使って、一つ目の画像の各キーポイントが二つ目の画像のどのキーポイントと最もよく似ているかを見つけます。つまり、一つ目の画像の特別な点が二つ目の画像のどこに対応するかを検出しています。 ただし、全てのマッチングが正しいわけではないので、良いマッチングだけを選び出すためにレシオテスト(Ratio test)という方法を使います。これは、一つ目の画像のキーポイントと最もよく似ている二つ目の画像のキーポイントと、次によく似ているキーポイントとの距離を比べて、その距離の差が0.75倍以下離れていればそのマッチングは信頼できる、というものです。0.75よりも小さい値にすることでレシオテストがより厳格になります。

このようにして2つの画像がどれだけ似ているか調べることができます。

エラー:SIFT_create()を呼び出せない

例外が発生しました: AttributeError module 'cv2.cv2' has no attribute 'SIFT_create' File "opencv_feature_matching.py", line 12, in <module> sift = cv2.SIFT_create() AttributeError: module 'cv2.cv2' has no attribute 'SIFT_create'

OpenCVのバージョンが4.5.0以下を使用している場合上記のようなエラーが出ます。OpenCVをアップデートすることでエラーが解消されます。

/*必要に応じてpipのアップデートを行う*/ pip install --user --upgrade pip /*インストールコマンド*/ python -m pip install --user opencv-python /*OpenCVのバージョンが4.5.0以上になっているか確認*/ python -c "import cv2; print( cv2.__version__ )"

解説4:マッチング結果の描画と表示

# 良いマッチングの結果を用いて画像にマッチングを描画 img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) # マッチング結果を描画した画像を表示 plt.imshow(img3),plt.show()

最後に、cv2.drawMatchesKnn関数を用いて、マッチング結果を描画しています。この関数は、以下の引数を使用しています。

img1 最初の画像(クエリ画像)
kp1 最初の画像のキーポイント
img2 2番目の画像(トレーニング画像)
kp2 2番目の画像のキーポイント
good マッチングの結果(ここではレシオテストを通過したマッチングのリスト)
None マスク(ここでは使用されていません)
flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS 描画オプション(ここでは単一の点は描画しないというオプションが指定されています) この関数は、2つの画像を横に並べ、マッチングした特徴点間に線を引いて表示する新しい画像(img3)を生成します。

そして、matplotlib.pyplot.imshowmatplotlib.pyplot.showを用いて、描画結果を表示しています。これにより、どの特徴点がマッチングしたのかを視覚的に確認することができます。

おまけ

上記で述べたように、特徴点を抽出する際には画像をグレースケール(モノクロ)に変換します。産業用カメラのラインナップにはモノクロカメラも含まれています。最初からモノクロカメラを使用することで、エッジが鮮明な画像を取得でき、特徴点の抽出精度を向上させることが可能です。
https://www.argocorp.com/UVC_camera/UVC_ColorMono.html