[OpenCV] SURF 알고리즘 코드 작성!

Checking·2023년 2월 11일
0

OpenCV

목록 보기
4/4
post-thumbnail

✅ 환경 세팅은 이전 글들을 확인해주세요!

SURF 알고리즘 코드

SURF 알고리즘은 크게 2가지의 과정으로 진행된다.

  1. 각 이미지에서 키포인트를 검출한다!
  2. 키포인트로 두 이미지를 매칭한다!

테스트 이미지는 같은 물체가 있는 각도가 다른 두 사진으로 진행하였다.

전체 코드

import cv2

# 이미지 불러오기 (확장자까지 적기!)
photo01 = cv2.imread("image01.jpg")
photo02 = cv2.imread("image02.jpg")

# 이미지가 너무 커서 사이즈 조절
photo01 = cv2.resize(photo01, (346, 462), cv2.INTER_LINEAR)
photo02 = cv2.resize(photo02, (346, 462), cv2.INTER_LINEAR)

# SURF 알고리즘 객체 생성 (500은 Threshold_임계값)
feature = cv2.xfeatures2d.SURF_create(500)

# 각 이미지에서 키포인트 추출
keyPoint01, descriptors01 = feature.detectAndCompute(photo01, None)
keyPoint02, descriptors02 = feature.detectAndCompute(photo02, None)

# Brute-force 방식으로 매칭
matcher = cv2.BFMatcher(cv2.NORM_L1, True)
matches = matcher.match(descriptors01, descriptors02)

# 키포인트 및 매칭 결과를 이미지에 그리기
keyPointImage01 = cv2.drawKeypoints(photo01, keyPoint01, None, None, cv2.DRAW_MATCHES_FLAGS_DEFAULT)
keyPointImage02 = cv2.drawKeypoints(photo02, keyPoint02, None, None, cv2.DRAW_MATCHES_FLAGS_DEFAULT)
matchImage = cv2.drawMatches(photo01, keyPoint01, photo02, keyPoint02, matches, None)

# 이미지 출력
cv2.imshow("keyPoint Image 01", keyPointImage01)
cv2.imshow("keyPoint Image 02", keyPointImage02)
cv2.imshow("match Image", matchImage)
cv2.waitKey(0)

일단 전체 코드를 확인하고 하나하나 분석을 해보자.

이미지 전처리 과정

# 이미지 불러오기 (확장자까지 적기!)
photo01 = cv2.imread("image01.jpg")
photo02 = cv2.imread("image02.jpg")

# 이미지가 너무 커서 사이즈 조절
photo01 = cv2.resize(photo01, (512, 512), cv2.INTER_LINEAR)
photo02 = cv2.resize(photo02, (512, 512), cv2.INTER_LINEAR)

이미지는 불러오자마자 쓸 수 있는 상태가 되면 더 없이 좋겠지만 아닐 가능성이 높다.
이미지가 너무 커서 불러와 한 번 조절하는 과정을 진행하였다.

※ 참조 : 두 이미지의 크기가 달라도 상관없다.

키포인트 추출

# SURF 알고리즘 객체 생성 (500은 Threshold_임계값)
feature = cv2.xfeatures2d.SURF_create(500)

# 각 이미지에서 키포인트 추출
keyPoint01, descriptors01 = feature.detectAndCompute(photo01, None)
keyPoint02, descriptors02 = feature.detectAndCompute(photo02, None)

왼쪽부터 임계값이 0일때, 500일때, 1000일때 이다.

SURF 알고리즘 객체를 생성할 때 값 안에 넣는 임계값에 따라 검출되는 키포인트 개수가 달라진다.
임계값이 높을수록! 키포인트 값이 높아야 하므로! 더 적은 키포인트가 검출된다.

  • 임계값은 500정도가 적당한 개수의 키포인트가 검출된다.

이후 각 이미지에서 키포인트를 검출해주고 저장한다.

키포인트 매칭

# Brute-force 방식으로 매칭
matcher = cv2.BFMatcher(cv2.NORM_L1, True)
matches = matcher.match(descriptors01, descriptors02)

키포인트를 매칭할때는 Brute-force 방식으로 매칭한다.
각각 하나씩 대칭해보면서 가장 적절한 키포인트와 매칭하는 방식이다.

matcher.match()함수는 첫번째 키포인트들을 두번째 키포인트에 매칭하는 방식이다.
그래서 두 순서가 바뀐다면 값이 다르게 나올 수 있다!

키포인트 및 매칭 결과 그리기

# 키포인트 및 매칭 결과를 이미지에 그리기
keyPointImage01 = cv2.drawKeypoints(photo01, keyPoint01, None, None, cv2.DRAW_MATCHES_FLAGS_DEFAULT)
keyPointImage02 = cv2.drawKeypoints(photo02, keyPoint02, None, None, cv2.DRAW_MATCHES_FLAGS_DEFAULT)
matchImage = cv2.drawMatches(photo01, keyPoint01, photo02, keyPoint02, matches, None)

# 이미지 출력
cv2.imshow("keyPoint Image 01", keyPointImage01)
cv2.imshow("keyPoint Image 02", keyPointImage02)
cv2.imshow("match Image", matchImage)
cv2.waitKey(0)

이미지에 keyPoint를 그릴 때 cv2.drawKeypoints()를 사용
매칭된 결과를 그릴 때 cv2.drawMatches()를 사용

keyPoint 그리기

cv2.drawKeypoints(image: Mat, keypoints: Any, outImage: Any, color: ... = ..., flags: int = ...)
drawKeypoints 함수의 형태이다.

  • image : keyPoint를 그릴 원본 이미지
  • keypoints : 검출한 키포인트 값
  • outImage : 저장할 변수 (안할거면 None)
  • color : 키포인트 색깔 (랜덤이면 None)
  • flags : 값을 표현하는 방식에 대한 태그

color

좌측의 경우 랜덤 None, 우측의 경우 Cyan (255, 255, 0)

color의 경우 (blue, green, red)의 형태로 0~255를 넣으면 대응하는 색으로 키포인트가 표시된다. None으로 할 경우 각 키포인트마다 랜덤한 색이 부여된다.

flags


좌측의 경우 키포인트 위치만 출력 cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
우측의 경우 키포인트 크기와 방향까지 출력 cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS

flags에 cv2.DRAW_MATCHES_FLAGS_DEFAULTcv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS를 넣으면 위치 값만 보여주는 작은 점들로 그려진다.
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS를 넣으면 위치 뿐만 아니라 크기 및 방향까지 보여준다.

Matching 결과 그리기

cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg, matchColor=..., singlePointColor=..., matchesMask=..., flags: int = ...)
drawMatches 함수의 형태이다.

  • img1 : 매칭에 사용한 이미지 원본 1
  • keypoints1 : img1의 키포인트
  • img2 : 매칭에 사용한 이미지 원본 2
  • keypoints2 : img2의 키포인트
  • matches1to2 : 매칭 결과값
  • outImg : 저장할 변수 (안할거면 None)
  • matchColor : 매칭된 선 색깔 (랜덤이면 None)
  • singlePointColor : 매칭되지 않은 키포인트 색깔 (랜덤이면 None)
  • matchesMask : 매칭을 시도할 부분의 마스크 (값 없으면 모든 키포인트를 매칭)
  • flags : 값을 표현하는 방식에 대한 태그

matchColor, singlePointColor


matchColor를 Cyan (255, 255, 0), singlePointColor를 Red (0, 0, 255)로 설정

매칭이 된 키포인트와 선은 matchColor가 되며, 매칭이 되지 않은 키포인트는 singlePointColor가 된다.
각각 None일 경우 랜덤한 색깔로 설정된다.

flags

flags는 총 3가지가 있다.
DEFAULT, NOT_DRAW_SINGLE_POINTS, DRAW_RICH_KEYPOINTS

  • DEFAULT
    키포인트는 위치 값만, 모든 키포인트를 표현하는 방식

  • NOT_DRAW_SINGLE_POINTS
    매칭된 키포인트들만 표현하는 방식

  • DRAW_RICH_KEYPOINTS
    키포인트가 위치 뿐만 아니라 크기와 방향까지 표현하는 방식

profile
(ง ᐖ)ว

0개의 댓글