opencv c++ 히스토그램을 이용하여 이미지 밝기 조절
- 최초 작성일: 2022년 1월 11일(화)
목차
[TOC]
목표
우선, 히스토그램이 무엇인지 알아보고 가자.
히스토그램(histogram)은 표로 되어 있는 도수 분포를 정보 그림으로 나타낸 것이다.
더 간단하게 말하면, 도수분포표를 그래프로 나타낸 것이다.
그러므로, 히스토그램을 이미지에 접목을 시키면, 각 픽셀의 값들의 분포를 그래프로 표기할 수가 있다.
그러면 불러온 이미지의 픽셀 값들에 대한 분포도를 가시적으로 더 쉽게 확인할 수 있다.
히스토그램의 기능들 중에 equalization이라는 기능이 있는데, 그것은 밝기 값들이 한 곳으로 모여있다면, 그 값들을 균등하게 분산시키는 기능이다.
아래의 사진은 가운데에 모여있는 값들을 보이는 이미지를 equaliation해준 결과를 보여준다.
즉, 이 작업으로 밝기 값들을 효과적으로 조절할 수 있는 것이다.
사칙 연산만으로는 이러한 결과를 얻기에는 많은 어려움이 있을 것이기 때문에, 효과적인 방법이라 할 수 있다.
실습
자, 그럼 이번에는, 히스토그램으로 불러온 이미지의 밝기를 조절해보자.
불러온 이미지들의 밝기 값들의 분포도를 확인 및 비교해보자.
그리고 나서, 이미지에 histogram equalization 함수 실행 결과를 확인해보자.
소스 코드
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int ac, char** av) {
Mat img1 = imread("lion.png", 0); //grayscale image
// Mat img1 = imread("doctor.png", 0); //grayscale image
Mat img_hist;
Mat hist_equal;
equalizeHist(img1, hist_equal);
MatND histogram;
MatND histogram_;
const int* channelN = { 0 };
float channel_range[] = { 0.0, 255.0 };
const float* channel_ranges = channel_range;
int binsNum = 255;
calcHist(&img1, 1, channelN, Mat(), histogram, 1, &binsNum, &channel_ranges);
calcHist(&hist_equal, 1, channelN, Mat(), histogram_, 1, &binsNum, &channel_ranges);
int hist_w = img1.cols;
int hist_h = img1.rows;
int bin_w = cvRound((double)hist_w / binsNum);
int hist_w_ = hist_equal.cols;
int hist_h_ = hist_equal.rows;
int bin_w_ = cvRound((double)hist_w_ / binsNum);
Mat hist_img(hist_h, hist_w, CV_8UC1, Scalar::all(0));
Mat hist_img_(hist_h_, hist_w_, CV_8UC1, Scalar::all(0));
normalize(histogram, histogram, 0, hist_img.rows, NORM_MINMAX, -1, Mat());
normalize(histogram_, histogram_, 0, hist_img_.rows, NORM_MINMAX, -1, Mat());
for (int i = 1; i < binsNum; 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);
}
for (int i = 1; i < binsNum; 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("origin", img1);
imshow("histogram", hist_img);
imshow("hist_equal", hist_equal);
imshow("histogram_equal", hist_img_);
waitKey(0);
return(0);
}
결과
아래의 사진은 불러온 이미지를 히스토그램으로 표현한 것이다.
사자 사진의 히스토그램을 보면, 잘 안 보이겠지만 왼쪽에 값들의 분포가 치우쳐져있다. 그 이유는, 바탕 화면이 검정색이라 낮은 픽셀 값들의 분포도가 높아서 그런 모습을 보이는 것이다.
반면에, 두번째 의사 사진의 히스토그램을 보면, 비교적 중간값들의 분포도가 높은 것을 볼 수 있다.
추가로, 이미지를 histogram equalization 한 결과도 확인할 수 있다.