ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Feature Matching
    Robotics/Open CV python 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

    댓글

Designed by Tistory.