OpenCV/OpenCV 강좌

SIFT와 XFeat 사용해보기

webnautes 2024. 7. 28. 22:08
반응형

카메라가 빨리 움직일때 SIFT보다 성능이 우수하다고 하는 XFeat를 사용해봤습니다. 지금은 이미지 테스트만 진행한 상황이며 실시간 테스트는 조만간 해보겠습니다. 



2024. 7. 28  최초작성

2024. 7. 28  실시간 테스트를 추가했습니다. 




참고

https://github.com/verlab/accelerated_features

 

https://docs.opencv.org/4.x/dc/dc3/tutorial_py_matcher.html





다음 포스트에 나온대로 conda 환경을 구성후 하는게 좋습니다.

 

Visual Studio Code와 Miniconda를 사용한 Python 개발 환경 만들기( Windows, Ubuntu, WSL2)

https://webnautes.tistory.com/1842




이제 XFeat를 테스트하기 위한 환경을 구성합니다




Xfeat 깃허브 저장소를 다운로드 합니다. 

 

git clone https://github.com/verlab/accelerated_features.git

 

cd accelerated_features




파이썬 가상환경을 생성하고 활성화합니다.

 

conda create -n xfeat python=3.8

 

conda activate xfeat




GPU 사용 여부에 따라 다음 두 명령 중 하나를 사용하세요. 글 작성 시점에서 Pytorch 2.4가 설치되었습니다. 

 

# GPU를 사용

conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia

 

# CPU를 사용
pip install torch==1.10.1+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html




필요한 패키지를 설치합니다. 

 

pip install opencv-contrib-python tqdm matplotlib




현재 폴더에서 코드를 실행해야 XFeat 모듈을 사용할 수 있습니다.

 

(xfeat) webnautes@webnautes-laptop:~/accelerated_features$ pwd                  

/home/webnautes/accelerated_features



현재 위치에 vscode를 실행한후,  다음 코드를 실행합니다.

 

code .



import numpy as np
import os
import torch
import tqdm
import cv2
import matplotlib.pyplot as plt
import numpy as np

from modules.xfeat import XFeat

xfeat = XFeat()


# # XFeat에서 제공하는 이미지를 사용합니다.
# im1 = cv2.imread('./assets/ref.png')
# im2 = cv2.imread('./assets/tgt.png')

# 이미지를 선택하여 사용합니다.
im1 = cv2.imread('1.png') # 찾을 물체 사진
im2 = cv2.imread('2.png') # 물체가 포함된 사진



def warp_corners_and_draw_matches(ref_points, dst_points, img1, img2):
    # Calculate the Homography matrix
    H, mask = cv2.findHomography(ref_points, dst_points, cv2.USAC_MAGSAC, 3.5, maxIters=1_000, confidence=0.999)
    mask = mask.flatten()

    # Get corners of the first image (image1)
    h, w = img1.shape[:2]
    corners_img1 = np.array([[0, 0], [w-1, 0], [w-1, h-1], [0, h-1]], dtype=np.float32).reshape(-1, 1, 2)

    # Warp corners to the second image (image2) space
    warped_corners = cv2.perspectiveTransform(corners_img1, H)

    # Draw the warped corners in image2
    img2_with_corners = img2.copy()
    for i in range(len(warped_corners)):
        start_point = tuple(warped_corners[i-1][0].astype(int))
        end_point = tuple(warped_corners[i][0].astype(int))
        cv2.line(img2_with_corners, start_point, end_point, (0, 255, 0), 4# Using solid green for corners

    # Prepare keypoints and matches for drawMatches function
    keypoints1 = [cv2.KeyPoint(p[0], p[1], 5) for p in ref_points]
    keypoints2 = [cv2.KeyPoint(p[0], p[1], 5) for p in dst_points]
    matches = [cv2.DMatch(i,i,0) for i in range(len(mask)) if mask[i]]

    # Draw inlier matches
    img_matches = cv2.drawMatches(img1, keypoints1, img2_with_corners, keypoints2, matches, None,
                                  matchColor=(0, 255, 0), flags=2)

    return img_matches



# Use out-of-the-box function for extraction + MNN matching
mkpts_0, mkpts_1 = xfeat.match_xfeat(im1, im2, top_k = 4096)

canvas = warp_corners_and_draw_matches(mkpts_0, mkpts_1, im1, im2)
plt.figure(figsize=(12,12))
plt.imshow(canvas[..., ::-1]), plt.show()



# Use out-of-the-box function for extraction + coarse-to-fine matching
mkpts_0, mkpts_1 = xfeat.match_xfeat_star(im1, im2, top_k = 8000)

canvas = warp_corners_and_draw_matches(mkpts_0, mkpts_1, im1, im2)
plt.figure(figsize=(12,12))
plt.imshow(canvas[..., ::-1]), plt.show()




실행 결과입니다. 두번 보입니다. 

 

 




지금은 OpenCV에 포함된 SIFT도 사용해봤습니다.

 

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

img1 = cv.imread('1.png',cv.IMREAD_GRAYSCALE) # 찾을 물체 사진
img2 = cv.imread('2.png',cv.IMREAD_GRAYSCALE) # 물체가 포함된 사진

# Initiate SIFT detector
sift = cv.SIFT_create()

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

# BFMatcher with default params
bf = cv.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])

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

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




실행 결과입니다. OpenCV에서 제공하는 코드인데 물체 위치까지 잡아주지는 않네요. 




SIFT와 XFeat 비교결과입니다. 아래 영상은 XFeat 실시간 매칭 결과입니다.

 

https://youtu.be/p-4KxXCxstY

 



SIFT와 XFeat 비교결과입니다. 아래 영상은 SIFT 실시간 매칭 결과입니다.

 

https://youtu.be/optr8jjeahM

 




테스트에 사용한 코드입니다.

 

XFeat

 

import numpy as np
import os
import torch
import tqdm
import cv2
import matplotlib.pyplot as plt
import numpy as np

from modules.xfeat import XFeat

xfeat = XFeat()


# # XFeat에서 제공하는 이미지를 사용합니다.
# im1 = cv2.imread('./assets/ref.png')
# im2 = cv2.imread('./assets/tgt.png')

# 이미지를 선택하여 사용합니다.
im1 = cv2.imread('1.png') # 찾을 물체 사진
# im2 = cv2.imread('2.png') # 물체가 포함된 사진



def warp_corners_and_draw_matches(ref_points, dst_points, img1, img2):
    # Calculate the Homography matrix
    H, mask = cv2.findHomography(ref_points, dst_points, cv2.USAC_MAGSAC, 3.5, maxIters=1_000, confidence=0.999)
    mask = mask.flatten()

    # Get corners of the first image (image1)
    h, w = img1.shape[:2]
    corners_img1 = np.array([[0, 0], [w-1, 0], [w-1, h-1], [0, h-1]], dtype=np.float32).reshape(-1, 1, 2)

    # Warp corners to the second image (image2) space
    warped_corners = cv2.perspectiveTransform(corners_img1, H)

    # Draw the warped corners in image2
    img2_with_corners = img2.copy()
    for i in range(len(warped_corners)):
        start_point = tuple(warped_corners[i-1][0].astype(int))
        end_point = tuple(warped_corners[i][0].astype(int))
        cv2.line(img2_with_corners, start_point, end_point, (0, 255, 0), 4# Using solid green for corners

    # Prepare keypoints and matches for drawMatches function
    keypoints1 = [cv2.KeyPoint(p[0], p[1], 5) for p in ref_points]
    keypoints2 = [cv2.KeyPoint(p[0], p[1], 5) for p in dst_points]
    matches = [cv2.DMatch(i,i,0) for i in range(len(mask)) if mask[i]]

    # Draw inlier matches
    img_matches = cv2.drawMatches(img1, keypoints1, img2_with_corners, keypoints2, matches, None,
                                  matchColor=(0, 255, 0), flags=2)

    return img_matches


cap = cv2.VideoCapture('test.MOV')


while True:

    ret, frame = cap.read()

    if not ret:
        break


    im2 = frame

    #Use out-of-the-box function for extraction + MNN matching
    mkpts_0, mkpts_1 = xfeat.match_xfeat(im1, im2, top_k = 14096)

    canvas = warp_corners_and_draw_matches(mkpts_0, mkpts_1, im1, im2)


    h,w,_ = canvas.shape
    canvas = cv2.resize(canvas, (int(w/2), int(h/2)), interpolation=cv2.INTER_AREA)

    cv2.imshow('ret', canvas)
    key = cv2.waitKey(1)

    if key == 27:
        break




SIFT

 

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

img1 = cv.imread('1.png',cv.IMREAD_GRAYSCALE) # 찾을 물체 사진
# img2 = cv.imread('2.png',cv.IMREAD_GRAYSCALE) # 물체가 포함된 사진

# Initiate SIFT detector
sift = cv.SIFT_create()



cap = cv.VideoCapture('test.MOV')


while True:

    ret, frame = cap.read()

    if not ret:
        break


    img2 = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

    # find the keypoints and descriptors with SIFT
    kp1, des1 = sift.detectAndCompute(img1,None)
    kp2, des2 = sift.detectAndCompute(img2,None)
   
    # BFMatcher with default params
    bf = cv.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])
   
    # cv.drawMatchesKnn expects list of lists as matches.
    img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
   

    h,w,_ = img3.shape
   
    img3 = cv.resize(img3, (int(w/2), int(h/2)), interpolation=cv.INTER_AREA)
   
    cv.imshow('ret', img3)
    key = cv.waitKey(1)

    if key == 27:
        break



테스트에 사용한 영상과 이미지입니다.

1.png
0.56MB
2.png
0.92MB
test.MOV
7.39MB


 

 

반응형