주어진 영상의 픽셀 밝기 분포를 조사해 밝기 및 명암비를 적절하게 조절
영상의 픽셀 밝기 값 분포를 나타내는 히스토그램
OpenCV에서 히스토그램을 구하는 방법
히스토그램 분석을 통해 영상의 밝기 및 명암비 자동 조절
→ 히스토그램 스트레칭, 히스토그램 평활화
영상의 픽셀 값 분포를 그래프 형태로 표현한 것
그레이스케일 → 각 그레이스케일 값에 해당하는 픽셀의 개수를 구하고 이를 막대 그래프 형태로 표현
컬러 → 세 개의 색상 성분 조합에 따른 픽셀 개수를 계산하여 히스토그램을 구함
아래 4 X 4 입력 영상은 각 픽셀이 0~7 사이의 밝기를 가짐
각각의 밝기에 해당하는 픽셀 개수를 세어서 막대 그래프 형태로 표현한 히스토그램
but, 히스토그램의 빈 개수가 항상 픽셀 값 범위와 같아야 하는 것은 X
OpenCV에서 영상의 히스토그램을 구하는 함수
💡
calcHist()
void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate = false);
• images | 입력 영상의 배열 또는 입력 영상의 주소. 영상의 배열인 경우, 모든 영상의 크기와 깊이는 같아야 함 |
---|---|
• nimages | 입력 영상 개수 |
• channels | 히스토그램을 구할 채널을 나타내는 정수형 배열 |
• mask | 마스크 영상. 입력 영상과 크기가 같은 8비트 배열이어야 함.마스크 행렬의 원소 값이 0이 아닌 좌표의 픽셀만 히스토그램 계산에 사용됨. mask 인자에 Mat() 또는 noArray()를 지정하면 입력 영상 전체에 대해 히스토그램을 구함. |
• hist | 출력 히스토그램. CV_32F 깊이를 사용하는 dims-차원의 행렬 |
• dims | 출력 히스토그램의 차원 수 |
• histSize | 각 차원의 히스토그램 배열 크기를 나타내는 배열(즉, 각 차원의 히스토그램 빈 개수를 나타내는 배열) |
• ranges | 각 차원의 히스토그램 범위. 등간격 히스토그램이면(uniform = true), ranges[i]는 각 차원의 최솟값과 최댓값으로 구성된 배열이고 [최솟값, 최댓값)2 범위를 나타냄. 비등간격 히스토그램이면(uniform = false), ranges[i]는 각각의 구역을 나타내는 histSize[i]+1개의 원소로 구성된 배열 |
• uniform | 히스토그램 빈의 간격이 균등한지를 나타내는 플래그 |
• accumulate | 누적 플래그. 이 값이 true이면 hist 배열을 초기화하지 않고 누적하여 히스토그램을 계산 |
Mat calcGrayHist(const Mat& img)
{
CV_Assert(img.type() == CV_8UC1);
Mat hist;
int channels[] = { 0 };
int dims = 1;
const int histSize[] = { 256 };
float graylevel[] = { 0, 256 };
const float* ranges[] = { graylevel };
calcHist(&img, 1, channels, noArray(), hist, dims, histSize, ranges);
return hist;
}
CV_Assert()
: calcGrayHist() 함수로 전달된 img 영상이 그레이스케일인지 검사→ 반환되는 hist : CV_32FC1 타입을 갖는 256 X 1 크기의 행렬
→ hist 행렬의 행 개수 = 256, 열 개수 = 1
hist 행렬을 참조하여 막대 그래프 영상을 생성
그래프에서 최대 빈도수를 표현하는 막대 그래프 길이가 100픽셀이 되도록 그래프를 그림
01 Mat getGrayHistImage(const Mat& hist)
02 {
03 CV_Assert(hist.type() = = CV_32FC1);
04 CV_Assert(hist.size() = = Size(1, 256));
05
06 double histMax;
07 minMaxLoc(hist, 0, &histMax);
08
09 Mat imgHist(100, 256, CV_8UC1, Scalar(255));
10 for (int i = 0; i < 256; i++) {
11 line(imgHist, Point(i, 100),
12 Point(i, 100 - cvRound(hist.at<float>(i, 0)*100/histMax)), Scalar(0));
13 }
14
15 return imgHist;
16 }
minMaxLoc()
: hist 행렬 원소의 최댓값을 histMax 변수에 저장 최솟값은 관심이 없으므로 두번째 인자는 0으로 설정
**line()
함수**를 이용하여 각각의 빈에 대한 히스토그램 그래프를 그림// 히스토그램 행렬, 그래프 변수 저장
Mat src = imread("camera.bmp", IMREAD_GRAYSCALE);
Mat hist = calcGrayHist(src);
Mat hist_img = getGrayHistImage(hist);
imshow("src", src);
imshow("srcHist", hist_img);
// 단순히 히스토그램 그래프 영상 화면 출력
Mat src = imread("camera.bmp", IMREAD_GRAYSCALE);
imshow("src", src);
imshow("srcHist", getGrayHistImage(calcGrayHist(src)));
히스토그램 픽셀 분포 그래프 → 밝기와 명암비를 가늠할 수 있는 유용한 도구로 사용할 수 O
(a) - 원본
(b) - 밝기 증가, 그래프 전체적으로 오른쪽 이동
(c) - 밝기 감소, 그레프 전체적으로 왼쪽 이동
(d) - 명암비 증가 - 그래프가 그레이스케일 값 범위 전체 구간에 골고루 나타남
(e) - 명암비 낮음 - 히스토그램 그래프가 가운데 일부 구간에 몰려서 나타남
영상의 히스토그램이 그레이스케일 전 구간에 걸쳐서 나타나도록 변경하는 선형 변환 기법
- src : 입력 영상, dst : 출력 영상
- Gmin = 입력 영상의 픽셀 값 중 가장 작은 그레이스케일 값
- Gmax = 입력 영상의 픽셀 값 중 가장 큰 그레이스케일 값
- ( Gmin, 0)과( Gmax, 255)를 지나가는 직선의 방정식을 구해서 이를 변환 함수로 사용
- 직선의 기울기 = 255 / ( Gmax − Gmin), y 절편 = -255 * Gmin / (Gmax-Gmin)이됨
- y = mx + b (b : y절편)
minMaxLoc()
함수 사용히스토그램 스트레칭 예제
01 void histgoram_stretching()
02 {
03 Mat src = imread("hawkes.bmp", IMREAD_GRAYSCALE);
04
05 if (src.empty()) {
06 cerr << "Image load failed!" << endl;
07 return;
08 }
09
10 double gmin, gmax;
11 minMaxLoc(src, &gmin, &gmax);
12
13 Mat dst = (src - gmin) * 255 / (gmax - gmin);
14
15 imshow("src", src);
16 imshow("srcHist", getGrayHistImage(calcGrayHist(src)));
17
18 imshow("dst", dst);
19 imshow("dstHist", getGrayHistImage(calcGrayHist(dst)));
20
21 waitKey();
22 destroyAllWindows();
23 }
Mat dst = (src - gmin) * 255 / (gmax - gmin);
→ 영상 dst는 어두운 영역과 밝은 영역이 고루 분포 → 명암비가 높아짐
→ dstHist창의 히스토그램은 입력 영상의 히스토그램이 양 옆으로 늘어난 듯한 형태
히스토그램 스트레칭과 더불어 영상 픽셀 값 분포가 그레이스케일 전체 영역에서 골고루 나타나도록 변경하는 알고리즘
h(g)
= 영상에서 그레이스케일 값이 g인 픽셀 개수 (그레이스케일 값 g)H(g)
: 히스토그램 누적 함수 → 히스토그램 평활화 계산H(g)
→ 픽셀 값 변환 함수- N : 입력 영상의 픽셀 개수
- Lmax : 영상이 가질 수 있는 최대 밝기 (일반적인 그레이스케일 : 255)
- round() : 반올림 함수
equalizeHist()
- 히스토그램 평활화 함수CV_8UC1
타입을 사용하는 그레이스케일 영상만 입력으로 받음에 주의 ⭐
void equalizeHist( InputArray src, OutputArray dst );
• src | 입력 영상. 8비트 1채널 |
---|---|
• dst | 출력 영상. src와 크기와 타입이 같음 |
히스토그램 평활화 예제
01 void histgoram_equalization()
02 {
03 Mat src = imread("hawkes.bmp", IMREAD_GRAYSCALE);
04
05 if (src.empty()) {
06 cerr << "Image load failed!" << endl;
07 return;
08 }
09
10 Mat dst;
11 equalizeHist(src, dst);
12
13 imshow("src", src);
14 imshow("srcHist", getGrayHistImage(calcGrayHist(src)));
15
16 imshow("dst", dst);
17 imshow("dstHist", getGrayHistImage(calcGrayHist(dst)));
18
19 waitKey();
20 destroyAllWindows();
21 }
→ srcHist에서 큰 값이 몰려 있던 부분의 히스토그램 그래프가 dstHist 그래프에서는 그레이스케일 전체 범위로 넓게 펼쳐짐
→ 기존 형태를 그대로 가져가지 않고 균등하게 분포