히스토그램(=도수분포도)
intensity levels의 범위가 [0, L-1]인 영상의 히스토그램에서
- ℎ (𝑟𝑘) = 𝑛𝑘
- 𝑟𝑘: 𝑘^𝑡ℎ intensity value(k번째 인텐시브 값), 𝑛𝑘 : the number of pixels with intensity 𝑟𝑘 (인텐시브 rk의 픽셀 수)
- 이 경우 bin의 개수는 L이다.
히스토그램의 bin의 개수가 256개, 이미 픽셀 값도 0~255라고 할때, 제일 첫번째 bin에 해당하는 값은 intensity 값(픽셀 값)이 0인 픽셀의 개수로 결정된다.
Histogram normalization(히스토그램 정규화)
- 각 구성 요소를 총 픽셀 수로 나눔. 즉, 각각의 bin에 있는 값을 영상을 포함하고 있는 전체 픽셀 값으로 나눠준다. 영상 내의 특정한 값을 가진 픽셀이 존재할 확률이, 이 정규화된 히스토그램으로 표현된다.
- 그렇기 때문에 확률 함수로 간주 될 수 있습니다
히스토그램은 수많은 공간 영역 처리 기술의 기초로, 적절한 bin 수를 설정하는 것이 중요하다.
bin의 개수가 너무 많으면, 대부분의 bin에서 유사한 값이 나타나는 것을 볼 수 있고,
bin의 개수가 너무 적으면, 영상의 특성을 반영하기 어렵다.
Histogram equalization(히스토그램 평준화)
- 히스토그램 평준화는 일종의 전처리 방식으로, 이미지의 대비(contrast)를 조정하는 방법이다.
이 때 대비(contrast)란, 개체를 구별 할 수있는 밝기 또는 색상의 차이로 대비가 클수록 이미지가 선명해보여서 물체의 식별이 용이해진다.
히스토그램이 상대적으로 균일하게 분포되어있는 가장 오른쪽 영상의 대비가 가장 높은 걸 알 수 있다.
히스토그램 평준화를 하는 방법을 간단하게 설명하자면
1. 입력 영상의 히스토그램을 계산하고
2. 히스토그램을 최대한 평평히 만들 수 있는, 즉 평활화 할 수 있는 함수를 구한다.
3. 이렇게 구한 함수를 매핑함수로 사용해 입력 영상에 적용한다.
ex code
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp> // equlizeHist, calcHist 사용하기위해 추가
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat drawHistogram(Mat src) {
Mat hist, histImage;
// establish the number of bins
int i, hist_w, hist_h, bin_w, histSize;
float range[] = { 0, 256 }; // 입력값의 범위를 정해주는 부분
const float* histRange = { range };
// 히스토그램을 그릴 캔버스 사이즈
hist_w = 512;
hist_h = 400;
histSize = 256;
bin_w = cvRound((double)hist_w / histSize); // 캔버스 크기 대비 bin의 개수로 나눠주면 하나의 bin의 width 알 수 있다.
// compute the histograms
// &src: input image, 1: #of src image, 0: #of channels numerated from 0 ~ channels()-1, Mat(): optional mask
// hist: output histogram, 1: histogram dimension, &histSize: array of histogram size, &histRange: array of histogram’s boundaries
calcHist(&src, 1, 0, Mat(), hist, 1, &histSize, &histRange); // 히스토그램을 계산하는 부분
//draw the histogram
histImage = Mat(hist_h, hist_w, CV_8UC3, Scalar(255, 255, 255)); // 히스토그램을 글기 위한 캔버스 설정. 초기색상은 흰색
// normalize the result to [0, histImage.rows]
// hist: input Mat, hist: output Mat, 0: lower range boundary of range normalization, histImage.rows: upper range boundary
// NORM_MINMAX: normalization type, -1: when negative, the ouput array has the same type as src, Mat(): optional mask
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); // 캔버스 높이를 이용해서 계산한 히스토그램을 정규화 시킴.
for (i = 1; i < histSize; i++) {
rectangle(histImage, Point(bin_w*i, hist_h), Point(bin_w*i, hist_h - cvRound(hist.at<float>(i))), Scalar(0, 0, 0), 2, 8, 0);
}
return histImage;
}
int main() {
Mat image;
Mat hist_equalized_image;
Mat hist_graph;
Mat hist_equalized_graph;
image = imread("lena.png", 0);
if (!image.data) exit(1); // check image
equalizeHist(image, hist_equalized_image); //histogram equlization
hist_graph = drawHistogram(image);
hist_equalized_graph = drawHistogram(hist_equalized_image);
imshow("Input image", image);
imshow("Hist Equalizd Image", hist_equalized_image);
imshow("Hist Graph", hist_graph);
imshow("Hist qualized Graph", hist_equalized_graph);
waitKey(0);
return 0;
}
calcHist() 의 파라미터를 순서대로 설명하면,
- 입력영상
- 입력영상의 개수(여러개의 영상에 대해서 동시에 히스토그램 그릴수 있기때문)
- 영상 채널수(0=채널1개, 1=2개..)
- 히스토그램을 특정한 부분에서 그리고싶을 때 옵션mat 사용
- 그려지게될(계산되게 될)히스토그램
- 히스토그램의 디맨져? 1이면 1차원적인 히스토그램
- bin의 개수
- 히스토그램을 그리기위해 사용되는 입력값의 범위를 설정해줌
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
히스토그램을 그릴 캔버스의 높이를 이용해서 히스토그램을 정규화시키는 이유는, hist_h(높이)보다 bin의 값이 클 경우엔, 캔버스를 넘어가버려 표현이 불가능해지기 때문이다.
히스토그램 평준화는 무조건 모든 영상에 사용가능한 것이 아니라, 영상 내의 픽셀들이 균등하게 분포하는 것이 타당한 경우에만 사용가능하다!
이 게시물은 한동대학교 황성수 교수님의 컴퓨터비전 강의를 공부하며 정리한 내용입니다.
'Computer Vision' 카테고리의 다른 글
[OpenCV] 컬러영상처리(Color Processing) (0) | 2020.01.19 |
---|---|
[OpenCV] 공간 도메인 필터링(Spatial Filtering) (0) | 2020.01.19 |
[OpenCV] 밝기값 변환(Intensity Transformation) (0) | 2020.01.18 |
[OpenCV] 메모리 관리 및 픽셀 액세스(Memory Management/Pixel Access) (0) | 2020.01.11 |
[OpenCV] Drawing 함수(Drawing Function) (0) | 2020.01.11 |