Histogram이란, 이미지에서 특정 픽셀값의 등장 빈도를 전체 픽셀 갯수 대비 비율로 나타낸 그래프 입니다.
이미지의 전체적인 명암 분포를 한 눈에 확인할 수 있습니다.
두 가지 예제 코드를 통해 Histogram에 대해 알아보겠습니다.
def plot_histogram_npy(img):
w, h = img.shape
w, h = int(w), int(h)
hist_cnt = np.zeros(255)
hist = np.zeros(255)
for j in range(h):
for i in range(w):
hist_cnt[img[j, i]] += 1
hist = hist_cnt / (w * h)
plt.plot(hist)
plt.title('Histogram of Lena, numpy', size=15)
plot_histogram_npy(img)
OpenCV등을 이용하지 않고 numpy만을 이용하여 구한 Lena의 Histogram 입니다.
이미지에서 개별 픽셀값이 몇 번씩 등장하는지 확인하고 전체 픽셀 수로 normalize하여 Histogram을 얻게 됩니다.
def plot_histogram_cv(img):
w, h = img.shape
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_norm = hist / (w * h) # normalize
plt.plot(hist_norm)
plt.title('Histogram of Lena, OpenCV', size=15)
plot_histogram_cv(img)
OpenCV를 이용하면 함수 호출을 통해 간단하게 Histogram을 구할 수 있습니다.
numpy로 구한 Histogram과 비교해 보면, 두 결과물이 완전히 동일한 것을 알 수 있습니다.
‘cv2.calcHist()’ 를 수행하면 픽셀값 별 등장 횟수의 그래프를 얻고, 이를 normalize하여 최종적으로 Histogram을 얻게 됩니다.
‘cv2.calcHist()’ 의 자세한 사용법은 OpenCV 공식 tutorial page를 통해 확인할 수 있습니다. [2]
Histogram Equalization
Histogram Equalization(히스토그램 평활화)란, pixel값 0부터 255까지의 누적치가 직선 형태가 되도록 만드는 이미지 처리 기법 입니다.
히스토그램 평활화 기법은 이미지가 전체적으로 골고루 어둡거나 골고루 밝아서 특징을 분간하기 어려울 때 자주 쓰입니다.
설명이 난해하니 코드를 통해 자세히 알아보겠습니다.
def show_stacked_histogram(img):
stack_hist = np.zeros(255, dtype=np.float32)
eq_hist = np.zeros(255, dtype=np.float32)
w, h = img.shape
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
for i in range(255):
stack_hist[i] = np.sum(hist[:i])
eq_hist[i] = round(stack_hist[i])
eq_hist /= (w * h)
plt.plot(eq_hist)
plt.title('Stacked Histogram', size=15)
plt.show()
show_stacked_histogram(img)
0부터 255까지의 Histogram의 누적치 입니다. 쉽게 말하면 Histogram을 적분한 것이라고 할 수 있습니다.
e.g) eq_hist[150] = 0.675 → 이미지 내에서 0부터 150까지의 pixel이 차지하는 비율 = 67.5%
당연히 항상 eq_hist[0] = 0이며, eq_hist[255] = 1.0 입니다.
전체적으로 직선에 가까운 형태지만 x좌표기준 0 근처와 255 근처는 수평인 것을 알 수 있습니다.
이 말은 Lena image에서 pixel 값 기준 0 근처와 255 근처가 존재하지 않는다는 말 입니다.
즉, 다시 말해 전체 pixel 값들에 대하여 분포가 균일하지 않다는 말 입니다.
히스토그램 평활화는 이와 같이 균일하지 않은 픽셀값의 분포를 고르게 만드는 작업입니다.
—