Robotics/Open CV python

Feature Matching

howtowhy 2019. 7. 24. 15:51

Feature Matching

Goal

  • 어떻게 features를 한 이미지에서 다른 이미지로 matching 시키는 지 알아볼 것입니다.
  • 여기서 Brute-Force matcher 와 FLANN Matcher 를 open cv 에서 사용할 것입니다.

Basics of Brute-Force Matcher

Brute-Force matcher는 간단합니다. 첫 번째 세트에서 한 feature의 descriptor를 가져 와서 일부 거리 계산을 사용하여 두 번째 세트의 다른 모든 피쳐와 일치시킵니다. 그리고 가장 가까운 것이 반환됩니다.

BF matcher의 경우 먼저 cv2.BFMatcher ()를 사용하여 BFMatcher 객체를 만들어야합니다. 두 개의 선택적 매개 변수가 필요합니다. 첫 번째는 normType입니다. 사용할 거리 측정을 지정합니다. 기본적으로 cv2.NORM_L2입니다. SIFT, SURF 등 (cv2.NORM_L1도 거기에 있다)에 좋다. ORB, BRIEF, BRISK 등과 같은 binary string 기반 descriptors의 경우, Hamming distance를 측정으로 사용하는 cv2.NORM_HAMMING이 사용되어야한다. ORB가 VTA_K == 3 또는 4를 사용하는 경우, cv2.NORM_HAMMING2를 사용해야합니다.

두 번째 매개 변수는 boolean variable 인 crossCheck이며 기본적으로 false입니다. 참인 경우, Matcher는 세트 A의 i 번째 설명자가 세트 B의 j 번째 설명자를 최상의 match로 가지도록 하는 값 (i, j)을 갖는 match 만 리턴합니다. (반대도 마찬가지입니다). 즉, 두 세트의 두 features 이 서로 match되야합니다. 일관된 결과를 제공하며 D.Lowe가 SIFT 논문에서 제안한 ratio test의 좋은 대안입니다.

일단 그것이 생성되면, 중요한 두 가지 메소드는 BFMatcher.match ()와 BFMatcher.knnMatch ()입니다. 첫 번째는 가장 match하는 것을 반환합니다. 두 번째 방법은 k가 사용자에 의해 지정된 k 개의 최상의 일치를 반환합니다. 추가 작업이 필요할 때 유용 할 수 있습니다.

우리가 cv2.drawKeypoints ()를 사용하여 키포인트를 그리는 것처럼, cv2.drawMatches ()는 우리가 일치하는 것을 그리는 데 도움이됩니다. 두 개의 이미지를 가로로 쌓고 첫 번째 이미지에서 두 번째 이미지까지 선을 그려 가장 잘 맞는 이미지를 보여줍니다. k 개의 가장 일치하는 것을 끌어 오는 cv2.drawMatchesKnn도 있습니다. k = 2 인 경우 각 키포인트에 대해 두 개의 일치 행을 그립니다. 따라서 선택적으로 그리려면 mask를 전달해야합니다.

SURF와 ORB 각각에 대해 하나의 예제를 보도록하겠습니다. 둘 다 다른 거리 측정을 사용합니다.

Brute-Force Matching with ORB Descriptors

여기서는 두 이미지간에 피쳐를 일치시키는 방법에 대한 간단한 예를 살펴 보겠습니다. 이 경우 queryImage 및 trainImage가 있습니다. 특징 매칭을 사용하여 trainImage에서 queryImage를 찾으려고합니다. (이미지는 /samples/c/box.png 및 /samples/c/box_in_scene.png 입니다.))

SIFT descriptors를 사용하여 features을 일치시킵니다. 이제 이미지로드, descriptors 찾기 등으로 시작합시다.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
orb = cv2.ORB()

# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

다음으로 cv2.NORM_HAMMING (ORB를 사용하고 있으므로)을 사용한 거리 측정 으로 BFMatcher 객체를 만들고 crossCheck를 사용하면 더 나은 결과를 얻을 수 있습니다. 그런 다음 Matcher.match () 메서드를 사용하여 두 이미지에서 최상의 일치를 얻습니다. 우리는 거리들을 오름차순으로 정렬하여 최상의 결과 (낮은 거리)가 제일 앞쪽으로 오게 됩니다.. 그런 다음 처음 10 개의 일치 항목 만 표시합니다 (가시성을 위해, 해당 항목을 원하는만큼 늘릴 수 있습니다.).

 # create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1,des2)

# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)

# Draw first 10 matches.
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)

plt.imshow(img3),plt.show()

다음은 얻은 결과입니다.

What is this Matcher Object?

matches 의 결과=bf.match(des1,des2)푸른선이 DMatch objects의 list 입니다. 이 DMatch object 는 다음의 attributes 를 가지고 있습니다. :

  • DMatch.distance- descriptors 간의 거리. 낮을수록 좋습니다.
  • DMatch.trainIdx- train descriptors 중 descriptor Index
  • DMatch.queryIdx- query descriptors 중 descriptorIndex
  • DMatch.imgIdx- train image 의 index

Brute-Force Matching with SIFT Descriptors and Ratio Test

이번에는 BFMatcher.knnMatch ()를 사용하여 k 개의 가장 match하는 항목을 가져옵니다. 이 예제에서 우리는 그의 paper에서 D.Lowe가 설명한 비율 테스트를 적용 할 수 있도록 k = 2를 취할 것입니다.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)

# Apply ratio test
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])

# cv2.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)

plt.imshow(img3),plt.show()

결과는 아래와 같습니다.

FLANN based Matcher

FLANN은 Approximate Nearest Neighbors의 Fast Library를 나타냅니다. 대규모 데이터 세트 및 고차원features에서 nearest neighbor search 을 위해 최적화 된 알고리즘 모음이 포함되어 있습니다. 대규모 데이터 세트의 경우 BFMatcher보다 더 빠르게 작동합니다. FLANN 기반 matcher로 두 번째 예제를 보게 될 것입니다.

FLANN 기반 매처의 경우 사용할 알고리즘, 관련 매개 변수 등을 지정하는 두 개의 사전을 전달해야합니다. 먼저 IndexParams입니다. 다양한 알고리즘에 대해 전달할 정보는 FLANN 문서에 설명되어 있습니다. 요약하면 SIFT, SURF 등과 같은 알고리즘의 경우 다음을 전달할 수 있습니다.

index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

ORB를 사용하는 동안 다음을 전달할 수 있습니다. 주석 값은 문서별로 권장되지만 경우에 따라 필요한 결과를 제공하지 않습니다. 다른 값은 잘 작동했습니다.

index_params= dict(algorithm = FLANN_INDEX_LSH,
                   table_number = 6, # 12
                   key_size = 12,     # 20
                   multi_probe_level = 1) #2     

두 번째 사전은 SearchParams입니다. 인덱스의 트리를 재귀 적으로 탐색해야하는 횟수를 지정합니다. 값이 높을수록 정확도가 높아지지만 시간이 더 많이 소요됩니다. 값을 변경하려면 search_params = dict (checks = 100)를 전달하십시오.

이러한 정보를 통해 이제 우리는 잘 할 수 있습니다.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
sift = cv2.SIFT()

# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)

# FLANN parameters
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary

flann = cv2.FlannBasedMatcher(index_params,search_params)

matches = flann.knnMatch(des1,des2,k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in xrange(len(matches))]

# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
    if m.distance < 0.7*n.distance:
        matchesMask[i]=[1,0]

draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = 0)

img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)

plt.imshow(img3,),plt.show()

결과는 아래와 같았습니다.

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_matcher/py_matcher.html