-
CvMat 행렬 구조체Programming/OpenCV 2015. 3. 27. 21:36
CvMat 행렬 구조체 OpenCV
행렬에 대해 알아보기 전에 두 가지 사항을 기억해야 한다.
- OpenCV에는 "벡터"를 표현하는 데이터 타입이 없다.
- 벡터를 사용하고 싶다면, 한 열(전치 벡터의 경우 한 행)짜리 행렬을 사용하면 된다.
- OpenCV에서 사용하는 행렬은 조금은 추상적인 개념이다.
- 행렬의 원소는 단순히 숫자만 해당 x
2차원 행렬을 만드는 함수의 원형CvMat* cvCreateMat ( int rows, int cols, int type );
세 번째 인자 type에는
CV_<비트수>(S|U|F)C<채널 개수>
형태의 다양한 데이터 타입 지정이 가능하다.32비트 실수형 1채널(CV_32FC1), 부호 없는 8비트 정수형 3채널(CV_8UC3) 등 여러 데이터 타입으로 구성될 수 있다.
S : signed integer
U : unsigned integer
F : float
ex1) CV_32FC1 , 실수형 32비트 1채널
ex2) CV_8UC3 , 부호없는 8비트 정수형 3채널
CvMat 구조체 정의: 행렬의 "헤더"
typedef struct CvMat { int type; int step; int* refcount; // 내부적 용도로만 사용된다. int hdr_refcount; union { uchar* ptr; short* s; int* i; float* fl; double* db; } data; union { int rows; int height; }; union { int cols; int width; }; } CvMat;
행렬은 여러 가지 방법으로 생성할 수 있다. 가장 일반적인 생성 방법은cvCreateMat()
함수를 사용하는 것이다.행렬의 생성과 소멸// 'type'으로 지정된 타입의 행렬('rows' x 'cols')을 생성한다. CvMat* cvCreateMat( int rows, int cols, int type ); // 데이터 할당 없이 행렬의 헤더만을 생성한다. CvMat* cvCreateMatHeader( int rows, int cols, int type ); // 이미 존재하는 CvMat 구조에서 헤더값을 초기화한다. CvMat* cvInitMatHeader( CvMat* mat, int rows, int cols, int type, void* data = NULL, int step = CV_AUTOSTEP ); // cvInitMatHeader() 와 유사하지만, CvMat을 새로 만든다. CvMat cvMat( int rows, int cols, int type, void* data = NULL ); // 행렬 'mat'와 같은 새로운 행렬을 만든다. CvMat* cvCloneMat ( const cvMat* mat ); // 행렬 'mat'을 소멸시킨다(헤더와 데이터 모두). void cvReleaseMat( CvMat** mat );
ex) 정적 배열을 이용하여 OpenCV 행렬 만들기float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025 }; CvMat rotmat; cvInitMatHeader( &rotmat, 2, 2, CV_32FC1, vals ); // 위 코드는 아래와 같다. // CvMat rotmat = cvMat(2, 2, CV_32FC1, vals);
행렬 데이터에 접근하기
간편한 방법
CV_MAT_ELEM() 매크로를 사용하는 것.
행렬과 원소의 타입, 행과 열을 입력받아 해당 원소의 값을 반환한다.
CvMat* mat = cvCreateMat( 5, 5, CV_32FC1 ); float element_3_2 = CV_MAT_ELEM( *mat, float, 3, 2 ); // 행렬의 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; // 행렬의 (3, 2)의 값을 7.7로 변경
엄격한 방법
cvPtr*D 또는 cvGet*D 형태의 함수들을 사용한다.
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* cvPtr1D( const CvArr* arr, int* idx, int* type = NULL, int create_node = 1, unsigned* precalc_hashval = NULL );
ex) cvPtr2D
#include "cv.h" #include "highgui.h" int main() { int x, y; int data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; int *ptr; CvMat mat = cvMat(2, 3, CV_32SC3, data); for (y = 0; y < mat.rows; y++) { for (x = 0; x < mat.cols; x++) { ptr = (int*)cvPtr2D(&mat, y, x); printf(" (%4d, %4d, %4d) ", *ptr, *(ptr + 1), *(ptr + 2)); } printf(" \n"); } return 0; }
결과( 1, 2, 3) ( 4, 5, 6) ( 7, 8, 9) ( 10, 11, 12) ( 13, 14, 15) ( 16, 17, 18)
단순히 데이터를 읽기 위해서라면cvGet*D
형태의 함수를 사용하면 편리하다.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 );
이 함수들을 많이 사용하면 연산량이 크게 증가할 수 있으므로, 코드를 간단하게 작성해야 할 때에만 사용하는 것이 좋다.
ex) GetReal2D#include "cv.h" #include "highgui.h" int main() { int x, y, nvalue; uchar data[] = {1, 2, 3, 4, 5, 6}; /*uchar == unsigned char */ CvMat mat = cvMat(2, 3, CV_8UC1, data); for(y = 0; y < mat.rows; y++) { for(x = 0; x < mat.cols; x++) { nvalue = (int)cvGetReal2D(&mat, y, x); printf("%4d", nvalue); } printf("\n"); } }
결과1 2 3 4 5 6
ex) cvGet2D#include "cv.h" #include "highgui.h" int main() { int x, y; CvScalar elem; char data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; CvMat mat = cvMat(2, 3, CV_8UC3, data); for (y = 0; y < mat.rows; y++) { for (x = 0; x < mat.cols; x++) { elem = cvGet2D(&mat, y, x); printf("(%2d, %2d, %2d)", (int)elem.val[0], (int)elem.val[1], (int)elem.val[2]); } printf(" \n"); } return 0; }
결과( 1, 2, 3)( 4, 5, 6)( 7, 8, 9) (10, 11, 12)(13, 14, 15)(16, 17, 18)
행렬에 데이터를 설정하는 함수는 cvSet*D 형태의 함수가 있다.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 );
ex) cvSetReal2D#include "cv.h" #include "highgui.h" int main() { CvMat* pMat = cvCreateMat(2, 3, CV_8UC1); int x, y, nValue; cvSetReal2D(pMat, 0, 0, 1); cvSetReal2D(pMat, 0, 1, 2); cvSetReal2D(pMat, 0, 2, 3); cvSetReal2D(pMat, 1, 0, 4); cvSetReal2D(pMat, 1, 1, 5); cvSetReal2D(pMat, 1, 2, 6); for (y = 0; y < pMat->rows; y++) { for (x = 0; x < pMat->cols; x++) { nValue = (int)cvGetReal2D(pMat, y, x); printf("%4d", nValue); } printf("\n"); } cvReleaseMat(&pMat); return 0; }
결과1 2 3 4 5 6
'Programming > OpenCV' 카테고리의 다른 글
cvSplit, cvMerge, cvFlip (0) 2015.04.14 IplImage 구조체 (0) 2015.04.12 기본 데이터 타입 (0) 2015.03.27 동영상 재생 (0) 2015.03.27 정지 영상 출력 (0) 2015.03.21