[OpenCV] Mat 클래스와 유용한 함수

zzwon1212·2023년 10월 26일
0

OpenCV

목록 보기
5/16
post-thumbnail

1. Mat 클래스

1.1. 개요

  • n차원 1채널 또는 다채널 행렬 표현을 위한 클래스

    • 실수/복소수 행렬, 그레이스케일/트루컬러 영상, 벡터 필드, 히스토그램, 텐서 등을 표현
  • 다양한 형태의 행렬 생성, 복사, 행렬 연산 기능을 제공

    • 행렬의 생성 시 행렬의 크기, 자료형과 채널 수(타입), 초기값 등을 지정할 수 있음
    • 복사 생성자& 대입 연산자는 얕은 복사 수행(참조 계수로 관리)
    • 깊은 복사는 Mat::copyTo() 또는 Mat::clone() 함수 사용
    • 다양한 사칙 연산에 대한 연산자 오버로딩과 std::cout 출력을 위한 << 연산자 오버로딩을 지원
  • 행렬의 원소(픽셀 값) 접근 방법을 제공

    사용 방법특징
    Mat::data메모리 연산이 잘못될 경우 프로그램이 비정상 종료될 수 있음
    Mat::at()좌표 지정이 직관적. 임의 좌표에 접근할 수 있음
    Mat::ptr()Mat::at()보다 빠르게 동작. 행 단위 연산을 수행할 때 유리함
    MatIterator 반복자좌표를 지정하지 않아서 안전. 성능은 느린 편
    • Mat::data 멤버 변수가 실제 픽셀 데이터 위치를 가리킴

      addr(Mi,j)=M.data+M.step[0]i+M.step[1]jaddr(M_{i, j}) = M.data + M.step[0] * i + M.step[1] * j
    • Mat::at<typename>(int y, int x) 또는 Mat::ptr<typename>(int y) 함수 사용을 권장

1.2. 필수 개념

1.2.1. 깊이(depth)

  • 행렬 원소가 사용하는 자료형 정보를 가리키는 매크로 상수
  • Mat::depth() 함수를 이용하여 참조
  • 형식: CV_<bit-depth>{U|S|F}
    #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	// short
    #define CV_32S  4	// int
    #define CV_32F  5	// float
    #define CV_64F  6	// double
    #define CV_16F  7	// float16_t

1.2.2. 채널(channel)

  • 원소 하나가 몇 개의 값으로 구성되어 있는가?
    • 그레이스케일 영상: 1개
    • 트루컬러 영상: 3개
  • Mat::channels() 함수를 이용하여 참조

1.2.3. 타입(type)

  • 행렬의 깊이와 채널 수를 한꺼번에 나타내는 매크로 상수
  • Mat::type() 함수를 이용하여 참조
  • 형식: CV_8UC1 8비트 unsigned char type을 사용하면서 채널은 1개인 그레이스케일 영상

2. Mat 관련 유용한 함수

2.1. 합

// 정의
Scalar sum(InputArray src);

// 예제 코드
uchar data[] = {1, 2, 3, 4, 5, 6};
Mat mat1(2, 3, CV_8UC1, data);

int sum1 = (int)sum(mat1)[0]; // 21
  • src: 입력 행렬. 1~4채널.
  • 반환값: 행렬 원소들의 합

2.2. 평균

// 정의
Scalar mean(InputArray src, InputArray mask = noArray());

// 예제 코드
Mat img_GRAY = imread("lenna.bmp", IMREAD_GRAYSCALE);
Mat img_COLOR = imread("lenna.bmp");

double mean_GRAY = mean(img_GRAY)[0]; // 124.0
Scalar mean_COLOR = mean(img_COLOR); // [0]: B, [1]: G, [2]: R, [3]: 0
  • mask: 마스크 영상
  • 반환값: 행렬의 평균값

2.3. 최솟값/최댓값

// 정의
void minMaxLoc(InputArray src, double* minVal, double* Maxval = 0,
               Point* minLoc = 0, Point* maxLoc = 0, InputArray mask = noArray());

// 예제 코드
Mat img = imread("lenna.bmp", IMREAD_GRAYSCALE);

double minv, maxv;
Point minLoc, maxLoc;
minMaxLoc(img, &minv, &maxv, &minLoc, &maxLoc); // 25, 245, [508, 71], [116, 273]
  • src: 입력 영상. 단일 채널.
  • minVal, maxVal: 최솟값/최댓값 변수 포인터. 필요 없으면 NULL 지정.
  • minLoc, maxLoc: 최솟값/최댓값 위치 변수 포인터. 필요 없으면 NULL 지정.
  • mask: 마스크 영상. mask 행렬 값이 0이 아닌 부분에서만 연산을 수행.

2.4. 자료형 변환

// 정의
void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0) const;

// 예제 코드
Mat img = imread("lenna.bmp", IMG_GRAYSCALE);

Mat fimg;
img.converTo(fimg, CV_32FC1);
m(x,y)=saturate_cast<rType>(α(this)(x,y)+βm(x, y) = saturate\_cast<rType>(\alpha(*this)(x, y) + \beta
  • rtype: 원하는 출력 행렬 타입
  • alpha: 추가적으로 곱할 값
  • beta: 추가적으로 더할 값

2.5. 정규화(원소값 범위 정규화)

// 정의
void normalize(InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
               int norm_type = NROM_L2, int dtype = -1, InputArray mask = noArray());

// 예제 코드
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);

Mat dst;
normalize(src, dst, 0, 255, NORM_MINMAX);
  • dst: 출력 행렬. src와 같은 크기.
  • alpha: (노름 정규화인 경우) 목표 노름(norm)값, (NORM_MINMAX인 경우) 최솟값
  • beta: (NORM_MINMAX인 경우) 최댓값
  • norm_type: 정규화 타입. NORM_INF, NORM_L1, NORM_L2, NORM_MINMAX 중 하나를 가짐. NORM_MINMAX를 지정할 경우, 출력 행렬 dst의 최솟값은 alpha, 최댓값은 beta가 되도록 설정함.
  • dtype: 출력 행렬의 타입
  • 아래는 예제 코드의 결과물이다. [25, 245]에 분포하던 픽셀들을 [0, 255]로 정규화한다. 따라서 어두운 부분은 더 어둡게, 밝은 부분은 더 밝게 표현된다.

2.6. 색 공간 변환

// 정의
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);

// 예제 코드
Mat src = imread("lenna.bmp");

Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);
  • code: 색 변환 코드
  • dstCn: 결과 영상의 채널 수. 0이면 자동으로 결정됨.
  • 예제 코드의 경우, imread에서 IMREAD_GRAYSCALE로 불러오는 것도 가능하다.

2.7. 채널 분리

// 정의
void split(const Mat& src, Mat* mvbegin);
void split(InputArray src, OutputArrayOfArrays mv);

// 예제 코드
Mat src = imread("lenna.bmp");

vector<Mat> planes;
split(src, planes);
  • src: (입력) 다채널 행렬
  • mvbegin: (출력) Mat 배열의 주소
  • mv: (출력) 행렬의 벡터. vector<Mat>
  • 아래는 예제 코드의 결과물이다. 트루컬러 영상이 B, G, R 3개의 영상으로 나뉘었다.

2.8. 채널 결합

// 정의
void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(InputArrayOfArrays mv, OutputArray dst);

// 예제 코드
Mat src = imread("lenna.bmp");

vector<Mat> planes;
split(src, planes);

swap(planes[0], planes[2]); // Blue와 Red를 서로 바꿔주기

Mat dst;
merge(planes, dst);
  • mv: (입력) 1채널 Mat 배열 또는 행렬의 벡터
  • count: (mvMat 타입의 배열인 경우) Mat 배열의 크기
  • dst: (출력) 다채널 행렬
  • 아래는 예제 코드의 결과물이다. 트루 컬러 영상을 B, G, R로 분리하고, B와 R을 swap한 뒤에 BGR을 결합하였다.

📙강의 - 강사 황선규

profile
JUST DO IT.

0개의 댓글