본문 바로가기

Computer Vision by OpenCV

Image processing: Brightness Contrast 밝기 대비

반응형


ㅇ Brightness(밝기)와 Contrast조절

ㅇ 영상처리 기술들 중에서 간단하면서도 직관적인 것이 brightness와 contrast 조절입니다.
  - 우선 둘 중에 직관적으로 이해하기 쉬운 brightness부터 살펴 보겠습니다.

ㅇ Brightness는 영상을 밝기를 뜻합니다.
  - 밝기를 조절하기 위해서는 픽셀의 intensity를 바꾸면 됩니다.
  - Intensity값을 증가시키면, 영상이 밝아집니다.
  - 반대로 감소시키면, 어두워집니다.

ㅇ Contrast는 영상에서 밝은 부분과 어두운 부분의 차이를 의미합니다.
  - 방금 설명했던 brightness보다는 직관적으로 이해가 하기가 쉽지 않을 겁니다.
  - 예를 들어 보겠습니다.
  - 이미지 안의 대부분 픽셀들의 intensity가 비슷하다면,
  - 어떤 물체가 있는지 쉽게 알 수가 없습니다.
  - 이런 경우가 contrast가 낮은 것입니다.
  - 반대로, 이것이 높다는 것은 픽셀들간의 Intensity 차이가 많이 난다는 겁니다.
  - 이 경우, 물체의 모양이나 윤곽을 한 눈에 알아볼 수 있을 겁니다.
  - 해가 비치는 부분과 그림자 진 부분을 쉽게 구분할 수 있는 것 처럼 말입니다.

ㅇ 그러면, brightness 조절은 어떻게 할까요?
  - 쉽습니다. 모든 픽셀들의 intensity에 모두 같은 값만큼 더하거나 빼면 됩니다.
  - 더하면 이미지가 환해져서 brightness가 증가됩니다.
  - 빼는 것은 더하는 것의 반대 경우이구요.

ㅇ Brightness를 조절한 이미지의 예를 보겠습니다.
  - 우선 아래 그림은 조절 전의 이미지입니다.
  - 이미지가 두 구역으로 나뉘어져 있고, 왼쪽 편 픽셀들의 intensity가 오른편보다 큰것을 알 수 있습니다.

- 입력이미지


  - Intensity에 같은 양수를 더해 brightness를 증가시킨 결과입니다.
  - 왼편은 거의 흰색에 가까울 정도로 밝아졌고,
  - 오른편도 그만큼 밝아졌습니다.
  - 이렇듯 brightness 조절은 쉽습니다.
- brightness를 증가한 경우
- 좌측과 우측 모두 환해진 것을 알 수 있다.


ㅇ Contrast 증가의 예를 살펴보겠습니다.
  - 동일한 입력이미지를 사용했을 때, 
  - 왼편은 흰색으로 매우 밝아졌지만,
  - 오른편은 별 차이가 없습니다.
  - 대신 왼쪽과 오른쪽의 intensity 차이가 분명해져서,  선명해졌습니다.

- contrast를 증가한 경우,
- 좌측은 환해졌지만, 오른쪽은 원래보다 더 어두워졌다.
- 밝았던 부분은 더 밝아지고, 
- 어두웠던 부분은 더 어두워지기 때문에,
- 두 부분간의 대비 (contrast)가 증가했다.


ㅇ Contrast 증가의 원리
  - 이것은 밝은 부분과 어두운 부분의 차이를 크게 하는 것을 목적으로 하여,
  - 핵심은 곱하기입니다.
  - 즉, intensity에 값을 곱하는 겁니다.
  - 왜 이러한 곱셈이 contrast를 증가시키는지 알아보겠습니다.
  - 예를 들어, 두 개의 픽셀 A, B가 있고, 
  - 각각의 intensity A = 100, B = 50 라고 하겠습니다.
  - Contrast조절을 위해 두 픽셀에 같은 1.5를 곱한다고 하면
  - A = 150, B= 75이 됩니다.
  - 곱셈에 의해 A는 50만큼 증가하였고, B는 25만큼 증가하였습니다.
  - 이로 인해 밝은 부분인 A가 B보다 더 환해졌기 때문에, A와 B간의 차이가 증가하여 contrast가 증가됩니다.
  -자세히 살펴보면, 조절전에는 두 픽셀간의 intensity차이 (A - B)가 50 = (100- 50)이었다면,
  - 조절후에는 75로 1.5배 만큼 늘어났습니다.


ㅇ 실제 이미지를 이용해서 brightness와 contrast 조절 실험을 진행해 보겠습니다.
  - 입력이미지는 아래와 같습니다.
- 도시의 야경을 gray로 촬영한 입력이미지 


  - Brightness를 증가시켜보겠습니다.
- Brightness를 증가시키면
- 이미지가 전체적으로 밝아진다.
- 이는 모든 픽셀의 intensity값이 증가했기 때문입니다.


  - 위의 실험에서 조절 전후 이미지의 히스토그램이 어떻게 변하는지 살펴보겠습니다.
  - 이것을 보면, brightness 조절이 어떤 역할을 하는지 보다 정확히 알 수 있습니다.
- 아래 그림에서
- 1번 히스토그램은 입력이미지의 히스토그램이고,
- 2번은 brightness 증가 후의 것입니다.
- 봉우리가 오른쪽으로 이동한 것이 관찰되는데,
- 픽셀들의 intensity가 전반적으로 증가했기 때문입니다.


  - 이번에는 contrast를 증가시켜보겠습니다.
- Contrast가 증가되면,
- 어두웠던 부분은 더 어두워지고,
- 밝았던 부분은 더 밝아지면서
- 두 부분이 좀 더 극명하게 대비되는 효과를 볼 수 있습니다.


  - Contrast 변화가 히스토그램에 어떠한 영향을 끼치는지 살펴보겠습니다.
- 아래 히스토그램들은
- 1번은 입력이미지, 2번은 contrast 증가 후의 것입니다.
- 2번에서 어두운 픽셀의 개수가 크게 증가하였다는 것을 볼 수 있다.
- 밝은 픽셀의 수는 별로 증가하지 않았는데,
- 이는 contrast 적용공식의 작동 방식 때문입니다.
- 여기에 대해서 좀 더 자세히 알아보겠습니다.


ㅇ Contrast와 Brightness를 조절하는 공식
  - 위의 예에서 보았듯이,
  - 조절하는 공식의 기본 아이디어는 
  - brightness의 경우는 픽셀 intensity를 전체적으로 증가 혹은 감소하는 것이고,
  - contrast는 intensity에 비례하여 값을 변화시키는 것입니다.
  - 이것을 수학공식으로 표현하면 다음과 같습니다.

- x가 픽셀의 intensity라고 할 때
- 1) contrast를 조절하기 위해서는 적절한 alpha를 계산하여 곱한다.
- 2) brightness를 조절하기 위해서는 beta를 더한다.
- 그렇다면, alpha와 beta는 어떻게 계산하는 것일까요?


ㅇ alpha와 beta의 결정
  - 우선 contrast와 brightness는 둘 다 1 ~ 200까지 변동가능하다고 가정하겠습니다.
  - 그리고 100은 입력이미지 상태그대로를 의미한다고 하겠습니다. 
  - 따라서, < 100 이면, contrast와 brightness가 감소되는 것을 의미하고,
  - > 100이면, 증가하는 것을 의미합니다.
  - 아래 코드는 alpha (=a)와 beta (=b)를 결정하는 소스코드입니다. 


ㅇ Brightness 조절에 따른 alpha와 beta값의 변화
  - brightness를 1부터 200까지 조절할 때, alpha와 beta가 어떻게 변하는지 그래프를 그려보겠습니다.
  - (brightness == 100)은 조절하지 않음.
  - (brightness > 100)은 이미지를 환하게
  - (brightness < 100)은 이미지를 어둡게
  - 아래 그래프에서 x축은 brightness (1 ~ 200)을 나타내고,
  - y축은 alpha와 beta값입니다.

- brightness 조절은 alpha값을 변화시키지는 않습니다.
- alpha = 1을 유지합니다.



- beta값은 brightness에 정비례하여 증가 혹은 감소합니다.


ㅇ Contrast 변화에 따른 alpha와 beta의 조절
  - 이번에는 brightness는 100으로 고정시키고 ( 변경시키지 않는다는 뜻입니다.),
  - contrast를 1 ~ 200까지 변화시키면서, alpha와 beta가 어떻게 변하는지 보겠습니다.
  - 실제 그래프에서는 1 ~ 180까지만 표시했습니다.
  - 이번에도 contrast = 100은 변화가 없다는 것입니다.
  - x축은 contrast의 값, y축은 alpah와 beta값입니다.

- Contrast가 증가할 수록
- alpha값이 빠르게 증가합니다.


- beta값은 contrast와는 반대로 움직입니다.
- 이것은 alpha값에 의한 변화를 보상하기 위해서입니다.
- 예를 들어, contrast > 100인 경우,
- alpha값이 1보다 커져서, intensity에 곱해서 나오는 결과도 커집니다.
- 따라서, beta는 음수가 되어 이 결과를 조금 작게 할 필요가 있습니다.
- contrast < 100인 경우는 반대로 이해하면 되겠습니다.


ㅇ 위그래프를 생성해내기 위한 MATLAB 소스코드

ㅇ 구현
  - Brightness와 contrast 이미지 처리기술을 OpenCV를 이용해서 구현해 보겠습니다.
  - 앞서 설명했듯이 픽셀 intensity에 alpha를 곱하고, beta를 더하는 연산이 필요합니다.
  - 이러한 연산을 편하게 할 수 있는 함수를 OpenCV가 제공하는데,
  - Mat 클래스의 메소드인 convertTo( )입니다.

- convertTo 메소드는, 각 픽셀에 곱할 alpha와 더할 beta를 인수로 받습니다.
- 인수 m은 계산결과를 담은 Mat 객체입니다.
- 이 함수를 이용하면 위에서 설명한 조절을 쉽게 구현할 수 있습니다.



ㅇ Brightness와 Contrast 이미지 프로세싱 C++ 구현 코드 
  - 슬라이드바 (Slide bar)를 이용해서 brightness와 contrast를 조절하는 프로그램을 짜 보았습니다.
  - 각각의 조절에 따른 이미지 변화를 관찰할 수 있는 편리한 프로그램입니다. 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

//
// 슬라이드 바의 위치에 해당하는 값
// 최소 0에서 최대 200까지 움직인다.
//
int init_brightness = 100;
int init_contrast = 100;

Mat image;

const char* keys = { "{@imageName1| img_osaka_night.jpg |input image file} \\
{@imageName2| fruits.jpg|input image file} \\
{N | 1.0 | this is double value} \\
{help h ? | | this is help}" };


void updateBrightnessContrast(int, void*)
{
	int histSize = 255;
	int var_brightness = init_brightness - 100;
	int var_contrast = init_contrast - 100;

	double a, b;
	if (var_contrast > 0)
	{
		double delta = 127.0*var_contrast / 100;
		a = 255.0 / (255.0 - delta * 2);
		b = a*(var_brightness - delta);
	}
	else
	{
		double delta = -128.0*var_contrast / 100;
		a = (256.0 - delta * 2) / 255.0;
		b = a*var_brightness + delta;
	}

	cout << "a: " << a << " b: " << b << endl;

	Mat dst, hist;
	//
	// image의 각 픽셀값을 변경하여, dst를 만들어 화면에 표시
	// pixel =  a*pixel + b
	//
	image.convertTo(dst, CV_8U, a, b);
	imshow("image", dst);

	// dst의 히스토그램을 계산한다.
	calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, 0);

	Mat histImage = Mat::ones(200, 320, CV_8U) * 255;  // 320 * 200의 흰색이미지를 만든다.

	normalize(hist, hist, 0, histImage.rows, CV_MINMAX, CV_32F);
	
	int binW = cvRound((double)histImage.cols / histSize);

	for (int i = 0; i < histSize; i++)
	{
		Point leftUp = Point(i*binW, histImage.rows);
		Point rightDown = Point((i + 1)*binW, histImage.rows - cvRound(hist.at<float>(i)));
		rectangle(histImage, leftUp, rightDown, Scalar::all(0), -1, 8, 0);
		imshow("histogram", histImage);
	}
}


/*
   read in an image as a gray
*/
int main(int argc, char** argv)
{
	CommandLineParser parser(argc, argv, String(keys));
	parser.about("This is test program for commandlineparser of opencv");
	string inputImage1 = parser.get<string>("@imageName1");

	image = imread(inputImage1, IMREAD_GRAYSCALE);
	if (image.empty() == true)
	{
		cout << "Unable to read the image " << inputImage1 << "." << endl;
		return -1;
	}
	namedWindow("image", WINDOW_KEEPRATIO);
	namedWindow("histogram", WINDOW_KEEPRATIO);

	createTrackbar("brightness", "image", &init_brightness, 200, updateBrightnessContrast);
	createTrackbar("contrast", "image", &init_contrast, 200, updateBrightnessContrast);

	// 이 함수를 호출해야
	// 이미지를 화면에 표시할 수 있다.
	//
	updateBrightnessContrast(0, 0);

	waitKey();
	return 0;
}














반응형