↓もし、良かったらSNSでの紹介よろしくお願いします。

OpenCV(Python)で物体認識、特徴抽出(SIFT、SURF、A-KAZEの使い方)

↓もし、良かったらSNSでの紹介よろしくお願いします。

OpenCVで物体認識

OpenCVで物体認識をする方法は大きく分けて3パターン

  1. テンプレートマッチング法
    このページでは、OpenCV(Python)を用いて、テンプレートマッチング法による物体検出を紹介します。また、テンプレートマッチング法のサンプルコードと解説をしています。matchTemplate関数、minMaxLoc関数についても解説。
  2. 特徴点の抽出し、比較することで検出
    今回は2.の方法で物体認識を行います。
  3. カスケード型分類器を用いて検出
    OpenCVで物体認識 OpenCVで静止画から物体認識をする場合、おもに3つの方法があります。 お手軽順で並べるとつぎのようになります。...

    OpenCVで顔認識とそれ以外の物体認識(カスケード分類機まとめ)

OpenCVで静止画から物体認識をする場合、3つの方法があります。お手軽順で並べてます。つまり、1.が最もお手軽な方法で、3.は判別機の学習のためにデータを集めて成形するのが面倒です。ただし、3.の方法を使った顔認識は優秀な判別機が公式から配布されているのでお手軽にできます。

今回、紹介する2.の方法は1.のテンプレートマッチング法と比べて、探したい物体が回転していたり大きさが違っていても画像の中から物体を探しだす事ができます。さらに学習データがいらないので3.の方法に比べてお手軽です。

OpenCVで特徴点抽出

特徴のある点を結ぶ

shift_result3

今回は画像から1ドル札を探すコードを紹介します。
上記の画像のように特徴のある点を結んだ結果画像が得られます。
特徴点を抽出するアルゴリズムはSIFT、SURF、A-KAZEなどがあります。
OpenCVではこれらのアルゴリズムがサポートされています。

SIFTは特徴抽出の代表的なアルゴリズムです。
SURFはSIFTの処理の一部を単純化して軽くしたアルゴリズムです。

SIFT、SURFの商用利用では特許上リスクがあります。

A-KAZEはライセンスフリーのアルゴリズムというメリットがあります。

環境

  • Python3.6.2
  • OpenCV3.3 + contribパッケージ

OpenCVはライセンスフリーではないアルゴリズムはcontribパッケージに隔離されています。なので、SIFTやSURFを使うためにはcontribパッケージを導入する必要があります。ソースをビルドするのが面倒な人はpipでいれることをオススメします。下記の記事で解説しています。

OpenCV3.3(core+contrib)をPython3にpipで入れてみた

サンプルコード(SIFT)

import numpy as np
import cv2
img1 = cv2.imread('dollar.png',0)
img2 = cv2.imread('dollar_in_scene.png',0)
#特徴抽出機の生成
detector = cv2.xfeatures2d.SIFT_create()
#kpは特徴的な点の位置 destは特徴を現すベクトル
kp1, des1 = detector.detectAndCompute(img1, None)
kp2, des2 = detector.detectAndCompute(img2, None)
#特徴点の比較機
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
#割合試験を適用
good = []
match_param = 0.6
for m,n in matches:
    if m.distance < match_param*n.distance:
        good.append([m])
#cv2.drawMatchesKnnは適合している点を結ぶ画像を生成する
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good, None,flags=2)
cv2.imwrite("shift_result.png", img3)

入力画像

今回は次の3つの画像の中から1ドル札を探します。これらの画像がサンプルコード内の’dollar_in_scene.png’です。

dollar-2565107_640
bills-2557264_640
dollar-1362243_640

1ドル画像(‘dollar.png’)は下記の画像を使いました。

dollar-1341261_640

実行結果

正面から検出した結果の図

正面から検出した結果です。大きさが異なっていても、ちゃんと1ドル札の同じ柄の箇所を線で結べています。

shift_result2_06

斜めっている1ドル札の検出です。大きさが異なっている上に回転が加わっても、ちゃんと1ドル札の同じ柄の箇所を線で結べています。

shift_result3

縮小と回転に加えて斜った始点からでも特徴を捉えることができるのかを確かめた結果です。捕らえられた特徴は少ないもののちゃんと1ドル札の特徴を捉えて認識しています。

サンプルコードの解説

#kpは特徴的な点の位置 destは特徴を現すベクトル
kp1, des1 = detector.detectAndCompute(img1, None)
kp2, des2 = detector.detectAndCompute(img2, None)

kp(キーポイント)は特徴的な点の位置dest(特徴量記述子)はキーポイントの特徴を現すベクトルです。特徴量記述子はキーポイントの周辺の情報を表現した128次元のベクトルです。detector.detectAndComputeの第1引数は特徴点が抽出される画像、第2引数は特徴点を抽出する領域を選択するマスクです。Noneの場合は画像全体から特徴点を抽出します。

#特徴点の比較機
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)

特徴点のマッチングを行ってます。BFMatcher()は特徴点をすべて比較する方法です。ちなみにBFはBrute-Force(総当り法、力ずく)の略です。

bf.knnMatchにそれぞれの画像の特徴量記述子(128次元ベクトル)を渡すと距離を計算します。k=2とするとdes1のそれぞれの点に対して、最も近いdes2の点2つを選び、マッチングインスタンスを出力します。

#割合試験を適用
good = []
match_param = 0.6
for m,n in matches:
    if m.distance < match_param*n.distance:
        good.append([m])

最も近い点が2番目に近い点の距離の0.6倍の場合良い結果とみなす。

SIFT以外のアルゴリズム

SIFT以外のアルゴリズムを使う場合、検出機を生成する部分のコードを下記のように書き換えてください。

SURFを使う場合

detector = cv2.xfeatures2d.SURF_create()

A-KAZEを使う場合

detector = cv2.AKAZE_create() 

実行結果

surf_result

SURFの実行結果です。SURFは反射している箇所も認識しています。これは、アルゴリズムの精度が良いというよりは割合検定をしている影響によるものだと思います。

akazeの結果

サンプルコードのパラメータの設定(match_param=0.6)だと1箇所しか認識できてないです。パラメータを調整した(match_param=0.7)結果が次の結果画像です。

akaze07_result

1ドル札の実験の場合、SIFTやSURFよりも若干精度が落ちてます。

↓もし、良かったらSNSでの紹介よろしくお願いします。

フォローする