ㅇ 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;
} |