OpenCV 특정점 검출과 매칭
크기 불변 특징점
- 스케일 스페이스 또는 이미지 피라미드를 구성하여 영상의 크기가 바뀌더라도 특징점을 찾아 응용에서 사용
- 주요 알고리즘: 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
- 이상치가 많은 원본 데이터로부터 모델 파라미터를 예측하는 방법