opencv(c++) RGB 값의 변경을 통해 Grayscale 표현

  • 최초 작성일: 2022년 1월 10일(월)

목차

[TOC]


목표

opencv를 사용할 때, 노이즈를 없애 연산처리 속도와 정확도를 향상하기 위해 Grayscaling을 많이 사용한다.

앞에서 설명했던, IMREAD_GRAYSCALE나 cvtColor() 함수로 Grayscaling 할수도 있지만, 이 두가지 방법은 약간의 차이를 보일 가능성이 있다.

그래서, 직접 이미지의 RGB 값을 변경해 Grayscale을 표현해보자.


실습

Grayscale은 컬러이미지에서 광도만을 표현한 색 채널을 말한다.

밝으면 흰색, 어두우면 검은색이고 0~255 사이의 값으로 표현된다. (0: 검은색, 1: 흰색)

컬러 -> 흑백 이미지 변환의 방법은 여러가지가 있겠지만, 코드를 직접 작성해서 결과를 확인해보자.



#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>

#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;


int main(int ac, char** av) {

	Mat img_color = imread("lion.png");
	Mat img_gray(img_color.rows, img_color.cols, CV_8UC1);

	for (int y = 0; y < img_color.rows; y++)
	{
		for (int x = 0; x < img_color.cols; x++)
		{
			int avg = (img_color.at<Vec3b>(y, x)[0] + img_color.at<Vec3b>(y, x)[1] + img_color.at<Vec3b>(y, x)[2]) / 3;
			img_gray.at<uchar>(y, x) = avg;
		}
	}

	imshow("img_gray", img_gray);
	waitKey(0);

	return 0;
}


결과 (RGB 값 변경 Grayscale)

image


imread() 및 cvtColor() 함수와 결과 비교

imread()를 통한 Grayscale

image

imread() vs RBB 값 변경 (차이)

image

이미지가 그냥 검정 화면처럼 보이지만 밝기를 높여 보면, 아주 미세한 차이를 확인할 수 있다. 위의 이미지는 imread() 함수를 통한 Grayscale과 RGB값을 임의로 바꿔주는 Grayscale 방법의 결과에 대한 차이를 확인할 수 있다.



cvtColor()를 통한 Grayscale

image


cvtColor() vs RGB 값 변경 (차이)

image

위의 이미지는 cvtColor() 함수를 통한 Grayscale과 RGB값을 임의로 바꿔주는 Grayscale 방법의 결과에 대한 차이를 확인할 수 있다.


(위의 결과 코드)

#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>

#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace cv;
using namespace std;


int main(int ac, char** av) {

	Mat img_color = imread("lion.png");

	Mat img_gray;
	Mat img_diff(img_color.rows, img_color.cols, CV_8UC1);

	cvtColor(img_color, img_gray, COLOR_BGR2GRAY);

	for (int y = 0; y < img_color.rows; y++) {
		for (int x = 0; x < img_color.cols; x++) {
			int avg = (img_color.at<Vec3b>(y, x)[0] + img_color.at<Vec3b>(y, x)[1] + img_color.at<Vec3b>(y, x)[2]) / 3;
			int diff = abs(img_gray.at<uchar>(y, x) - avg);   // 음수가 나오면 안되므로 abs 함수 추가 (음수가 되면 아주 높은 숫자가 된다) (abs함수를 뺀 결과도 코드 아래 첨부)

			img_diff.at<uchar>(y, x) = diff;
		}
	}
	imshow("img_diff", img_diff);

	waitKey(0);

	return 0;
}



아래의 이미지는 diff를 구할 때 abs(절대값처리)를 안해주어 음수가 나왔을 때 아주 아주 밝은 색으로 흰색이 나타나는 오류

image


데이터로 차이 확인

육안으로 봤을 땐 그렇게 차이 안 나 보이는데라는 생각을 할 수 있으니, 수치 상으로 얼마나 차이가 있는지 확인을 해보자. 너무 많아서 인덱스 가로x세로 200~300 개의 데이터만 추려서 출력하여 일부만 가져왔다.

image


(위의 결과 코드)

#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>

#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace cv;
using namespace std;


int main(int ac, char** av) {

	Mat img_color = imread("lion.png");
	Mat img_gray = imread("lion.png", IMREAD_GRAYSCALE);

	//Mat img_gray;
	Mat img_diff(img_color.rows, img_color.cols, CV_8UC1);

	//cvtColor(img_color, img_gray, COLOR_BGR2GRAY);
	int col = img_color.cols;
	int row = img_color.rows;


	for (int y = 0; y < img_color.rows; y++) {
		for (int x = 0; x < img_color.cols; x++) {
			int avg = (img_color.at<Vec3b>(y, x)[0] + img_color.at<Vec3b>(y, x)[1] + img_color.at<Vec3b>(y, x)[2]) / 3;
			int diff = abs(img_gray.at<uchar>(y, x) - avg);

			img_diff.at<uchar>(y, x) = diff;
		}
	}

	for (int y = 100; y < 200; y++) {
		for (int x = 100; x < 200; x++) {
			cout << int(img_diff.at<uchar>(y, x)) << " ";
		}
		cout << endl;
	}
	imshow("img_diff", img_diff); 

	waitKey(0);

	return 0;
}