1. OpenCV 에서 컬러영상 다루기
1) R,G,B 색성분 각 256단계 표현/.
2) CV_8UC3 타입 //그레이는 CV_8UC1
3) BGR 순서를 Opencv에선 기본으로 사용
2. 컬러 영상의 픽셀값 참조
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp");
if (src.empty()) {
cerr << "Image laod failed!" << endl;
return -1;
}
Mat dst = 255 - src;
imshow("src", src);
imshow("dst", dst);
waitKey();
}

컬러이미지 반전시 우측같이 비정상적인 결과영상이 나왔다.
** 255 는 자동으로 Scalar 형으로 변환해서 연산이 된다
Scalar 클래스는 내부에 4개의 요소가 있다. 즉 (오버로딩 연산자 - 보면 확인 가능)
Scalar(255, 0, 0 , 0 ) - src; 한것과 동일하다.
4번째 채널은 무시하고, 2,3 채널은 G, R 이 0보다 작아짐에따라 포화연산으로 0으로 처리됨
이에 B만 형성이 되어 파란 화면이 나온다.
해결법 Scalar(255,255,255)
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp");
if (src.empty()) {
cerr << "Image laod failed!" << endl;
return -1;
}
Mat dst = Scalar(255,255,255) - src;
imshow("src", src);
imshow("dst", dst);
waitKey();
}

각 픽셀을 직접 접근해서 반전시켜보자
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp");
if (src.empty()) {
cerr << "Image laod failed!" << endl;
return -1;
}
Mat dst(src.rows, src.cols, src.type());
//Mat dst(src.rows, src.cols, CV_8UC3);
for (int y = 0; y < src.rows; ++y) {
for (int x = 0; x < src.cols; ++x) {
//src.at<uchar>(y, x); // gray scale 다룰 시 접근 법
// 컬러영상 픽셀 접근법
Vec3b& p1 = src.at<Vec3b>(y, x); // 참조를 사용한 이유. p1로 사용 시 복사본으로 할당한 영상을 바꾸는 용도로 사용할 수 없다.
Vec3b& p2 = dst.at<Vec3b>(y, x); // 이에 참조를 사용함으로써 얕은복사와 같이 p1, p2가 변환되면 src, dst 도 변환되게 만들어준다.,
//& 가 효율적.
// p1을 바꾸지 않기에 const 사용하는게 좋긴하나 생략
p2[2] = 255 - p1[2]; // R G B 반전
p2[1] = 255 - p1[1];
p2[0] = 255 - p1[0];
}
}
imshow("src", src);
imshow("dst", dst);
waitKey();
}
3줄을 한 줄로
for (int y = 0; y < src.rows; ++y) {
for (int x = 0; x < src.cols; ++x) {
Vec3b& p1 = src.at<Vec3b>(y, x); // 참조를 사용한 이유. p1로 사용 시 복사본으로 할당한 영상을 바꾸는 용도로 사용할 수 없다.
Vec3b& p2 = dst.at<Vec3b>(y, x); // 이에 참조를 사용함으로써 얕은복사와 같이 p1, p2가 변환되면 src, dst 도 변환되게 만들어준다.,
p2 = Vec3b(255, 255, 255) - p1;
}
}
이 한줄로도 커버 가능
for (int y = 0; y < src.rows; ++y) {
for (int x = 0; x < src.cols; ++x) {
dst.at<Vec3b>(y, x) = Vec3b(255, 255, 255) - src.at<Vec3b>(y, x);
}
}
3. 컬러영상을 그레이스케일 영상으로 변환
Y = 0.299R + 0.587G + 0.114B // Y: GrayScale 밝기 값
3 : 6 : 1 비율을 따름.
장점: 데이터 저장용량 감소(3Byte -> 1Byte), 연산 처리 속도향상
단점: 색상 정보 손실.
#include <iostream>
#include "opencv2/opencv.hpp"
#include<vector>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp",IMREAD_COLOR);
if (src.empty()) {
cerr << "Image laod failed!" << endl;
return -1;
}
Mat dst(src.rows, src.cols, CV_8UC1);
for (int y = 0; y < src.rows; y++) {
for (int x = 0; x < src.cols; x++) {
Vec3b& p1 = src.at<Vec3b>(y, x);
uchar b = p1[0];
uchar g = p1[1];
uchar r = p1[2];
uchar gray = (uchar)(0.299 * r + 0.587 * g + 0.114 * b + 0.5); // 0.5는 반올림 기능. 해도 안해도 그만
dst.at<uchar>(y, x) = gray;
}
}
imshow("src", src);
imshow("dst", dst);
waitKey();
}
#define RGB2GRAY(r, g, b) ((4899*(r) + 9617*(g) + 1868*(b)) >> 14 ) // >> 14 : 2의 14승으로 나눈다는 의미.
for (int y = 0; y < src.rows; y++) {
for (int x = 0; x < src.cols; x++) {
Vec3b& p1 = src.at<Vec3b>(y, x);
uchar b = p1[0];
uchar g = p1[1];
uchar r = p1[2];
//uchar gray = RGB2GRAY(r, g, b);
dst.at<uchar>(y,x) = RGB2GRAY(r, g, b);
}
}
define 하여 이처럼 gray 변환 식 가능.
그러나, 아래 코드는 육안으로 그레이색이나,. 그레이스케일 변환 방법이 아니다. 비율을 1/3 으로 나눠주었기에.
uchar gray = (r + g + b) / 3; 엄밀히 말하여 이 코드는 그레이스케일 변환 방법이 아니다.

opencv 함수 cvtColor 사용해서 gray색 변환
#include <iostream>
#include "opencv2/opencv.hpp"
#include<vector>
using namespace std;
using namespace cv;
int main()
{
Mat src = imread("lenna.bmp",IMREAD_COLOR);
if (src.empty()) {
cerr << "Image laod failed!" << endl;
return -1;
}
#if 1
Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);
#else
Mat dst(src.rows, src.cols, CV_8UC1);
for (int y = 0; y < src.rows; y++) {
for (int x = 0; x < src.cols; x++) {
Vec3b& p1 = src.at<Vec3b>(y, x);
uchar b = p1[0];
uchar g = p1[1];
uchar r = p1[2];
dst.at<uchar>(y,x) = RGB2GRAY(r, g, b);
}
}
#endif
imshow("src", src);
imshow("dst", dst);
waitKey();
}