ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CvMat 행렬 구조체
    Programming/OpenCV 2015. 3. 27. 21:36


    행렬에 대해 알아보기 전에 두 가지 사항을 기억해야 한다.

    • 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

    댓글

Designed by Tistory.