그림 6-30은 히스토그램이 영상 분석에서 어떻게 사용될 수 있는지를 보여주는 좋은 예이다. 그림 6-30(a)는 전반적으로 밝은 영상이고, 그림 6-30(b)는 전반적으로 어두운 영상이다. 그림 6-30(C)는 명암비가 낮은 영상이고, 그림 6-30(d)는 명암비가 높은 영상의 예이다. 이 영상들은 6.2절에서 배운 밝기와 명암비 조절 기능을 이용하여 생성하였다. 각 영상의 오른쪽 그림은 해당 영상의 히스토그램을 보여주고 있다. 그림 6-30(a)의 밝은 영상의 경우, 히스토그램이 오른쪽으로 치우쳐 있으며, 그림 6-30(b)의 어두운 영상은 그레이스케일 값이 0에 가까운 왼쪽에 히스토그램이 치우쳐서 나타나게 된다. 명암비가 낮은 그림 6-30(C) 영상은 히스토그램이 일정 구역에 몰려서 나타나며, 반면에 명암비가 높은 그림 6-30(d) 영상의 히스토그램은 그 값이 0~255 구간 전체에 골고루 나타나는 것을 볼 수 있다.
히스토그램을 구하는 방법은 매우 간단하다. 256개의 원소를 갖는 배열을 하나 선언한 후, 영상의 모든 픽셀을 검사하면서 픽셀의 그레이스케일에 해당하는 배열의 원소 값을 1씩 증가시키면 된다. 만약 정규화된 히스토그램 함수를 얻고 싶다면 연산이 끝난 후에 각 배열 값을 전체 픽셀의 개수로 나눈다.
그러면 실제 영상의 히스토그램을 구하는 함수를 작성해보도록 하자. 히스토그램을 구하는 함수의 이름은 IppHistogram을 사용하기로 하고, IppEnhance.h 파일에 다음과 같은 함수의 선언을 추가하자.
void IppHistogram(IppByteImage& img, float histo[256]);
이 함수는 IppByteImage 클래스의 참조형으로 입력 영상 img를 인자로 받고, 256 크기의 실수형 배열을 두 번째 인자로 받는다. img로부터 계산된 정규화된 히스토그램은 histo 배열에 저장된다. IppHistogram 함수의 전체 내용은 소스 6-16에 나타내었다.
void IppHistogram(IppByteImage& img, float histo[256]) { int size = img.GetSize(); BYTE* p = img.GetPixels(); // 히스토그램 계산 int cnt[256]; memset(cnt, 0, sizeof(int) * 256); for (int i = 0; i < size; i++) cnt[p[i]]++; // 히스토그램 정규화(histogram normalization) for (int i = 0; i < 256; i++) { histo[i] = static_cast<float>(cnt[i]) / size; } }
IppHistogram 함수의 두 번째 인자에 해당하는 배열은 항상 256개의 원소를 가지고 있는 float 타입의 배열이어야 한다. 함수의 내부에서 int cnt[256] 배열에서 각 그레이스케일에 해당하는 픽셀의 개수를 계산한다. 그리고 마지막 for 루프에서 cnt 배열에 저장된 값을 전체 픽셀의 개수로 나누어 정규화된 히스토그램 값을 histo 배열에 저장하고 있다.