2020-05-12 수정됨
채널관련 기본 영상처리 함수
OpenCV
는 다음과 같은 기본 채널연산을 제공합니다.
- 채널 분리 (spilt)
- 채널 병합 (merge)
- 채널 혼합 (mix)
채널 분리
N채널 영상을 1채널 영상 N개로 분리합니다.
함수 정의
/**
* src를 1채널 단위로 분리한다.
*
* @param src 분리할 영상.
* @param dest 분리된 채널들이 저장될 배열.
*/
void spilt(const Mat &src, Mat dest[]);
예제
//! 테스트 3채널 영상.
Mat src = Mat(Size(2, 2), CV_8SC3, Scalar(0, 1, 2));
/*
* [(0, 1, 2), (0, 1, 2);
* (0, 1, 2), (0, 1, 2)]
*/
//! 각 채널을 분리한다.
Mat dest[3];
split(src, dest);
/*
* dest[0] :
* [0, 0;
* 0, 0]
*/
/*
* dest[1] :
* [1, 1;
* 1, 1]
*/
/*
* dest[2] :
* [2, 2;
* 2, 2]
*/
채널 병합
1채널 영상 N개를 N채널 영상 1개로 병합합니다.
함수 정의 1
/**
* 입력영상들을 단일영상으로 만든다.
*
* @param src 입력영상의 벡터
* @param dest 출력영상
*/
void merge(vector<Mat> src, Mat dest);
함수 정의 2
/**
* 입력영상들을 단일영상으로 만든다.
*
* @param src 입력영상의 배열
* @param N 입력영상의 개수
* @param dest 출력영상
*/
void merge(Mat src[], int N, Mat dest);
벡터를 이용한 구현은 모던하지만,
배열과 길이를 이용한 기법은 C++에서 여전히 유용하게 사용됩니다.
예제
//! 테스트 1채널 영상들.
Mat src[3];
for(int i=0; i<3; i++){
src[i] = Mat(Size(2, 2), CV_8UC1, Scalar(i));
}
/*
* src[0] :
* [0, 0;
* 0, 0]
*/
/*
* src[1] :
* [1, 1;
* 1, 1]
*/
/*
* src[2] :
* [2, 2;
* 2, 2]
*/
//! 1채널 영상 3개를 병합한다.
Mat dest;
merge(src, 3, dest);
/*
* dest :
* [(0, 1, 2), (0, 1, 2);
* (0, 1, 2), (0, 1, 2)]
*/
채널 혼합
단일영상 혼합
먼저 혼합순서
가 무엇인지 알아야 합니다.
예제를 보면서 살펴보겠습니다.
예제 1
BGR
을 RGB
로 바꾸는 혼합순서는 다음과 같습니다.
- input[0] -> output[2] (0 -> 2)
- input[1] -> output[1] (1 -> 1)
- input[2] -> output[0] (2 -> 0) 이므로,
int bgr_to_rgb_order[] = {
0, 2, // 0 -> 2
1, 1, // 1 -> 1
2, 0 // 2 -> 0
};
예제 2
BGR
을 RRR
로 바꾸는 혼합순서는 다음과 같습니다.
int fill_to_red_order[] = {
2, 0, // 2 -> 0
2, 1, // 2 -> 1
2, 2 // 2 -> 2
};
다중영상 혼합
이번에는 다중영상에서의 혼합순서도 알아보겠습니다.
간단하게 요약하면 모든 영상들의 채널을 일렬로 나열
하는 것이 포인트입니다.
이번에도 예시를 보면서 생각해보겠습니다.
//! 입력영상의 배열.
Size size = Size(2, 2);
Mat img1 = Mat(size, CV_8UC3, Scalar(0, 1, 2));
Mat img2 = Mat(size, CV_8UC3, Scalar(3, 4, 5));
Mat input[] = {img1, img2};
//! 출력영상의 배열.
Mat r = Mat(size, CV_8UC2);
Mat g = Mat(size, CV_8UC2);
Mat b = Mat(size, CV_8UC2);
Mat output[] = {r, g, b};
위의 입력배열과 출력배열의 채널들을 나열하면,
다음과 같은 형태가 완성됩니다.
여기서 입력영상은 BGRBGR
으로 생각할 수 있고,
출력영상을 BBGGRR
로 만들기 위한 혼합순서는 다음과 같이 생각할 수 있습니다.
- input[0] -> output[0]
- input[1] -> output[2]
- input[2] -> output[4]
- input[3] -> output[1]
- input[4] -> output[3]
- input[5] -> output[5]
int mix_order[] = {
0, 0,
1, 2,
2, 4,
3, 1,
4, 3,
5, 5
};
함수 정의 1
/**
* 입력영상의 채널순서를 변경하여 출력영상으로 내보낸다.
*
* @param src 입력영상의 벡터
* @param dest 출력영상의 벡터
* @param order 혼합순서쌍의 벡터
* @since OpenCV 4.x
*/
void mixChannels(vector<mat> src, vector<mat> dest, vector<int> order);
함수 정의 2
/**
* 입력영상 N개의 채널순서를 변경하여,
* 출력영상 M개로 내보낸다.
*
* @param src 입력영상의 배열
* @param src_n 입력의 수
* @param dest 출력영상의 배열
* @param dest_n 출력의 수
* @param pairs 혼합순서쌍의 배열
* @param pairs_n 혼합순서쌍의 개수
*/
void mixChannels(
Mat src[], size_t src_n,
Mat dest[], size_t dest_n,
int pairs[], size_t pairs_n);
STL 벡터는 깔끔하지만, 오래된 OpenCV에는 이 구현이 없으므로,
C++ 관용구인 포인터와 길이를 같이 넘겨주는 기법도 기억해두면 좋습니다.
예제
2개의 BGRA
영상을, 아래처럼 4개의 영상으로 나눠보겠습니다.
- 첫 번째 영상의 RGB 영상.
- 첫 번째 영상의 Alpha 영상.
- 두 번째 영상의 RGB 영상.
- 두 번째 영상의 Alpha 영상.
//! 입력영상의 배열.
Size size = Size(2, 2);
Mat a = Mat(size, CV_8UC4, Scalar(0, 1, 2, 3));
Mat b = Mat(size, CV_8UC4, Scalar(3, 4, 5, 6));
Mat input[] = {a, b};
//! 출력영상의 배열.
Mat a_rgb = Mat(size, CV_8UC3);
Mat a_a = Mat(size, CV_8UC1);
Mat b_rgb = Mat(size, CV_8UC3);
Mat b_a = Mat(size, CV_8UC1);
Mat output[] = {a_rgb, a_a, b_rgb, b_a};
//! 혼합순서
int order[] = {
0, 2,
1, 1,
2, 0,
3, 3,
4, 6,
5, 5,
6, 4,
7, 7
};
mixChannels(input, 2, output, 4, order, 8);
'# 미사용 > OpenCV' 카테고리의 다른 글
[OpenCV] 행렬의 비트연산 (0) | 2019.11.01 |
---|---|
[OpenCV] 행렬의 산술연산 (0) | 2019.10.31 |
[OpenCV] 행렬의 대칭, 전치, 반복 (0) | 2019.10.30 |
[OpenCV] 기본도형 그리기 (0) | 2019.10.29 |
[OpenCV] 윈도우 및 이벤트 관리 (0) | 2019.10.29 |