OpenCV의 영상 데이터 구조체인 IplImage는 imageData 라는 배열에 영상의 픽셀 정보를 저장한다.
IplImage로부터 픽셀값을 읽어오는 방법에는 직접 imageData라는 배열에 접근해서 가져오는 방법과 cvGet* 함수를 이용하는 방법이 있다.
imageData에 직접 접근하는 경우 픽셀의 인덱스를 계산하여 값을 얻어온다. 좌표가 (x,y)인 픽셀의 값은 다음과 같이 읽어온다. 인덱스를 계산할 때는 width 보다는 widthStep을 이용하는 것이 안전하다. widthStep은 IplImage에서 row하나가 저장되는 메모리의 폭을 나타낸다고 보면 된다. 영상의 폭이 홀수로 끝나는 경우는 영상의 한 row가 저장되는 메모리의 폭이 width와 다른 경우도 있기 때문이다. (이런 경우 x 좌표가 하나씩 밀리는 현상이 나타난다.)
다음과 같은 영상이 있다고 할 때,
IplImage *image = cvLoadImage(filename) ;
1 channel gray 영상의 경우:
int index = x + y*image->widthStep ;
unsigned char value = image->imageData[index] ;
3 channel RGB 영상의 경우:
int index = 3*x + y*widthStep ;
unsigned char B = image->imageData[index] ;
unsigned char G = image->imageData[index+1] ;
unsigned char R = image->imageData[index+2] ;
또 다른 방법은 OpenCV가 제공하는 cvGet 함수를 이용하는 것이다. 1채널 Gray 영상에는 cvGetReal2D() 함수를, 다채널 영상에는 cvGet2D()를 사용한다. cvGetReal2D 함수는 double 값을, cvGet2D는 CvScalar 구조체에 각 채널별로 값을 저장해서 리턴한다. 함수의 인자에 x와 y의 순서에 주의한다.
1 channel gray 영상의 경우
double value = cvGetReal2D(image, y, x) ;
3 channel RGB 영상의 경우
CvScalar value = cvGet2D(image, y, x) ;
double B = value.val[0];
double G = value.val[1];
double R = value.val[2];
imageData에 직접 접근하는 방법이 픽셀값에 접근하는 성능이 빠르다고 한다. 아마도 cvGet* 함수 내부에 있는 오류 검출 코드들 때문이 아닌가 한다. 그렇지만 인덱스 계산할 필요 없이 픽셀 좌표 만으로 데이터를 가져오는 데는 cvGet* 함수가 더 편리하고, 코드도 읽기가 편하다. 성능에 문제가 없다면 괜찮은 방법이다.