OpenCV CvMat행렬의 구조와 데이터 접근 방법에 대해 정리한다.
CvMat 행렬의 구조는 다음과 같다.
CvMat 행렬의 구조는 다음과 같다.
typedef struct CvMat {
int type;
int step;
int* refcount; // for internal use only
union {
uchar* ptr;
short* s;
int* i;
float* fl;
double* db;
} data;
union {
int rows;
int height;
};
union {
int cols;
int width;
};
} CvMat;
매트릭스의 행렬의 생성
CvMat* cvCreateMat( int rows, int cols, int type );
// Create only matrix header without allocating data
//
CvMat* cvCreateMatHeader( int rows, int cols, int type );
// Initialize header on existing CvMat structure
//
CvMat* cvInitMatHeader(
CvMat* mat,
int rows,
int cols,
int type,
void* data = NULL,
int step = CV_AUTOSTEP
);
// Like cvInitMatHeader() but allocates CvMat as well.
//
CvMat cvMat(
int rows,
int cols,
int type,
void* data = NULL
);
// Allocate a new matrix just like the matrix 'mat'.
//
CvMat* cvCloneMat( const cvMat* mat );
// Free the matrix 'mat', both header and data.
//
void cvReleaseMat( CvMat** mat );
행렬 데이터에 접근하기
- 간편한 방법
CV_MAT_ELEM() 매크로를 사용하여 행렬의 원소값 받아오기
CvMat* mat = cvCreateMat( 5, 5, CV_32FC1 );
float element_3_2 = CV_MAT_ELEM( *mat, float, 3, 2 );
printf("Exercise 3_4, matrix created and accessed [3,2]=%f\n",element_3_2);
CV_MAT_ELEM_PTR() 매크로를 사용하여 행렬의 원소값 설정하기
CvMat* mat = cvCreateMat( 5, 5, CV_32FC1 );
float element_3_2 = 7.7;
*( (float*)CV_MAT_ELEM_PTR( *mat, 3, 2 ) ) = element_3_2;
// below from example ch3_ex3_8.txt
cvmSet( mat, 2, 2, 0.5000 );
cvSetReal2D( mat, 3, 3, 0.3300 );
printf("Exercise 3_5, matrix created and accessed [3,2]=%f, [2,2]=%f, [3,3]=%f\n",CV_MAT_ELEM( *mat, float, 3, 2 ),CV_MAT_ELEM( *mat, float, 2, 2 ),CV_MAT_ELEM( *mat, float, 3, 3 ));
CV_MAT_ELEM() 매크로와 CV_MAT_ELEM_PTR() 매크로는 호출할 때마다 주소값 계산을 반복한다.
매번 행렬의 데이터 영역 시작 주소를 찾고, 알고싶은 원소의 주소까지 오프셋을 계산한 후 시작 주소에 더해서 해당 원소에 접근하는 작업을 반복한다.
- 엄격한 방법
Example 3-6. Pointer access to matrix structures
uchar* cvPtr1D(
const CvArr* arr,
int idx0,
int* type = NULL
);
uchar* cvPtr2D(
const CvArr* arr,
int idx0,
int idx1,
int* type = NULL
);
uchar* cvPtr3D(
const CvArr* arr,
int idx0,
int idx1,
int idx2,
int* type = NULL
);
uchar* cvPtrND(
const CvArr* arr,
int* idx,
int* type = NULL,
int create_node = 1,
unsigned* precalc_hashval = NULL
);
Example 3-7. CvMat and IplImage element functions
double cvGetReal1D( const CvArr* arr, int idx0 );
double cvGetReal2D( const CvArr* arr, int idx0, int idx1 );
double cvGetReal3D( const CvArr* arr, int idx0, int idx1, int idx2 );
double cvGetRealND( const CvArr* arr, int* idx );
CvScalar cvGet1D( const CvArr* arr, int idx0 );
CvScalar cvGet2D( const CvArr* arr, int idx0, int idx1 );
CvScalar cvGet3D( const CvArr* arr, int idx0, int idx1, int idx2 );
CvScalar cvGetND( const CvArr* arr, int* idx );
Example 3-8. Set element functions for CvMat or IplImage.
// Also see usage example in ch3_ex5.cpp
void cvSetReal1D( CvArr* arr, int idx0, double value );
void cvSetReal2D( CvArr* arr, int idx0, int idx1, double value );
void cvSetReal3D(
CvArr* arr,
int idx0,
int idx1,
int idx2,
double value
);
void cvSetRealND( CvArr* arr, int* idx, double value );
void cvSet1D( CvArr* arr, int idx0, CvScalar value );
void cvSet2D( CvArr* arr, int idx0, int idx1, CvScalar value );
void cvSet3D(
CvArr* arr,
int idx0,
int idx1,
int idx2,
CvScalar value
);
void cvSetND( CvArr* arr, int* idx, CvScalar value );
- 적절한 방법
float sum( CvMat* mat ) {
float s = 0.0f;
for( int row = 0; row < mat->height; row++ )
{
float* ptr = mat->data.fl + row * mat->step / 4; // Float형 포인터인 경우
// float* ptr = (float*)(mat->data.ptr + row * mat->step); // 그냥 포인터인 경우
for( int col = 0; col < mat->width; col++ )
{
s += *ptr++;
}
}
return( s );
};
OpenCV에서 step은 행렬의 행 크기를 바이트 단위로 나타낸다.
그러므로 다음행으로 넘어가기 위해서는 해당 포인터에 step을 더해줘야한다.
댓글 없음:
댓글 쓰기