[컴퓨터 비전] Mat클래스 - 개요, 생성과 초기화 Week3_2

Ogu·2023년 10월 11일
0
post-thumbnail

W3_2 기본 자료형, 행렬Mat클래스

3.2 Mat 클래스

3.2.1 Mat 클래스 개요

  • OpenCV에서 가장 많이 사용하는 행렬을 나타내는 클래스
  • 2차원 행렬 뿐만 아니라 고차원 행렬을 표현 가능
  • 한 개 이상의 채널
  • 정수, 실수, 복소수 등으로 구성된 행렬 또는 벡터 저장
  • 벡터 필드, 포인트 클라우드, 텐서, 히스토그램 등의 정보를 저장하는 용도로 사용
  • 2차원 영상 데이터를 저장하고 처리

Mat 클래스의 생성자, 멤버 변수, 멤버 함수

**Mat::dims** 멤버 변수 ⇒ Mat 행렬의 차원

  • 영상과 같은 2차원 행렬의 경우 Mat:dims 값은 2

**Mat::rows, Mat::cols 멤버 변수 ⇒ 2차원 행렬의 크기 🌟**

  • Mat::rows ⇒ 행렬의 행 개수 , 영상의 세로 픽셀 크기
  • Mat::cols ⇒ 행렬의 열 개수, 영상의 가로 픽셀 크기
  • → Mat 객체가 2차원 행렬인 경우에만 의미있는 값을 가지며, 3차원 이상의 행렬에서는 -1 저장
  • 3차원 이상의 행렬 → Mat::size 멤버 변수를 이용해 참조

**Mat::data** 멤버 변수 ⇒ 행렬의 원소 데이터가 저장되어 있는 메모리 공간을 가리키는 포인터형 멤버 변수

  • 행렬에 아무것도 저장되어 있지 않은 상태 → 0(NULL)
  • Mat::cols ⇒ 행렬의 열 개수

  • Mat클래스의 모든 멤버 변수는 public 접근지시자로 선언되어 있음

    → 외부에서 직접 접근 O

  • 다양한 자료형의 원소를 가질 수 O

  • Mat 클래스의 원소는 하나의 값을 가질 수도 있고, 또는 여러 개의 값이 모여 하나의 원소로 표현됨

  • unsigned char, signed char, unsigned short, signed short, int, float, double 자료형을사용하는Mat 행렬을지원

  • 깊이(depth): Mat 클래스에서 행렬이 어떤 자료형을 사용하는 지에 대한 정보

    CV_<bit-depth>{U|S|F}

    • CV_ : OenCV를 나타내는 접두사
    • : 8, 16, 32, 64 숫자 지정 → 원소 값 하나의 비트 수
    • {U|S|F} → U, S, F 세 문자중 하나 지정
      • U : 부호 없는 정수형 (unsigned char)

      • S : 부호 잆는 정수형 (signed char)

      • F : 부동 소수형 (float)

        #define CV_8U   0    // uchar, unsigned char
        #define CV_8S   1    // schar, signed char
        #define CV_16U  2    // ushort, unsigned short
        #define CV_16S  3    // signed short
        #define CV_32S  4    // int
        #define CV_32F  5    // float
        #define CV_64F  6    // double
        #define CV_16F  7    // float16_t

        ex) 행렬 원소를 float 자료형으로 선언 → CV_32F

  • Mat 행렬 원소는 하나의 값(채널)을 가질 수도 있고, 여러 개로 구성된 값을 가질 수도 있음

  • 채널(channel) : Mat 행렬 원소를 구성하는 각각의 값

    • → 즉 하나의 채널을 가질 수도, 여러 개의 채널을 가질 수도 있음
  • 하나의 행렬을 구성하는 각 채널은 모두 같은 자료형 사용

    • ex) 그레이스케일 → 하나의 픽셀이 밝기 정보 하나만 사용 → 1채널 행렬
    • ex) 트루컬러 영상 → 하나의 픽셀이 파란색(B), 녹색(G), 빨간색(R) 세 개의 색상 정보를 가지는 3채널 행렬
  • Mat 객체의 타입(type) : Mat 행렬의 깊이 정보(자료형) + 채널 수 정보 → 매크로 상수로 표현

    • CV_<bit-depth>{U|S|F}C(<number_of_channels>)
    • → 깊이(depth) 표현 매크로 뒤에 C1, C3과 같은 채널 정보 추가
    • ex) CV_8UC1 → 8비트 unsighed char, 채널이1개인 행렬 또는 영상
    • ex) CV_32FC2 → 복소수처럼 두개의 실수 값 사용

행렬의 생성과 초기화

**Mat 클래스의 기본 생성자** 이용

  • 인자 X, 단순히 Mat 클래스 타입의 변수 선언
  • Mat img1;
    • → 비어있는 행렬
    • 즉, img1.rows, img1.cols = 0, img1.data = 0(NULL)

Mat 객체를 생성함과 동시에 원소 값 저장을 위한 메모리 공간 할당

Mat::Mat(int rows, int cols, int type);

• rows새로 만들 행렬의 행 개수(영상의 세로 크기)
• cols새로 만들 행렬의 열 개수(영상의 가로 크기)
• type새로 만들 행렬의 타입
  • → 행 개수가 ros, 열 개수가 cols인 2차원 행렬(또는 영상) 생성

ex)

Mat img2(480, 640, CV_8UC1); //unsigned char, 1-channel, **그레이스케일**
Mat img2(480, 640, CV_8UC3); //unsigned char, 3-channel, **트루컬러**

→ 세로크기(rows), 가로크기(cols) 순서임 점에 주의

**Size** 클래스 → mat 클래스 생성자에서 행렬의 크기 지정

Mat::Mat(Size size, int type);

• size새로 만들 행렬의 크기. Size(cols, rows) 또는 Size(width, height)
• type새로 만들 행렬의 타입
  • Size 클래스 → 2차원 사각형(또는 영상, 행렬)의 가로, 세로 크기를 표현하는 클래스
  • Size 클래스 → 2개 인자 (가로 크기, 세로 크기) 순서로 값 지정
  • ex) 가로크기가 640, 세로 크기가 480인 3채널 컬러 영상 → Mat img4(Size(640, 480), CV_8UC3); // (Size(width, height)
  • but, Mat 행렬의 모든 원소가 쓰레기 값(garbage value)인 임의의 값으로 채워짐
Mat::Mat(int rows, int cols, int type, const Scalar& s);
Mat::Mat(Size size, int type, const Scalar& s);
• rows새로 만들 행렬의 행 개수(영상의 세로 크기)
• cols새로 만들 행렬의 열 개수(영상의 가로 크기)
• size새로 만들 행렬의 크기
• type새로 만들 행렬의 타입
• s행렬 원소 초깃값
  • **Scalar 클래스**네 개의 실수 값을 저장할 수 있는 클래스, 영상 픽셀 값을 표현
    • 그레이스케일 : 하나의 멤버 변수만 사용
    • 3채널 컬러 영상 : 세 개의 멤버 변수 사용
    • 파란색(B), 녹색(G), 빨간색(R) 순서
  • ex) 모든 픽셀 값이 128로 초기화된 그레이 스케일 영상, 모든 픽셀 빨간색 컬러 영상
    Mat img5(480, 640, CV_8UC1, Scalar(128));          // initial values, 128
    Mat img6(480, 640, CV_8UC3, Scalar(0, 0, 255));    // initial values, red

**Mat::zeros()** : 모든 원소가 0으로 초기화 된 행렬

static MatExpr Mat::zeros(int rows, int cols, int type);
static MatExpr Mat::zeros(Size size, int type);
• rows새로 만들 행렬의 행 개수(영상의 세로 크기)
• cols새로 만들 행렬의 열 개수(영상의 가로 크기)
• size새로 만들 행렬의 크기
• type새로 만들 행렬의 타입
• 반환값모든 원소가 0으로 초기화된 행렬 표현식
  • Mat클래스 행렬 원소 초깃값에 Scalar(0) 을 지정하는 것과 같음
  • Mat::zeros() 함수는Mat 클래스의 정적 멤버 함수이기 때문에 실제 코드에서 사용할 때 **Mat::을 붙여서 사용해야 함 🌟**
  • 반환값 MatExpr : OpenCV에서 행렬의 대수 연산을 표현하는 클래스, Mat클래스로 자동 형변환
  • ex) 0으로 초기화된 3 X 3 정수형 행렬 → Mat mat1 = Mat::zeros(3, 3, CV_32SC1); // 0's matrix

**Mat::ones()** : 모든 원소가 1으로 초기화 된 행렬

static MatExpr Mat::ones(int rows, int cols, int type);
static MatExpr Mat::ones(Size size, int type);

**Mat::eye()** : 단위 행렬 생성

static MatExpr Mat::eye(int rows, int cols, int type);
static MatExpr Mat::eye(Size size, int type);

ex ) Mat::ones()와 Mat::eye() 함수를 사용한 mat 객체 생성 예제

  • Mat mat2 = Mat::ones(3, 3, CV_32FC1); // 1's matrix
  • Mat mat3 = Mat::eye(3, 3, CV_32FC1); // identity matrix

기존에 이미 할당되어있는 메모리 공간의 데이터를 행렬 원소 값으로 사용

  • 외부 메모리 공간을 활용한 Mat 객체 생성
  • 외부 배열의 크기와 생성할 행렬 원소의 개수, 자료형이 같아야 함
Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP);
• data사용할 (외부) 행렬 데이터의 주소. 외부 데이터를 사용하여 Mat 객체를 생성할 경우, 생성자에서 원소 데이터 저장을 위한 메모리 공간을 동적으로 할당하지 않음
• step(외부) 행렬 데이터에서 한 행이 차지하는 바이트 수. 만약 외부 행렬 데이터의 각 행에 여분의 패딩 바이트(padding byte)가 존재한다면 명시적으로 지정해야 함. 만약 기본값 AUTO_STEP을 사용하면 패딩 바이트가 없다고 간주

기존에 이미 할당되어있는 메모리 공간의 데이터를 행렬 원소 값으로 사용

  • 외부 메모리 공간을 활용한 Mat 객체 생성
  • 외부 배열의 크기와 생성할 행렬 원소의 개수, 자료형이 같아야 함
Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP);
  • ex) 여섯 개의 원소를 갖는 float 자료형의 배열 data를 먼저 정의, 이 배열을 행렬 원소로 사용하는 Mat 객체 mat4 생성
    float data[] = { 1, 2, 3, 4, 5, 6 };
    Mat mat4(2, 3, CV_32FC1, data);

→ **Mat 객체의 원소 값과 외부 메모리 공간의 데이터 값이 상호 공유됨**

→ mat4 객체 생성 후 외부 메모리 공간의 값을 변경하면 amt 행렬의 원소 값도 같이 변경

→ 반대로, amt 행렬의 원소 값을 변경해도 외부 메모리 공간의 값도 변경
  • 동적 할당으로 만든 대용량 메모리도 Mat 클래스에서 참조 O → Mat 객체가 소멸될 때 자동 해제 X, 따라서 사용자가 직접 메모리 해제

**Mat_** 클래스를 사용한 객체 생성

  • Mat_ 클래스와 Mat 클래스는 상호 변환 가능
  • << 연산자와 콤마(,)를 이용해 간단하게 행렬 원소 값을 설정 가능
  • ex) << 연산자로 행렬 원소 지정, 이를 Mat 객체로 변환
    Mat_<float> mat5_(2, 3);
    mat5_ << 1, 2, 3, 4, 5, 6;
    Mat mat5 = mat5_;
    • Mat_ 클래스는 탬플릿 클래스 → 저장할 원소의 자료형 명시적 지정
    • << 연산자, 콤마(,)로 mat 행렬의 전체 여섯 개의 원소 값을 차례대로 지정
    • mat5_ 행렬을 복사 → Mat 클래스 타입 변수mat5 선언
    • 2 X 3 행렬, 타입(type) : CV_32FC1
    • Mat mat5 = (Mat_<float>(2, 3) << 1, 2, 3, 4, 5, 6); 로 생략 가능

**초기화 리스트**를 이용한 행렬 초기화 → 중괄호{} 사용

  • OpenCV 4.0부터 초기화 리스트를 이용한 행렬 초기화 방법 제공
  • Mat 클래스 또는 Mat_ 클래스의 생성자에 행렬 크기와 초깃값을 중괄호를 이용한 리스트 형태로 전달
  • Mat 객체의 타입을 명시적으로 지정하기 위해 Mat_ 클래스 형식으로 생성 후 Mat 타입으로 변경 하는 것이 좋음
  • ex) mat5 행렬과 같은 초깃값을 갖는 행렬 mat6을 초기화 리스트 방법으로 생성 Mat mat6 = Mat_<float>({2, 3}, { 1, 2, 3, 4, 5, 6 });

**Mat::create()** : 비어있는 Mat 객체 또는 이미 생성된 Mat 객체에 새로운 행렬 할당

void Mat::create(int rows, int cols, int type);
void Mat::create(Size size, int type);
  • Mat::create() 함수의 인자로 지정한 행렬 크기와 타입이 기존 행렬과 모두 같으면 Mat::create() 함수는 별다른 동작 없이 그대로 함수 종료
  • 반면, 새로 만들 행렬 크기 또는 타입이 기존 행렬과 다른 경우, 일단 기존 메모리 공간을 해제한 후 새로운 데이터 저장을 위한 메모리 공간을 할당
  • ex) mat4와 mat5에 새로운 크기와 타입의 행렬 할당
    mat4.create(256, 256, CV_8UC3);    // 256x256, uchar, 3-channels
    mat5.create(4, 4, CV_32FC1);       // 4x4, float, 1-channel

**= 연산자 재정의**, **Mat::setTo()** : create() 함수로 행렬 생성 후 행렬 전체 원소 값 초기화

  • = 연산자 재정의
    Mat& Mat::operator = (const Scalar& s);
    • s행렬 원소에 설정할 값
    • 반환값값이 설정된 Mat 객체의 참조

  • setTo() 함수 원형
    Mat& Mat::setTo(InputArray value, InputArray mask = noArray());
    • value행렬 원소에 설정할 값
    • mask마스크 행렬. 마스크 행렬의 원소가 0이 아닌 위치에서만 value 값이 설정
    행렬 전체 원소 값을 설정하려면 noArray() 또는 Mat()을 지정
    • 반환값Mat 객체의 참조
    → mask : 영상의 특정 영역에 대해서만 원소 값을 설정하고 싶을 때 사용 → mask 인자를 생략하거나 mask 인자에 noArray() 또는 Mat()을 지정하면 행렬 전체 원소를 value 값으로 설정
  • ex) = 연산자와 setTo() 함수를 이용한 Mat클래스 원소 값 초기화
    mat4 = Scalar(255, 0, 0);  // = 연산자, mat4 영상의 모든 픽셀 파란색으로 초기화
    mat5.setTo(1.f);  // setTo() -> 행렬의 모든 원소 값 1.f로 설정
  • 코드 3-7 Mat 객체 생성 [ch03/MatOp]
  void MatOp1()
{
    Mat img1;    // 빈 매트릭스

    Mat img2(480, 640, CV_8UC1);          // unsigned char, 1-channel
    Mat img3(480, 640, CV_8UC3);          // unsigned char, 3-channels
    Mat img4(Size(640, 480), CV_8UC3);    // Size(width, height)

    Mat img5(480, 640, CV_8UC1, Scalar(128));          // initial values, 128
    Mat img6(480, 640, CV_8UC3, Scalar(0, 0, 255));    // initial values, red

    Mat mat1 = Mat::zeros(3, 3, CV_32SC1);    // 0's matrix 1채널 행렬
    Mat mat2 = Mat::ones(3, 3, CV_32FC1);     // 1's matrix
    Mat mat3 = Mat::eye(3, 3, CV_32FC1);      // identity matrix

    float data[] = { 1, 2, 3, 4, 5, 6 };
    Mat mat4(2, 3, CV_32FC1, data); // 외부 메모리 배열 활용

    Mat mat5 = (Mat_<float>(2, 3) << 1, 2, 3, 4, 5, 6); 
    Mat mat6 = Mat_<uchar>({2, 3}, { 1, 2, 3, 4, 5, 6 }); 

    mat4.create(256, 256, CV_8UC3); // uchar, 3-channels
    mat5.create(4, 4, CV_32FC1);    // float, 1-channel

    mat4 = Scalar(255, 0, 0); 
    mat5.setTo(1.f);
}
profile
私はゲームと日本が好きなBackend Developer志望生のOguです🐤🐤

0개의 댓글