python3,opencv3で特徴点マッチング(AKAZE, KNN)

プログラミング
OpenCVに実装されている特徴量記述子(AKAZE)を使って、二枚の画像間の特徴点マッチングアルゴリズムを実装してみたいと思います。

また、今回はベース画像の特徴量記述子によって得られた特徴量をテキストベースで格納し、そのテキストデータからマッチングを処理する部分も実装してみました。

 

画像マッチング手法にはたくさんの研究や提案がされていますが、その中でも照明やノイズにもロバストな手法である”増分符号相関法”についてもPythonで実装した記事もおすすめです。

特徴点(特徴量)マッチングとは?

二枚の画像の中から特徴点および特徴量を検出し、その情報を元にマッチングする技術です。
この技術の応用例として、以下があげられます。
・パノラマ画像の生成

・物体検知

スポンサーリンク

画像ファイル

手元にあった O’Reillyの「コンピュータビジョン」の表紙を使ってテストしてみます。
 画像1
 画像2

動作環境

・Python3.6
・OpenCV 3.4.3.18

ソースコード(画像によるマッチング)

二枚の画像から特徴点マッチングを行ってみます。

# -*- coding: utf-8 -*-
import cv2
import csv
import numpy as np


def image_matching(img1, img2):
    # 特徴量検出器の生成
    feature_detector = cv2.AKAZE_create()

    # 特徴量の検出と特徴量ベクトルの計算
    kp1, des1 = feature_detector.detectAndCompute(base_img, None)
    kp2, des2 = feature_detector.detectAndCompute(img, None)

    # Brute-Force Matcher生成
    bf = cv2.BFMatcher()

    # マッチング
    matches = bf.knnMatch(des1, des2, k=2)

    # 良いデータのみ選別
    ratio = 0.5
    good_feature = []
    for m, n in matches:
        if m.distance < ratio * n.distance:
            good_feature.append([m])

    # 選別した特徴点同士を描画
    res_img = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good_feature, None, flags=2)

    # 画像表示
    cv2.imshow('result', res_img)

    # csvファイルを閉じる
    csv_f.close()


if __name__ == '__main__':
    # 画像の読み込み
    base_img = cv2.imread("img1.jpg")
    img = cv2.imread("img2.jpg")

    # 特徴点マッチング
    image_matching(base_img, img)

 

マッチング結果(画像によるマッチング)

対応する特徴点同士を描画した結果がこちらです。
誤マッチングはなさそうです。
ここまではよくやられる処理ですね。

 

ソースコード(テキストベースによるマッチング)

次に、画像1の特徴量をcsvファイルに保存し、マッチングの際にはcsvファイルから特徴量を呼び出してマッチングしてみます。
# -*- coding: utf-8 -*-
import cv2
import csv
import numpy as np

def get_feature(img1):
    # 特徴量検出器の生成
    feature_detector = cv2.AKAZE_create()

    # 特徴量の検出と特徴量ベクトルの計算
    kp1, des1 = feature_detector.detectAndCompute(base_img, None)

    # ===== 特徴点と特徴量を同じ配列に生成しなおす
    numFeatures = len(kp1)
    kp_des_arry = []
    for i in range(numFeatures):
        # 特徴点の座標を格納
        kp_des = []
        kp_des.append(kp1[i].pt[0])  # x座標
        kp_des.append(kp1[i].pt[1])  # y座標
        # 特徴量ベクトルを格納
        numDescriptors = len(des1[i])
        for j in range(numDescriptors):
            kp_des.append(des1[i][j])
        # 特徴点の座用、特徴量ベクトルを一つの配列に格納
        kp_des_arry.append(kp_des)

    # ====== 特徴量ベクトルをcsvファイルに出力 =====
    csv_f = open('./feature.csv', 'w')
    header = ['x', 'y', 'descriptor']
    writer = csv.writer(csv_f, lineterminator='\n')
    writer.writerow(header)
    writer.writerows(kp_des_arry)

    # csvファイルを閉じる
    csv_f.close()

def vetor_matching(img):
    # 特徴量検出器の生成
    feature_detector = cv2.AKAZE_create()

    # 特徴量ベクトルが格納されたcsvファイルから特徴量を格納
    des1 = np.loadtxt(fname='feature.csv', dtype="uint8", delimiter=",", skiprows=1, usecols = (range(2, 63)))

    # 特徴量の検出と特徴量ベクトルの計算
    kp2, des2 = feature_detector.detectAndCompute(img, None)

    # Brute-Force Matcher生成
    bf = cv2.BFMatcher()

    # マッチング
    matches = bf.knnMatch(des1, des2, k=2)

    #良いデータのみ選別
    ratio = 0.5
    good_feature = []
    for m, n in matches:
        if m.distance < ratio * n.distance:
            good_feature.append([m])

    print(good_feature)


if __name__ == '__main__':
    # 画像の読み込み
    base_img = cv2.imread("img1.jpg")
    img = cv2.imread("img2.jpg")

    # base_imgの特徴量をcsvファイルに出力
    get_feature(base_img)

    # ベース画像の特徴量を配列として格納し、特徴量ベクトルの配列でマッチング
    vetor_matching(img)

 

マッチング結果(テキストベースによるマッチング)

対応する特徴点同士を描画した結果がこちらです。
当たり前ですが画像によるマッチングと同じ結果になりましたね。

 

”テキストベースによるマッチング”は結局何がしたかったのか?

画像による特徴点マッチングは他にもたくさんの方のブログやチュートリアルで紹介されているのですが、テキストベースによるマッチングは結局何がしたかったの?と疑問に思った方もいると思います。

この手法が役に立つ場面として想定しているのは、組み込み系のシステムでかつ計算資源が豊富でない環境に使えるかなと思っています。

画像情報よりもテキストベースのほうが圧倒的にデータサイズが小さいため、あらかじめベース画像の特徴量をcsvファイル等でデータベース化しておき、カメラで得られた画像とテキストベースによるマッチングが行えます。

これにより、組み込み系等のストレージが大きくない環境においてもマッチングが行えるのではないかと思っています。

 

まとめ

OpenCVを使って特徴点マッチングを行ってみました。

また、2枚のうち1枚の画像の特徴量をcsvファイルにテキストベースとして保存し、テキストベースでの特徴点マッチングを行いました。

テキストベースでの特徴点マッチングは、組み込み系のシステムでかつ計算資源が豊富でない環境で威力を発揮する手法になるかもしれませんね。

 

人気記事

 

 

スポンサーリンク

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