히스토그램이란?
히스토그램은 이미지의 픽셀 값 분포를 나타내는 그래프
- X축: 픽셀 값 (0-255)
- Y축: 해당 픽셀 값을 가진 픽셀의 개수
사용 목적:
- 이미지 밝기/대비 분석
- 어두운 이미지 개선
- 이미지 비교
히스토그램 평탄화 (Histogram Equalization)
히스토그램 평탄화는 이미지의 밝기 분포를 균등하게 만들어 대비를 향상시킵니다.
In [8]:
import cv2
import matplotlib.pyplot as plt
# 이미지 읽기
img = cv2.imread('../../.data/gorilla.jpg', cv2.IMREAD_GRAYSCALE)
# 히스토그램 평탄화
equalized = cv2.equalizeHist(img)
# CLAHE 생성 및 적용
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_img = clahe.apply(img)
# 이미지와 히스토그램을 함께 표시하는 함수
def plot_image_and_histogram(img, title, img_pos, hist_pos, fig):
"""이미지와 히스토그램을 함께 표시하는 함수"""
# 이미지 표시
ax_img = fig.add_subplot(3, 2, img_pos)
ax_img.imshow(img, cmap='gray')
ax_img.set_title(title)
ax_img.axis('off')
# 히스토그램 표시
ax_hist = fig.add_subplot(3, 2, hist_pos)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
ax_hist.plot(hist)
ax_hist.set_title(f'{title} Histogram')
ax_hist.set_xlabel('Pixel Value')
ax_hist.set_ylabel('Number of Pixels')
ax_hist.set_xlim([0, 256])
# 결과 비교
fig = plt.figure(figsize=(12, 12))
# 원본 이미지와 히스토그램
plot_image_and_histogram(img, 'Original Image', 1, 2, fig)
# 평탄화된 이미지와 히스토그램
plot_image_and_histogram(equalized, 'Equalized Image', 3, 4, fig)
# CLAHE 이미지와 히스토그램
plot_image_and_histogram(clahe_img, 'CLAHE Image', 5, 6, fig)
plt.tight_layout()
plt.show()In [9]:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 컬러 이미지 읽기
img_color = cv2.imread('../../.data/gorilla.jpg')
img_color = cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB) # BGR을 RGB로 변환
# 히스토그램 계산 및 시각화 함수
def plot_histogram(img, title, ax_img, ax_hist):
"""이미지와 히스토그램을 함께 표시하는 함수"""
# 이미지 표시
if len(img.shape) == 2: # 그레이스케일
ax_img.imshow(img, cmap='gray')
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
ax_hist.plot(hist, color='black')
else: # 컬러
ax_img.imshow(img)
# RGB 각 채널별 히스토그램
for i, color in enumerate(['r', 'g', 'b']):
hist = cv2.calcHist([img], [i], None, [256], [0, 256])
ax_hist.plot(hist, color=color, alpha=0.7, label=color.upper())
ax_hist.legend()
ax_img.set_title(title)
ax_img.axis('off')
ax_hist.set_title(f'{title} Histogram')
ax_hist.set_xlabel('Pixel Value')
ax_hist.set_ylabel('Number of Pixels')
ax_hist.set_xlim([0, 256])
# 컬러 이미지 평탄화
# YUV 색공간으로 변환 후 Y 채널만 평탄화 (일반적인 방법)
# YUV 색공간: Y(밝기), U(색상), V(색상) 채널로 구성
# - Y 채널: 밝기(Luminance) 정보만 담고 있음
# - U, V 채널: 색상(Chrominance) 정보를 담고 있음
# Y 채널만 평탄화하면 색상 정보(U, V)는 유지하면서 밝기만 개선할 수 있음
# 만약 RGB 각 채널을 모두 평탄화하면 색상 왜곡이 발생할 수 있음
img_yuv = cv2.cvtColor(img_color, cv2.COLOR_RGB2YUV)
img_yuv[:, :, 0] = cv2.equalizeHist(img_yuv[:, :, 0])
equalized_color = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2RGB)
# CLAHE 적용 (컬러 이미지)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
img_yuv_clahe = cv2.cvtColor(img_color, cv2.COLOR_RGB2YUV)
img_yuv_clahe[:, :, 0] = clahe.apply(img_yuv_clahe[:, :, 0])
clahe_color = cv2.cvtColor(img_yuv_clahe, cv2.COLOR_YUV2RGB)
# 결과 비교
fig, axes = plt.subplots(3, 2, figsize=(12, 15))
# 원본 이미지
plot_histogram(img_color, 'Original Image', axes[0, 0], axes[0, 1])
# 평탄화된 이미지
plot_histogram(equalized_color, 'Equalized Image', axes[1, 0], axes[1, 1])
# CLAHE 이미지
plot_histogram(clahe_color, 'CLAHE Image', axes[2, 0], axes[2, 1])
plt.tight_layout()
plt.show()