열심히(?) 추출한 특징점들의 매칭에 대해서 알아보겠습니다.
영상으로부터 SIFT나 SURF의 국소특징들을 추출해 보았기 때문에
이제는 그것을 응용해 보겠습니다.
특징점의 매칭은 두 개의 영상간의 대응하는 점들을 찾는 과정입니다.
즉, 앞에서 언급하였던 특정물체인식에 있어서
미리 만들어 둔 물체의 모델 데이터베이스와 입력되는 영상간에 대응되는 점들을 찾으므로써
가장 많이 대응되는 점을 가지는 물체 짝들을 동일한 물체로 인식하겠다는 것으로
생각할 수 있습니다.
아래의 그림을 보시면 어떻게 진행되는지 대략적인 이해를 할 수 있을겁니다.
아래의 두 영상 사이를 연결하는 직선들은
양단 키포인트의 특징 벡터들간의 거리가 가까운 점들을 서로 연결하고 있습니다.
아래가 매칭을 위한 프로그램입니다.
실행 - 실행파일 이름과 입력영상 1, 2의 파일명을 차례로 입력하면 됩니다.
keypoint_matching.exe [입력영상 1번의 파일명] [입력영상 2번의 파일명] |
코드 - cpp
#include <cv.h> using namespace std; const int DIM_VECTOR = 128; // 128次元ベクトル /** /** for (int i = 0; i < descriptors->total; i++) { // 최근접점에서도 거리가 임계값 이상이라면 무시한다. // 최근접점이 없는 경우 /** * @param[out] ptpairs 유사 키포인트 인덱스의 열(2개당 1짝) int main(int argc, char** argv) { cvNamedWindow("Keypoint Matching"); // 영상은 그레이스케일로 로드 // 결과의 표현을 위해 컬러영상도 로드 // 매칭을 표현하기 위한 영상의 표현 // 영상 1의 표현 CvSeq *keypoints1 = 0, *descriptors1 = 0; // SURF의 추출 // 특징 벡터의 유사도가 높은 키포인트들을 선으로 연결 // 2개씩 짝을 맞추어 직선을 긋는다. // 키포인트 매칭의 결과를 표현 // 후처리 - 메모리 해제 등 return 0; |
영상 1(왼쪽의 영상)의 각 키포인트에 대해
영상 2(오른쪽 아래의 영상)로부터 최근접점을 검색하고 있습니다.
검색의 방법은 선형탐색으로,
모든 키포인트간의 거리를 계산해 제일 가까운 것을 선택합니다.
그러므로, 영상 1의 키포인트 수가 800, 영상 2의 키포인트 수가 800개라고 하면
전부 800 x 800 = 640,000의 거리계산이 필요하게 됩니다.
선형 탐색은 - 계산량의 측면에서 특별히 - 효율성이 나쁘기 때문에
다음에 조금 더 고속 검색을 위한 방법에 대해 알아보도록 하겠습니다.
여기서, SURF는 라플라시안이 일치하지 않는 점끼리는 닮지 않았다고 판정해도 좋다고 언급하고 있습니다. 알고리즘 부분은 후에 따로 정리하고 내용을 추가하겠습니다.
유클리드 거리가 THRESHOLD(=0.3)보다 작은 경우에 대응하는 것으로 판단하고
직선으로 두 점을 연결하여 나타내고 있습니다.
실제는 거리의 비교이므로 거리의 제곱을 사용해도 문제 없습니다.
(다만 임계값을 조정해주어야 합니다.)
대량으로 계산이 필요하므로 sqrt()를 사용하지 않고 int형으로 계산하는 편이
속도가 더 빠를지도 모르겠다고 하네요.
SURF 국소특징의 강인성 검증
SIFT와 SURF는 영상의 스케일 변화, 평행 이동, 회전, 은폐(Occlusion)에 대해서
강인하다고 얘기하고 있습니다.
그래서 영상 2를 변경해서 키포인트의 매칭을 테스트 해 보도록 하겠습니다.
<Scale>
<Rotation>
<Occlusion>
영상의 크기 변경, 회전, 은폐등은 아래의 코드를 참조하시면 가능합니다.
(직접 코딩하시거나 알씨에서 손으로 하셔도 무방합니다만.)
은폐는 왼쪽 절반을 흰색으로 칠을 합니다.
영상의 사이즈 변경
영상의 회전
은폐
// 축소 IplImage* dst = cvCreateImage(cvSize(src->width/2, src->height/2), src->depth, src->nChannels); cvResize(src, dst); // 은폐(왼쪽 반을 전부 색칠함) IplImage* dst = cvCloneImage(src); cvRectangle(dst, cvPoint(0, 0), cvPoint(dst->width/2, dst->height), cvScalar(255,255,255), CV_FILLED); // 회전 IplImage* dst = cvCloneImage(src); int angle = 45; // 회전각도 float m[6]; CvMat M; m[0] = (float)(cos(angle * CV_PI / 180)); m[1] = (float)(-sin(angle * CV_PI / 180)); m[2] = src->width * 0.5; m[3] = -m[1]; m[4] = m[0]; m[5] = src->height * 0.5; cvInitMatHeader(&M, 2, 3, CV_32FC1, m, CV_AUTOSTEP); cvGetQuadrangleSubPix(src, dst, &M); |
특정 물체 인식에의 응용
키포인트의 매칭은 여러 물체들이 있는 영상에서 일부에 있는 물체의 경우에도 가능합니다.
영상 2를 여러 물체를 결합한 영상으로 구성해 보았습니다.
영상 2(오른쪽 아래 영상)는 많은 물체 영상을 정리한 영상이지만,
다음 장에서는 물체 모델 데이터베이스,
대량의 물체 영상의 키포인트와 특징 벡터를 격납한 데이터베이스에 옮겨 놓을 예정이라고 하네요.
저는 영상 만드는 것이 귀찮아서. ^-^
같은 영상에 임계값만 0.2와 0.3을 비교하고 넘어 가도록 하겠습니다.
<임계값 0.2>
<임계값 0.3>
아직은 임계값의 역할이 무엇인지 정확하게 이야기할 수 있을만큼
매칭 알고리즘을 정확하게 이해하고 있는 상태는 아니지만 임계값을 0.3으로 하였을 경우에는
0.2인 경우에 비해서 매칭되는 점들이 많아집니다만,
그 만큼 에러도 많아지네요.
(쉽게 아실 수 있겠지만 두 영상간의 닮은 정도, 또는 벡터들의 오차값이
0.3보다 큰 경우와 0.2보다 큰 경우로 생각해보면
위의 임계값이 어떤 역할을 하고 있는지는 쉽게 이해가 될 것으로 생각됩니다.)
에러는 많이 보이지만, 영상1과 같은 영상2의 시계 영상에 매칭되는 선들이
집중 되는 것을 알 수 있습니다.
실제로 특징점의 매칭을 특정 물체 인식에 사용하는 경우에는
잘못된 매칭점들이 다소 있더라도 큰 문제가 되지는 않습니다.
아래와 같이 정답의 영상에 매칭하는 선이 집중되고 있으면 (득표수가 많으면)
제대로 인식한다고 판단합니다.
다소 잘못된 매칭 부분이 있더라도 인식할 수 있다는 것을 이용하여
인식을 고속화시키는 방법도 제안되고 있습니다라고 얘기하고 있네요.
잘못된 매칭 부분이 있더라도 인식할 수 있다는 얘기는
특정물체인식의 경우 구성된 데이터베이스 내에서 제일 매칭되는 부분이 많은 영상을
입력영상(여기에서는 영상1)과 동일한 영상으로 인식할 수 있다는 얘기로
이해하면 좋을 것 같습니다..
다음은 물체인식에 관한 이야기 - (5) 물체 모델의 데이터 베이스 작성입니다.
--
물체 인식에 관한 이야기 - 목록
물체인식에 관한 이야기 - (1) 시작하기
물체인식에 관한 이야기 - (2) SIFT특징 추출
물체인식에 관한 이야기 - (3) SURF 특징추출하기
물체인식에 관한 이야기 - (4) 특징점의 매칭
물체인식에 관한 이야기 - (5) 물체 모델의 데이터 베이스 작성
물체인식에 관한 이야기 - (6) 선형탐색을 이용한 특정 물체 인식
물체인식에 관한 이야기 - (7) 최근접탐색의 고속화
--
* 본 자료의 내용은 aidiary의 내용을 바탕으로 하고 있습니다.
* 일본어가 가능하신 분은 직접 aistudy 블로그에 엑세스하셔서 보는 것이
저의 허접한 번역과 부족한 코멘트 보다는 훨씬 이해도 쉽고 유익하리라 판단됩니다.