2차원 비전 기반 객체 인식 방법에 대해 정리한다. 이 내용은 모두 OpenCV 에서 사용할 수 있는 것들로, 관련된 함수를 표시하였다.
일반적인 2차원 비전을 통한 객체 인식은 다음과 같은 순서를 가진다.
1. 2차원 이미지 획득
2. 모서리 추출
Canny edge detector 등을 이용해 모서리를 추출한다.
3. 외곽선 추출
모서리 추출 결과를 이용해, 벡터라이징을 하여, 외곽선을 추출한다. 추출된 외곽선은 시퀀스 트리 데이터 구조로 저장된다. 벡터라이징 방법은 프리만 체인을 이용해 8방향 탐색으로 추출하는 등의 기법을 사용한다.
int cvFindContour(CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
int header_size = sizeof(CvContour), int mode = CV_RETR_LIST,
int method = CV_CHAIN_APPROX_SIMPLE,
CvPoint offset = cvPoint(0,0))
4. 외곽선 후처리
- 추출된 외곽선을 이용해, 외곽선을 다각형으로 근사화하거나, 길이 및 면적을 얻거나, 바운딩 박스를 얻을 수 있다.
- 미리 준비한 외곽선과 비교해, 유사도를 계산할 수 있다. 휴의 불변 모멘트를 이용하면, 유사도 비교를 효과적으로 실행할 수 있다.
- 컨벡스홀을 얻을 수 있다.
기타 객체를 인식하는 다양한 방법은 다음과 같다. 이는 계산성능에 따라 선택할 수 있고, 이 중에 단순 마스크 필터나 패치(patch) 부분의 통계 처리 등과 관련된 알고리즘은 매우 빠른 속도로 계산할 수 있다. 다만, 조명, 그림자 등 환경에 따라 민감하게 결과가 달라질 수 있다.
1. 허프 변환
영상에서 직선, 원 혹은 간단한 모양을 찾는 방법이다.
cvHoughLines2(CvArr* image, void* line_storage, int method, double rho,
double theta, int threshold, double param1 = 0, double param2 = 0)
주어진 이미지를 구성하는 하나의 픽셀과 주변의 픽셀이 이루는 수많은 직선을 극좌표계에 누적한다. 이 중에 가장 많이 누적된 직선들을 리턴한다.
허프 변환은 근본적으로 직선 변환 방법이었으므로, 곡선일 경우, 수정된 방법을 사용한다.
CvSeq* cvHoughCircle(CvArr* image, void* circle_storage, int method, double dp,
double min_dist, double param1 = 100,
double param2 = 100, int min_radius = 0, int max_radius = 0)
2. 히스토그램 매칭
주어진 이미지에서 관심 영역에 대한, 특정 방향의 히스토그램을 만들고, 미리 계산한 히스토그램 모델과 비교해, 유사도 여부를 계산하는 방법이다.
히스토그램은 정해진 갯수의 빈(bin)에 축적된 데이터 합산이다. 히스토그램은 그래디언트 크기와 방향, 색상 등으로 부터 추출된 특징이 나타난 횟수를 합산한 것이며, 데이터 분포를 보여주는 통계적인 값이다.
보통, 전체 데이터갯수로 각 빈을 다음 함수로 정규화하면, 특정 패턴을 매칭하는 것에 유리하다.
void cvNormalizeHist(CvHistogram* hist, double factor)
또한, 잡으로 취급되어야 하는 빈을 0값으로 만들어주는 함수도 존재한다.
void cvThreshHist(CvHistogram* hist, double threshold)
다음은 히스토그램의 최대/최소값을 알려준다.
void cvGetMinMaxHistValue(const CvHistogram* hist, float* min_value,
float* max_value, int* min_idx = NULL, int* max_idx = NULL)
다음은 이미지로부터 히스토그램을 계산하는 함수이다.
void cvCalcHist(lplImage** image, CvHistogram* hist, int accumulate = 0,
const CvArr* mask = NULL)
다음은 두개의 히스토그램을 비교하는 함수이다.
double cvCompareHist(const CvHistogram* hist1, const CvHistogram* hist2,
int method)
비교할 때 method에 따라, 상관관계, 카이제곱, 교차, 바타챠야 거리에 따라 유사도를 비교할 수 있다.
다만, 이런 방법들은 조명에 변화에 따라, 색 공간의 이동을 초래하여, 히스토그램 매칭 결과가 부정확하게 나타날 수 있다. 이를 개선한 어스 무버 거리(EMD. Earth mover's distance)는 히스토그램 모양을 흙이 쌓여 있는 형태라 간주하여, 하나의 히스토그램을 다른 형태로 변경하기 위해 얼마나 많은 작업량이 필요한지를 계산한다. 최소 작업량이 두 히스토그램의 유사도이다.
float cvCalcEMD2(const CvArr* sig1, const CvArr* sig2, int distance_type,
CvDistanceFunction distance_func = NULL,
const CvArr* const_matrix = NULL
CvArr* flow = NULL, float* lower_bound = NULL,
void* userdata = NULL)
만약, 주어진 이미지에서 특정 영역이 미리 만들어 놓은 히스토그램과 일치하는 지를 확인하고 싶다면, 히스토그램 역투영 기법(back projection)을 사용하면 된다. 이를 이용해, 매칭되는 이미지 특정 영역을 알 수 있다.
void cvCalcBackProject(lplImage** image, CvArr* back_project,
const CvHistogram* hist)
3. 템플릿 매칭
입력 이미지를 주어진 이미지 패치로 스캔하면서, 강한 유사도가 있는 부분을 찾는다.
void cvMatchTemplate(const CvArr* image, const CvArr* templ, CvArr* results,
int method)
매칭 방법은 제곱차 매칭, 상관관계 매칭, 상관계수 매칭, 정규화 방법을 이용할 수 있다.
4. 배경 삭제
움직이는 객체가 있을 때, 객체 전경은 두고, 배경만 삭제할 수 있다.
5. 특징 검출
객체 추적을 위해, 지역 특징을 추출할 수 있다.
코너 추출
옵티컬 플로우: 움직임 추정
움직임 추정: 칼만 필터
6. 이미지 캘리브레이션
카메라 렌즈 차이에 따라, 이미지의 왜곡이 발생한다. 왜곡된 이미지를 앞의 알고리즘으로 처리하면, 렌즈 차이에 따라, 처리 결과가 달라질 수 있다. 이를 보정하기 위해, 캘리브레이션을 처리할 수 있고, 캘리브레이션 된 결과는 왜곡지도(distortion map)을 생성한다. 이 지도를 이용해, 외곡된 이미지를 보정할 수 있다.
void cvInitUndistortMap(const CvMat* intrinsic_matrix,
const CvMat* distortion_coeffs,
CvArr* mapx,
CvArr* mapy)
7. 투영 및 3D 비전
캘리브레이션이 되었다면, 실좌표에서 픽셀좌표로 투영하거나, 다음 함수를 이용해 스테레오 이미지에서 깊이맵을 얻을 수 있다.
void cvReprojectImageTo3D(CvArr* disparityImage, CvArr* results3DImage, CvArr* Q)
이외에, 영상 모폴로지 변환(morphological transformation)을 이용해 픽셀 밝기나 색상 속성등을 이용해, 유사한 속성이 뭉쳐져 있는 영역을 구할 수 있다. 피라미드 영상을 만들어 LOD (Level Of Detail)별로 영상을 생성할 수 있다.