본문 목표
이미지의 Histogram 정보를 통해서 이미지의 밝기를 효과적으로 조절할 수 있다.
OpenCV 에서도 해당 기능을 지원하는데, 이를 적용해보도록 한다.
키워드 : equalizeHist, Histogram equalization, 히스토그램 equalizeHist
히스토그램 - 원리 이해
히스토그램은 이미지의 밝기 값이 0~255 까지 있을 때,
픽셀들이 얼마나 그 값들을 갖고 있는지 나타내주는 그래프 이다.
예를 들면, 위와 같이 a 라는 이미지의 픽셀들 값이 행렬처럼 존재한다고 하면
오른쪽 그래프처럼 10의 값을 갖고 있는 픽셀 6개, 20의 값을 갖고 있는 픽셀 4개, 50의 값을 갖고있는 픽셀 7개, 90의 값을 갖고있는 픽셀 3개 로 나타낼 수 있다.
이런 히스토그램을 이미지에 적용한다면 다음과 같은 결과를 볼 수 있다.
왼쪽 사진의 히스토그램이 오른쪽 그래프이다.
한눈에 봐도 가운데 값(60~140)에 픽셀들의 값이 쏠려있는 것을 확인할 수 있다.
사람눈으로 봐도 왼쪽 사진은 흐려서 보기 좋지 못한 사진이라고 할 수 있다.
당연히 이런 사진은 컴퓨터에서 연산하기에도 좋지 않은 사진이다.
이러한 사진을 효과적으로 밝기를 조절할 수 있는데,
우리는 이 방식을 Histogram equalization 이라고 한다.
가운데 쏠려있는 밝기 정보를 골고루 분산시켜 주는 것이다.
결과부터 보자면 위와 같이 히스토그램 정보를 통해서 균일하게 펼쳐주었음을 확인할 수 있다.
확실히 전의 사진보다 뚜렷해졌음을 확인할 수 있다.
즉, 히스토그램 정보를 통해서 균일하게 밝기 값을 효과적으로 조절할 수 있는 것이다.
사칙연산만으로는 위와같은 결과를 얻기는 분명 힘들 것이므로, 효과적이라 할 수 있다.
위의 사진들도 마찬가지다.
어두운 상황의 사진을 보면 히스토그램 정보가 어두운 값에 몰려있는데,
이를 균일하게 펴주면서 아래와 같이 뚜렷한 결과물을 얻을 수 있게 되는 것이다.
알아볼 함수 원형
- 히스토그램 계산 ( calcHist )
...
MatND histogram;
const int* channel_numbers = { 0 };
float channel_range[] = { 0.0, 255.0 };
const float* channel_ranges = channel_range;
int number_bins = 255;
calcHist(&img_1, 1,channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);
...
https://swprog.tistory.com/entry/OpenCV-histogram
자세한 사용 방법은 위의 블로그에서 친절하게 다뤄주고 있으니, 참고하면 좋을것 같다.
calcHist( ) 함수는 이미지의 히스토그램 정보를 계산하는 역할을 한다.
다만 이 결과값을 확인하기가 까다로우니 아래의 예제코드를 참고하는 것이 정신건강에 이로울 것이다.
히스토그램 분석 코드 테스트 결과
- CODE
#include <opencv2/opencv.hpp>
//#include <iostream>
using namespace cv;
using namespace std;
int main(int ac, char** av) {
Mat img_1 = imread("Lenna.png",0); //이미지를 grayscale로 불러옴
Mat img_2 = img_1 * 2;
Mat img_3 = img_1 / 2;
Mat img_hist;
MatND histogram;
const int* channel_numbers = { 0 };
float channel_range[] = { 0.0, 255.0 };
const float* channel_ranges = channel_range;
int number_bins = 255;
calcHist(&img_1, 1,channel_numbers, Mat(), histogram, 1, &number_bins, &channel_ranges);
// plot the histogram
int hist_w = img_1.cols;
int hist_h = img_1.rows;
int bin_w = cvRound((double)hist_w / number_bins);
Mat hist_img(hist_h, hist_w, CV_8UC1, Scalar::all(0));
normalize(histogram, histogram, 0, hist_img.rows, NORM_MINMAX, -1, Mat());
for (int i = 1; i < number_bins; i++)
{
line(hist_img, Point(bin_w * (i - 1), hist_h - cvRound(histogram.at<float>(i - 1))), Point(bin_w * (i), hist_h - cvRound(histogram.at<float>(i))), Scalar(255, 0, 0), 1, 8, 0);
}
imshow("Origianl",img_1);
imshow("Histogram", hist_img);
//imshow("original", img_1);
//imshow("img_mul", img_2);
//imshow("img_div", img_3);
waitKey(0);
return 0;
}
- RESULT
위의 Lenna 사진에 대한 히스토그램 정보를 그래프로 확인 가능하다.
비교적 Lenna 이미지는 균일한 히스토그램 분포를 갖고 있는 것으로 판단된다.
한눈에 봐도 인물이 뚜렷하게 나와있어서, 이는 영상처리에 사용되어도 큰 문제 없을듯 싶다.
알아볼 함수 원형
- 히스토그램 균일화 ( equalizeHist )
...
Mat img_1 = imread("Lenna.png", 0); //이미지를 grayscale로 불러옴
Mat hist_img;
equalizeHist(img_1, hist_img);
...
equalizeHist(Input Array, Output Array) : Input Array(입력 이미지)의 히스토그램 정보를 통해서 균일화를 해준 후 해당 정보를 Output Array(결과 이미지)에 저장한다.
해당 함수는 사용하기가 정말 쉽다.
그냥 입력 이미지와 연산 처리 된 결과를 저장한 결과 이미지 변수만 필요하다.
자동으로 균일하게 히스토그램을 분포시켜준다.
히스토그램 균일화 코드 테스트 결과
- CODE
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int ac, char** av) {
Mat img_1 = imread("Lenna.png", 0); //이미지를 grayscale로 불러옴
Mat hist_img;
equalizeHist(img_1, hist_img);
imshow("Original", img_1);
imshow("Histogram equalization", hist_img);
waitKey(0);
return 0;
}
- RESULT
분명 원본 이미지도 괜찮다고 생각했었는데,
히스토그램 균일화 작업을 하니까 이미지가 더 선명해졌음을 알 수 있다.
결과만 놓고 쉽게 이해하자면
기본 이미지에 대비를 더 심하게 한것과 동일한 결과라 할 수 있다.
하지만 히스토그램 균일화 작업을 대비를 높였다라고 쉽게 부르지는 않는다.
대비를 높였다라기 보다는 이미지 밝기를 고르게 만드는 작업이기 때문이다.
아무튼, 이런 이미지 밝기 조절 기법은 OpenCV를 떠나서 모든 영상처리에 기본적으로 사용된다.
이 작업을 하지 않으면 상황이 바뀔 때, 노이즈가 많이 잡히거나, 정상적인 처리를 할 수 없게 되는 것이다.
하지만 단순히 어두운 이미지를 밝게 한다면 덧셈이나 곱셈 연산을 사용하는것이 Histogram equalization 보다 더 빠를 것이다.
왜냐하면 Histogram equalization은 histogram을 한 번 분석하고 그거를 균일화 시키는 작업이 필요하기 때문이다.
상황에 맞는 방법으로 이미지 밝기를 조절하길 바란다.
도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!
감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^
'코딩 > OpenCV' 카테고리의 다른 글
[C++ opencv] 가우시안 필터로 노이즈 제거하기 gaussian filter, gaussian blur() (4) | 2020.06.30 |
---|---|
[C++ opencv] 평균필터 적용하여 노이즈 제거하기 average filter, filter2d() (2) | 2020.06.26 |
[C++ opencv] 가장 쉽게 이미지 밝기 조절 하는 방법 (0) | 2020.06.25 |
[C++ opencv] 동영상 불러오기 VideoCapture() (1) | 2020.06.24 |
[C++ opencv] 카메라, 웹캠 영상 입력받기 VideoCapture() (0) | 2020.06.24 |
댓글