10.1 컬러 영상 다루기
10.1.1 컬러 영상의 픽셀 값 참조
일반적으로는 RGB 색상 순서를 사용하지만 OpenCV의 경우 BGR(파랑, 초록, 빨강) 순서로 저장된 Mat 객체를 사용. 각 색상 성분은 0부터 255 사이의 값을 가질 수 있다.
void color_inverse()
{
Mat src = imread("butterfly.jpg", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst(src.rows, src.cols, src.type());
for (int j = 0; j < src.rows; j++) {
for (int i = 0; i < src.cols; i++) {
Vec3b& p1 = src.at<Vec3b>(j, i);
Vec3b& p2 = dst.at<Vec3b>(j, i);
p2[0] = 255 - p1[0]; // B
p2[1] = 255 - p1[1]; // G
p2[2] = 255 - p1[2]; // R
}
}
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
- 3행: butterfly.jpg 파일을 3채널 BGR 컬러 영상으로 불러와서 src에 저장
- 10행: 반전된 영상을 저장할 dst 영상을 생성. dst 영상의 모든 픽셀 값은 이후 for 반복문에서 설정할 것이므로 초깃값은 따로 지정하지 않음
- 14~15행: src와 dst 영상의 (i, j) 좌표 픽셀 값을 각각 p1과 p2 변수에 참조로 받아옴
- 17~19행: p1 픽셀의 세 개 색상 성분 값을 모두 반전시켜 p2 픽셀 값으로 설정
10.1.2
void cvtColor (InputArray src, OutputArray dst, int code, int dstCn = 0);
- src: 입력 영상. CV_8U, CV_16U, CV_32F 중 하나의 깊이를 사용해야 함
- dst: 결과 영상. src와 크기 및 깊이가 같다
- code: 색 공간 변환 코드. ColorConversionCodes 열거형 상수 중 하나를 지정
- dstCn : 결과 영상의 채널 수. 0이면 자동으로 결정
void color_grayscale()
{
Mat src = imread("butterfly.jpg");
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);
imshow("src", src);
imshow("dst", dst);
waitKey();
destroyAllWindows();
}
- 3행: imread() 함수의 두 번째 인자를 지정하지 않으면 기본적으로 3채널 BRG 컬러 영상 형식으로 불러온다
- 11행: 3채널 BRG 컬러 영상 src를 그레이스케일 영상으로 변환하여 dst에 저장
10.1.3 색상 채널 나누기
void split(const Mat& src, Mat* mvbegin);
void split(InputArray src, OutputArrayOfArray mv);
- src: 입력 다채널 행렬
- mvbegin: 분리된 1채널 행렬을 저장할 Mat 배열 주소. 영상 배열 개수는 src 영상 채널 수와 같아야 함
- mv: 분리된 1채널 행렬을 저장할 벡터
void merge(const Mat* mv, size_t count, OutputArray dst);
void merge(InputArrayOfArrays mv, OutputArray dst);
- mv: 1채널 행렬을 저장하고 있는 배열 또는 벡터. 모든 행렬은 크기와 깊이가 같아야 함
- count: (mv가 Mat 타입의 배열인 경우) Mat 배열의 크기
- dst: 출력 다채널 행렬
void color_split()
{
Mat src = imread("candies.png");
if (src.empty()) {
cerr << "Image load failed!" << endl;
return;
}
vector<Mat> bgr_planes;
split(src, bgr_planes);
imshow("src", src);
imshow("B_plane", bgr_planes[0]);
imshow("G_plane", bgr_planes[1]);
imshow("R_plane", bgr_planes[2]);
waitKey();
destroyAllWindows();
}
- 3행: condies.png 영상을 3채널 BGR 컬러 영상 형식으로 불러옴
- 10~11행: src 영상의 채널을 분할하여 bgr_planes 벡터에 저정. bgr_planes[0]에는 파란색 색상 평면, bgr_planes[1]에는 녹색 색상 평면, bgr_planes[2]에는 빨간색 색상 평면이 저장됨.
10.2 컬러 영상 처리 기법
10.2.1 컬러 히스토그램 평활화
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(void)
{
Mat src = imread("pepper.bmp", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
Mat src_ycrcb;
cvtColor(src, src_ycrcb, COLOR_BGR2YCrCb);
vector<Mat> ycrcb_planes;
split(src_ycrcb, ycrcb_planes);
equalizeHist(ycrcb_planes[0], ycrcb_planes[0]); // Y channel
Mat dst_ycrcb;
merge(ycrcb_planes, dst_ycrcb);
Mat dst;
cvtColor(dst_ycrcb, dst, COLOR_YCrCb2BGR);
imshow("src", src);
imshow("dst", dst);
waitKey(0);
return 0;
}
- 9행: pepper.bmp 영상을 3채널 BGR 영상으로 불러와서 src에 저장
- 16~17행: BGR 색 공간의 src 영상을 YCrCb 색 공간으로 변경하여 src_ycrcb에 저장
- 19~20행: src_ycrcb 영상의 채널을 분리하여 ycrcb_planes에 저장
- 22행: Y 성분에 해당하는 ycrcb_planes[0] 영상에 대해서만 히스토그램 평활화를 수행
- 24~25행: ycrcb_planes 벡터에 들어있는 세 영상을 합쳐서 dst_ycrcb 영상을 생성
- 27~28행: dst_ycrcb 영상의 색 공간을 BRG 색 공간으로 변환하여 dst에 저장
10.2.2 색상 범위 지정에 의한 영역 분할
void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
- src: 입력 영상
- lowerb: 하한 값. 주로 Mat 또는 Scalar 객체를 지정
- upperb: 상한 값. 주로 Mat 또는 Scalar 객체를 지정
- dst: 출력 마스크 영상. 입력 영상과 크기가 같고, 타입은 CV_8UC1
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int lower_hue = 40, upper_hue = 80;
Mat src, src_hsv, mask;
void on_hue_changed(int, void*);
int main(int argc, char* argv[])
{
src = imread("candies.png", IMREAD_COLOR);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
cvtColor(src, src_hsv, COLOR_BGR2HSV);
imshow("src", src);
namedWindow("mask");
createTrackbar("Lower Hue", "mask", &lower_hue, 179, on_hue_changed);
createTrackbar("Upper Hue", "mask", &upper_hue, 179, on_hue_changed);
on_hue_changed(0, 0);
waitKey(0);
return 0;
}
void on_hue_changed(int, void*)
{
Scalar lowerb(lower_hue, 100, 0);
Scalar upperb(upper_hue, 255, 255);
inRange(src_hsv, lowerb, upperb, mask);
imshow("mask", mask);
}
- 7행: 두 개의 트랙바 위치를 저장할 정수형 변수 lower_hue, upper_hue를 전역 변수로 선언
- 8행: main() 함수와 트랙바 콜백 함수 on_hue_changed() 함수에서 함께 사용할 Mat 객체를 전역 변수로 선언
- 14행: candies.png 파일을 불러와서 src 변수에 저장
- 21행: src 영상을 HSV 색 공간으로 변환하여 src_hsv에 저장
- 26~27행: 색상의 하한 값과 상한 값을 조절할 수 있는 두 개의 트랙바를 생성. 색상의 최댓값을 179로 설정. 두 트랙바의 콜백 함수를 모두 on_hue_change() 함수로 설정
- 28행: 프로그램이 처음 실행될 때 영상이 정상적으로 출력되도록 트랙바 콜백 함수를 강제로 호출
- 36~37행: 사용자가 지정한 색상의 하한 값과 상한 값을 이용하여 lowerb, upperb 객체를 생성. 채도의 범위느 ㄴ임이의 100부터 255로 설정. 명도의 영항은 무시하도록 범위를 0부터 255로 설정
- 38행: src_hsv 영상에서 HSV 색 성분 범위가 lowerb부터 upperb 사이인 위치의 픽셀만 흰색으로 설정한 mask 영상을 생성
10.2.3 히스토그램 역투영
void calcBackProject(cont Mat* images, int nimages, const int* channels,
InputArray hist, OutputArray backProeject, const float** ranges,
double scale = 1, bool uniform = true);
- images: 입력 영상의 배열 또는 입력 영상의 주소. 영상의 배열인 경우, 모든 영상의 크기와 깊이는 같아야 한다
- nimages: 입력 영상 개수
- channels: 역투영 계산 시 사용할 채널 번호 배열
- hist: 입력 히스토그램
- backProject: 출력 히스토그램 역투영 영상. 입력 영상과 같은 크기, 같은 깊이를 갖는 1채널 행렬
- ranges: 각 차원의 히스토그램 빈 범위를 나타내는 배열의 배열
- scales: 히스토그램 역투영 값에 추가적으로 곱할 값
- uniform: 히스토그램 빈의 간격이 균등한지를 나타내는 플래그
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
// Calculate CrCb histogram from a reference image
Mat ref, ref_ycrcb, mask;
ref = imread("ref.png", IMREAD_COLOR);
mask = imread("mask.bmp", IMREAD_GRAYSCALE);
cvtColor(ref, ref_ycrcb, COLOR_BGR2YCrCb);
Mat hist;
int channels[] = { 1, 2 };
int cr_bins = 128; int cb_bins = 128;
int histSize[] = { cr_bins, cb_bins };
float cr_range[] = { 0, 256 };
float cb_range[] = { 0, 256 };
const float* ranges[] = { cr_range, cb_range };
calcHist(&ref_ycrcb, 1, channels, mask, hist, 2, histSize, ranges);
// Apply histogram backprojection to an input image
Mat src, src_ycrcb;
src = imread("kids.png", IMREAD_COLOR);
cvtColor(src, src_ycrcb, COLOR_BGR2YCrCb);
Mat backproj;
calcBackProject(&src_ycrcb, 1, channels, hist, backproj, ranges, 1, true);
imshow("src", src);
imshow("backproj", backproj);
waitKey(0);
return 0;
}
- 12행: 피부색 히스토그램 정보를 추출할 기준 영상 ref.png 파일을 불러옴
- 13행: 기준 영상에서 피부색이 있는 위치를 흰색으로 표시한 마스크 영상 mask.bmp 파일을 불러옴
- 14행: 기준 영상을 YCrCb 색 공간으로 변환
- 16~24행: 기준 영상에서 피부색 영역의 CrCb 2차원 히스토그램을 계산하여 hist에 저장
- 28~30행: 입력 영상 kids.png 파일을 불러와 YCrCb 색 공간으로 변환
- 32~33행: 앞서 구한 히스토그램 hist 를 이용하여 입력 영상에서 히스토그램 역투영을 수행. 역투영 결과는 backproj에 저장
'3학년 > OpenCV' 카테고리의 다른 글
[OpenCV] 12장 레이블링과 외곽선 검출 (0) | 2023.07.02 |
---|---|
[OpenCV] 11장 이진화와 모폴로지 (0) | 2023.07.02 |
[OpenCV] 9장 에지 검출과 응용 (0) | 2023.07.01 |
[OpenCV] 8장 영상의 기하학적 변환 (0) | 2023.07.01 |
[OpenCV] 7장 필터 (0) | 2023.06.30 |