** 본내용은 OPENCV 4로 배우는 컴퓨터 비전과 머신러닝 도서 내용을 정리한 내용입니다.
행렬을 표현하는 클래스로, 2차원 행렬뿐 아니라 고차원의 행렬또한 표현할 수 있다. 정수, 실수, 복소수 등으로 구성된 행렬 또는 벡터를 저장하거나, 그레이 스케일 또는 컬러 영상을 저장할 수도 있다. 2차원 영상데이터를 저장하고 처리하는 용도로 가장 많이 쓰이고 있다.
Mat::dims
Mat행렬의 차원
Mat::rows
행개수(세로 픽셀 크기)
Mat::cols
열개수(가로 픽셀 크기)
Mat::size
3차원 이상 행렬의 크기 정보
Mat::data
행렬의 원소데이터가 저장된 메모리 공간을 가리키는 포인터형 멤버변수
Mat 클래스에서는 행렬이 어떤 자료형을 사용하는 지에 대한 정보를 깊이라고 부른다. 또한 Mat 행렬의 깊이를 다음과 같은 형식의 매크로 상수를 이용하여 표현한다.
CV_8U : uchar, usigned char
CV_8S : schar, signed char
CV_16U : ushort, unsigned short
CV_16S : signed short
CV_32S : int
CV_32F : float
CV_64F : double
CV_16F : float16_t
Mat행렬 원소를 구성할때, 각각의 값을 채널이라고 하는데, 여기서 여러개의 채널을 가질 수 있다. 예를 들어 그레이 스케일의 영상이라면 하나의 픽셀이 밝기정보 하나만 사용하므로 1채널 행렬이다. 트루컬러 영상은 하나의 픽셀이 파란색, 녹색, 빨간색 삼원색의 색상정보를 가지므로 3채널 행렬로 표현한다.
이를 CV_<bit-depth>{U|S|F}C(<number_of_channels>)
로 표현한다.
만약 B, G, R 세 색상 성분을 가지는 컬러영상은 unsigned char 자료형과 세개의 채널을 가지므로 CV_8UC3 타입이다.
먼저 Mat img1; 로 행렬을 생성할 수 있다. img의 rows와 cols는 각각 0인 상태이다.
크기를 함께 설정하고자 하면Mat img1(int rows, int cols, int type);
로 행렬을 생성할 수 있다.
여기서 type은 위에서 정리한 매크로 상수를 전달하면 된다.
int 자료형 대신 size클래스를 사용하여 행렬의 크기를 나타낼 수도 있다.
Mat(Size size, int type);
으로 행렬을 선언하며,
예로 Mat img(Size(640,480), CV_8UC3);
로 작성 가능하다.
위 방식으로 행렬의 크기와 타입을 지정하여 행렬을 생성할 경우, 모든 원소는 임의의 값으로 채워지게 된다. 이 대신 모든 원소를 특정값으로 초기화하여 사용하고자 하면
Mat(int rows, int cols, int type, const Scalar& s);
를 통해 Scalar클래스를 이용해 줄 수 있는데,
이는 주로 영상의 픽셀 값을 표현하는 용도로 사용된다.
예를 들어 모든 픽셀값이 128로 초기화된 그레이스케일 영상은
Mat img(480, 640, CV_8UC1, Scalar(128));
모든 픽셀이 빨간색으로 설정된 컬러 영상은 Mat img(480,640, CV_8UC3, Scalar(0,0,255));
로 표현가능하다.
새로운 행렬을 생성할 때 모든 원소 값을 0으로 초기화하는 경우에 사용된다. 파라미터로 행과 열 또는 size, 그리고 type이 들어간다.
모든 원소가 1로 초기화된 행렬을 생성하는 경우에 사용된다.
단위 행렬을 생성할때 사용된다.
외부 메모리 공간을 활용하여 Mat 객체를 생성할 수 있다.
float data[] = {1, 2, 3, 4, 5, 6};
Mat mat(2,3, CV_32FC1, data);
Mat 행렬의 1행은 data배열의 1, 2, 3으로 채워지고, 2행은 4, 5, 6으로 채워지게 된다.
Mat_<float> mat_(2,3);
mat_ << 1, 2, 3, 4, 5, 6;
Mat mat = mat_;
위와 같이 << 연산자를 통해 지정할 수도 있다.
비어있는 Mat 객체 또는 이미 생성된 Mat 객체에 새로운 행렬을 할당할때 사용한다. 새로 만들 행렬의 크기 또는 타입이 기존 행렬과 다른경우에 기존 메모리 공간을 해제한 후 새로운 행렬 데이터 저장을 위한 메모리 공간을 할당한다.
행렬 원소에 설정할 값을 파라미터로 넘겨 설정할 수 있다.
만약
Mat img1 = img2
혹은
Mat img3;
img3 = img1;
와 같은 얕은 복사를 하게 되면 픽셀 데이터만을 공유하게 된다.
복사본 영상을 새로 생성할때 메모리 공간을 새로 할당하여 픽셀 데이터 전체를 복사하고자 한다면 Mat::clone() 또는 Mat::copyTo() 함수를 사용한다.
Mat img = img1.clone();
Mat img;
img1.copyTo(img);
이를 통해 깊은 복사를 할 수 있다.
Mat img2 = img1(Rect(100, 50, 10, 20);
img1 의 (100,50) 좌표에서 시작하여 10x20 사이즈의 부분을 추출하여 img2에 저장하는 코드이다.
지정한 범위의 행으로 구성된 행렬을 반환
지정한 범위의 열로 구성된 행렬을 반환
1행 또는 1열짜리 행렬을 만들고자 할때 추출한 부분 행렬을 반환
+, -, *, / 연산기호를 사용하여 계산 가능하다.
같은 위치에 있는 원소끼리 곱셈 연산을 할때 사용한다.
행렬의 역행렬을 구할 때 사용한다.
전치행렬을 구할 때 사용한다.
행렬의 타입을 변경
img.converTo(img1f, CV_32FC1);
행렬 원소 데이터를 같이 참조하는 행렬을 반환, 모양만 변경된 행렬을 반환한다.
새로운 행렬을 만드는 것이 아니다.
uchar data1[] = {1,2,3,4,5,6,7,8,9,10,11,12};
Mat mat1(3, 4, CV_8UC1, data1);
Mat mat2= mat1.reshape(0,1);
위 코드에서 mat2는 기존의 data1의 원소를 가져온 3x4 의 mat1 행렬에서 행의 수가 1인 행렬로 크기가 변경된다.
따라서 mat1 은 [1, 2, 3, 4 \ 5, 6, 7, 8 \ 9, 10, 11, 12] 이고,
mat2 는 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 이다.
행렬의 모양이 아닌 행 크기를 변경할때 사용한다.
mat1.resize(5, 100);
3x4크기에서 행의 개수가 5이고, 새롭게 추가된 행의 원소가 100으로 초기화된 행렬이 만들어 진다.
[1, 2, 3, 4 \ 5, 6, 7, 8 \ 9, 10, 11, 12 \ 100, 100, 100, 100 \ 100, 100, 100, 100]
이미 존재하는 행렬에 맨마지막 행에 원소 데이터를 추가
맨 아래 행을 제거할때 사용