컴퓨터 비전

OpenCV 특정점 검출과 매칭

Jagbbum 2023. 10. 23. 11:54

크기 불변 특징점

- 스케일 스페이스 또는 이미지 피라미드를 구성하여 영상의 크기가 바뀌더라도 특징점을 찾아 응용에서 사용

- 주요 알고리즘: SIFT, SURF, KAZE, AKZE, ORB 등

 

SIFT 알고리즘

Detector

1. 스케일 스페이스 : DOG 영상 생성

2. 키포인트 찾기 : DOG 영상에서 주변 8개 점과 상/하 스케일 DOG 영상에서 18개 점, 총 26개 점을 비교하여 지역 최대 최솟값 선택

 

Descriptor

1. 방향 불변 특성을 위한 주 방향 성분 추출

- 키포인트 근방의 부분 영상 추출

- 부분 영상의 모든 픽셀에서 그래디언트 성분 계산

- 히스토그램 최댓값 방향과 최댓값의 80% 이상 크기를 갖는 빈 방향을 키포인트 방향으로 설정

2. 각 키포인트에 대해 기준 방향 성분 설정

3. 키포인트 기술자(descriptor)

- 각 키포인트 위치에서 스케일과 기준 방향을 고려하여 사각형 영역 선택

- 사각형 영역을 4x4 구역으로 분할하고 각 구역에서 8방향의 방향 성분 히스토그램 구함

 

OpenCV 특징점 검출

특징점 알고리즘 선택

SIFT::create(); // SIFT, KAZE, AKAZE, ORB

스마트 포인터 형식으로 반환

Ptr<Feature2D> detector = SIFT::create();

vector<KeyPoint> keypoints;
detector->detect(src, keypoints);

검출된 특징점 그리기 함수

void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,
                               const Scalar& color=Scalar::all(-1), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );

 

특징점 기술자 구하기

OpenCV에서는 Mat 객체로 표현

 

실수 기술자 : 특징점 부근 부분 영상의 방향 히스토그램을 사용

- float 자료형을 사용하여 실수 정보 저장

- 알고리즘 :  SIFT, SURF, KAZE 등

 

이진 기술자 : 이진 테스트를 이용하여 부분 영상의 특징 기술

- unchar 자료형을 사용하여 비트 단위로 영상 특징 저장

- 알고리즘 : AKAZE, ORB, BRIEF 등

 

특징점에서 기술자 계산

// 기술자 계산
void cv::Feature2D::compute	(	InputArrayOfArrays 	images,
std::vector< std::vector< KeyPoint > > & 	keypoints,
OutputArrayOfArrays 	descriptors 
)	

// 특징점 검출 및 기술자 계산
void detectAndCompute( InputArray image, InputArray mask,
                                           CV_OUT std::vector<KeyPoint>& keypoints,
                                           OutputArray descriptors,
                                           bool useProvidedKeypoints=false );

특징점 매칭

특징점 매칭

-  두 영상에서 추출한 특징점 기술자를 비교하여 유사한 기술자끼리 선택하는 작업

 

특징 벡터 유사도 측정 방법

- 실수 특징 벡터: L2 norm 사용

- 이진 특징 벡터: 해밍 거리 사용

 

void match( InputArray queryDescriptors, InputArray trainDescriptors,
                CV_OUT std::vector<DMatch>& matches, InputArray mask=noArray() ) const;
                
void drawMatches( InputArray img1, const std::vector<KeyPoint>& keypoints1,
                             InputArray img2, const std::vector<KeyPoint>& keypoints2,
                             const std::vector<DMatch>& matches1to2, InputOutputArray outImg,
                             const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
                             const std::vector<char>& matchesMask=std::vector<char>(), DrawMatchesFlags flags=DrawMatchesFlags::DEFAULT );

좋은 매칭 선별 방법

1.

- 가장 좋은 매칭 결과에서 distance 값이 작은 것 N개 사용

Ptr<DescriptorMatcher> matcher = BFMatcher::create();

vector<DMatch> matches;
matcher->match(desc1, desc2, matches);

std::sort(matches.begin(), matches.end());
vector<DMatch> good_matches(matches.begin(), matches.begin() + 80);

2.

- knnMatch() 함수를 사용하여 두 개의 매칭 결과 반환

- 가장 좋은 매칭 결과의 distance 값과 두 번째로 좋은 매칭 결과의 distance 값의 비율 계산

- 비율이 임계값보다 작으면 선택

vector<vector<DMatch>> matches;
matcher->knnMatch(desc1, desc2, matches, 2);

vector<DMatch> good_matches;
for (const auto& m : matches) {
	if (m[0].distance / m[1].distance < 0.7)
		good_matches.push_back(m[0]);
}

호모그래피와 영상 매칭

호모그래피

- 두 평면 사이의 투시 변환

- 8DOF: 최소 4개의 대응점 좌표가 필요

// 호모그래피 행렬 구하기
Mat findHomography( InputArray srcPoints, InputArray dstPoints,
                                 int method = 0, double ransacReprojThreshold = 3,
                                 OutputArray mask=noArray(), const int maxIters = 2000,
                                 const double confidence = 0.995);

// ransacReprojThreshold:대응점들을 inlner로 인식하기 위한 최대 허용 에러

 

RANSAC

- random sample consensus

- 이상치가 많은 원본 데이터로부터 모델 파라미터를 예측하는 방법