본문 바로가기

OpenCV

cv2.BFMatcher( )에 대해 알아보자

320x100
320x100

 

 

 파노라마 사진을 만들기 위해선 image stitching이라고도 부르는 image registration (영상 정합)을 해야한다. 그리고 이를 위해서는 두 이미지에서 같은 지점을 가리키는 좌표들의 쌍들을 먼저 알아내야 한다. 그래야 변환 행렬을 계산해 registration을 할 수 있기 때문이다. image registration은 보통 아래와 같은 흐름으로 진행된다.

 

 

이번 글에서는 matching 과정에서 쓰이는 cv2.BFMatcher( ) 함수에 대해 정리하고자 한다.

 

 


 

 

 cv2.BFMatcher( ) 에서 BF는 Brute Force의 약자이다. Brute Force는 원래부터 있던 개념으로 무식하게 전부 다 확인해본다는 의미를 갖는다. 다르게 말하면 가능한 모든 경우에 대해 다 계산해본 후 최적의 결과를 반환하는 알고리즘이다.

 cv2.BFMatcher( ) 함수는 image A의 des1과 가장 유사도가 높은 image B의 descriptor를 찾기 위해 M개의 descriptor를 대상으로 거리를 모두 구한 다음에 가장 짧은 거리를 갖는 image B의 descriptor를 찾는다. 만약 image A의 des1과 image B의 des15가 가장 유사도가 높은 descriptor라고 가정하면, cv2.BFMatcher( )는 매칭된 des들의 index들과 유사도를 반환한다. (리터값 = 1, 15, descriptor 사이의 거리 반환 )

 

 예제를 통해 확인해보자.

 

왼쪽 사진

  

오른쪽 사진

 

 왼쪽 사진과 오른쪽 사진 사이의 유사도가 높은 특징점들을 매칭하는 예제를 살펴보겠다.

import numpy as np
import cv2


imageA = cv2.imread('./pano_1.jpeg') # 왼쪽 사진
imageB = cv2.imread('./pano_2.jpeg') # 오른쪽 사진

grayA = cv2.cvtColor(imageA,cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB,cv2.COLOR_BGR2GRAY)


sift = cv2.xfeatures2d.SIFT_create()
kpA, desA = sift.detectAndCompute(grayA, None)
kpB, desB = sift.detectAndCompute(grayB, None)


bf = cv2.BFMatcher()
matches = bf.match(desA,desB)


sorted_matches = sorted(matches, key = lambda x : x.distance)
res = cv2.drawMatches(imageA, kpA, imageB, kpB, sorted_matches[:30], None, flags = 2)

cv2.imshow('res', res)
  • [Line 12 ~ 14]
    keypoint 및 descriptor를 뽑아내기 위해 SIFT를 사용했다.
  • [Line 17, 18]
    cv2.BFMatcher( )를 통해 유사도가 가장 높은 keypoint 쌍들을 찾은 결과들이 matches에 저장된다.
    함수의 내부 흐름은 다음과 같다.
      (1) desA[0]와 매칭되는 desB의 des에 대한 정보를 matches[0]에 저장
      (2) desA[1]와 매칭되는 desB의 des에 대한 정보를 matches[1]에 저장
      (3) desA의 마지막 des까지 반복
  • matches[0]에는 queryIdx, trainIdx, distance 정보가 포함되는데 각각의 의미는 아래와 같다.

    (1) queryIdx
       : 기준이 되는 descriptor 및 keypoint의 index이다.
         matches[0]는 desA[0]를 기준으로 삼기 때문에
         matches[0].queryIdx = 0 이다.
    (2) trainIdx
       : desA[0]과 매칭된 image B, des의 index에 해당한다.
    (3) distance
       : desA[0]와 매칭된 desB의 des 사이의 거리( = 유사도 )값이다.
        → matches[0].distance와 np.linalg.norm( ) 결과가 같은 것을 확인할 수 있다.

 

 

※ distance를 유사도와 같은 의미로 사용하는 이유는 Norm2를 사용하기 때문이다. MSE에서도 거리를 에러로 사용한다는 걸 떠올리자.

 

 

결과 이미지는 다음과 같다.

 

 

 

[ 참고 사이트 ]

https://adrian0220.tistory.com/36

http://blog.naver.com/PostView.nhn?blogId=samsjang&logNo=220657424078&categoryNo=66&parentCategoryNo=0&viewDate=&currentPage=2&postListTopCurrentPage=1&from=postList&userTopListOpen=true&userTopListCount=10&userTopListManageOpen=false&userTopListCurrentPage=2

https://www.pyimagesearch.com/2016/01/11/opencv-panorama-stitching/

https://towardsdatascience.com/image-stitching-using-opencv-817779c86a83

https://swprog.tistory.com/entry/%ED%8C%8C%EB%85%B8%EB%9D%BC%EB%A7%88-panorama-by-OpenCV-32