- 대부분 경우에는 영상이 시각적으로 빈약하지 않으며, 너무 좁은 밝기 범위를 갖지 않는다.
- 오히려 어떤 명암도 값은 다른 것에 비해 자주 사용.
- 히스토그램 평활화는 영상 히스토그램을 가능한 한 평평하게 만든다.
- Example
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
// 멤버 변수 정의
class Histogram1D {
private:
int histSize[1]; // 빈도수
float hranges[2]; // 최소/최대 화소값
const float* ranges[1];
int channels[1]; // 여기서 1채널만 사용
public :
Histogram1D() { // 1차원 히스토그램을 위한 인자 준비
histSize[0]= 256;
hranges[0]= 0.0;
hranges[1]= 255.0;
ranges[0]= hranges;
channels[0]= 0; // 기본적으로 채널을 0으로 보기
}
// 정의한 멤버 변수로 그레이레벨 영상의 히스토그램을 계산할 때는 다음 메소드를 사용해 수행
cv::MatND getHistogram(const cv::Mat &image) {
// 1차원(1D) 히스토그램 계산.
cv::MatND hist;
cv::calcHist(&image, // 히스토그램 계산
1, // 단일 영상의 히스토그램만
channels, // 대상 채널
cv::Mat(), // 마스크 사용하지 않음
hist, // 결과 히스토그램
1, // 1차원(1D) 히스토그램
histSize, // 빈도수
ranges // 화소값 범위
);
return hist;
}
// 값의 순서만으로 의미를 파악하기 어려우므로 바 그래프를 사용
// 그래프를 생성하는 메소드
cv::Mat getHistogramImage(const cv::Mat &image){
// 1차원(1D) 히스토그램을 계산하고, 영상으로 반환
cv::MatND hist= getHistogram(image); // 먼저 히스토그램 계산
double maxVal=0; // 최대 빈도수 가져오기
double minVal=0; // 최소 빈도수 가져오기
cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);
cv::Mat histImg(histSize[0], histSize[0], CV_8U,cv::Scalar(255));
// 히스토그램을 출력하기 위한 영상
int hpt = static_cast<int>(0.9*histSize[0]);
// nbins의 90%를 최대점으로 설정
for(int h=0; h<histSize[0]; h++){ // 각 빈도에 대한 수직선을 그리기
float binVal = hist.at<float>(h);
int intensity = static_cast<int>(binVal*hpt/maxVal);
cv::line(histImg,cv::Point(h,histSize[0]),cv::Point(h,histSize[0]-intensity),cv::Scalar::all(0));
// 두 점 간의 거리를 그리는 함수
}
return histImg;
}
cv::Mat equalize(const cv::Mat &image) {
// 원 영상을 평활화
cv::Mat result;
cv::equalizeHist(image,result);
return result;
}
};
int main()
{
cv::Mat image = cv::imread("batgirl.jpg", 0);
if(!image.data)
return 0;
cv::namedWindow("Image");
cv::imshow("Image", image);
Histogram1D h; // 히스토그램 객체
cv::Mat eq= h.equalize(image); // 영상 평활화
cv::namedWindow("Equalized Image"); // 결과 보기
cv::imshow("Equalized Image",eq);
cv::namedWindow("Equalized Histogram"); // 새로운 히스토그램 보기
cv::imshow("Equalized Histogram",h.getHistogramImage(eq));
cv::waitKey(0);
return 0;
}
- Result
- 완벽한 균등 히스토그램의 모든 빈도는 화소 개수와 모두 같다.
- 화소의 50%는 128보다 작은 명암도를 갖고, 25%는 64보다 작은 명암도를 갖는다.
- 균등 히스토그램에서 화소의 p%에 속한 명암도 값을 갖되 255*p%보다 적거나 같아야 한다는 게 히스토그램을 평활화 하는 데 사용하는 규칙.
- 명암도 i는 i보다 적은 명암도 값을 갖는 화소의 %에 대응하는 명암도로 매핑.
- 즉, 다음 공식을 적용해 구축된 룩업 테이블 필요.
- lookup.at<uchar>(i) = static_cast<uchar>(255.0*p[i]);
- p[i]는 i보다 적거나 같은 명암도를 갖는 화소 개수.
- p[i]는 종종 누적 히스토그램으로 불림.
- 즉, 지정된 명암도와 적거나 같은 화소 개수를 포함하는 히스토그램으로, 해당 화소값을 갖는 화소 개수를 대신함.
- 참고문헌 : OpenCV 2 Computer Vision Application Programming Cookbook