본문 바로가기

PyImageSearch

OpenCV - Image Histograms

1. 이미지 히스토그램이란 무엇인가?

  • 정의: 히스토그램은 이미지의 픽셀 강도 분포(색상 또는 그레이스케일)를 빈(bin) 단위로 집계한 그래프
  • 빈의 의미: 예를 들어 256개의 빈을 사용하면, 각 픽셀 값(0~255)이 몇 번 등장했는지 세어 막대 그래프로 표현

 

2. cv2.calcHist 함수

 
cv2.calcHist(images, channels, mask, histSize, ranges)

 

파라미터 설명
images 히스토그램을 계산할 이미지 배열을 리스트 형태로 감싸서 전달 ( [image] )
channels 계산할 채널 인덱스 리스트.

그레이스케일: [0]
컬러(RGB): [0,1,2]
mask 히스토그램 계산에 포함할 픽셀 영역을 지정하는 바이너리 마스크. 전체 영역 계산 시 None.
histSize 각 채널별 빈 개수를 리스트로 지정. (예: [256], 컬러 3채널 모두 256개면 [256,256,256])
ranges 픽셀값 범위(비포함 상한 포함). 보통 [0,256]

 

 

3. 히스토그램 정규화하기(L1 정규화 / 확률밀도 히스토그램)

# 1.
hist /= hist.sum ( )
# 2. 
cv2.normalize(hist, hist_l1, alpha=1, beta=0, norm_type=cv2.NORM_L1)

 

 

  • 백분율로 변환 >>> 모든 값을 합산하면 1이 되므로 히스토그램을 확률분포로 변환
  • 픽셀 수 차이 보정 : 서로 다른 크기·조명·노출 이미지 간 분포 비교 가능
  • 특징 벡터 단위화 : 머신러닝·딥러닝 입력으로 사용할 때, 피처 스케일을 맞춰 학습 안정성 향상

 

4. Grayscale Histogram

image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist( [image], [0], None, [256], [0, 256]

 

결과 해석 : 검은색, 흰색 픽셀은 매우 적고 중간값이 높음

 

 

5. Color Histogram

5-1. 1D Histogram : 이미지의 한가지 특징에 대한 픽셀 갯수 선 그래프 출력

# 채널별 이미지 분할
chans = cv2.split(image)
colors = ("b", "g", "r")

for (chan, color) in zip(chans, colors):
	# 채널별로 히스토그램 생성 후 겹쳐서 시각화
	hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
	plt.plot(hist, color=color)
	plt.xlim([0, 256])

채널별 1D 히스토그램 (선그래프)

🔵 파란색(Blue) 채널

  • 밝은영역(220~240)에 매우 높고 뾰족한 peak 존재 : 아주 밝은 파란색을 가진 픽셀이 압도적으로 많음
  • 사진 속 하늘과 바다의 색조가 비교적 균일하고 매우 밝음

🟢 녹색(Green) 채널

  • 중간~밝은 영역(100~200)에 넓게 분포하며 여러 개의 봉우리를 형성
  • 사진 속 야자수 잎은 햇빛을 직접 받는 밝은 부분과 그늘진 어두운 부분이 공존

🔴 빨간색(Red) 채널

  • 어두운 영역(0~50)에몇 개의 봉우리를 형성, 밝은 영역으로 갈수록 픽셀 수가 급격히 줄어듬
  • 사진 속 야자수 나무 기둥과 해변의 모래 색상, 이미지 전체적으로 밝은 빨간색 요소는 거의 없기 때문에 갈수록 값이 매우 낮음

 

5-2. 2D Histogram : 채널간의 관계를 픽셀 밀도 맵으로 시각화

  • 32*32개의 bin 사용
  • X,  Y축: 각 색상 채널의 강도
  • 색상/밝기(Z축): 해당 (X, Y) 좌표의 색상 조합을 가진 픽셀의 수.
    그래프에서 밝은 부분은 해당 색상 조합을 가진 픽셀이 이미지에 많다는 것을 의미
    진한보라 : 픽셀 거의 없음, 연한노랑 : 픽셀 많음
# green and blue channels
fig = plt.figure(figsize=(15, 25))
ax = fig.add_subplot(131)
hist = cv2.calcHist([chans[1], chans[0]], [0, 1], None, [32, 32],
	[0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for G and B")
plt.colorbar(p)

# green and red channels
ax = fig.add_subplot(132)
hist = cv2.calcHist([chans[1], chans[2]], [0, 1], None, [32, 32],
	[0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for G and R")
plt.colorbar(p)

# blue and red channels
ax = fig.add_subplot(133)
hist = cv2.calcHist([chans[0], chans[2]], [0, 1], None, [32, 32],
	[0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for B and R")
plt.colorbar(p)

채널 조합 별 2D 히스토그램 (픽셀밀도 맵)

🔵🟢 Green & Blue

  • 노랑부분이 green, blue 모두 높은 값에 존재 : 파란색과 녹색이 함께 많이 포함된 청록색 등의 색상을 주요하게 가지고 있음
  • 밝은 점에서 원점 방향으로 대각선 분포 : 청록색 계열의 색상이 매우 넓은 영역 차지

🟢🔴 Green & Red

  • 원점에서 우상단으로 진한 대각선 분포 : 회색조(Grayscale)에 가까운 색상(R, G, B 값이 모두 비슷한 경우) 또는 노란색/갈색 계열(R과 G는 높고 B는 낮은 경우)이 많다
  • 원점근처에 노랑색상 집중됨 : 검은색 또는 매우 어두운 영역이 상당히 큰 비중을 차지 (예: 어두운 배경, 그림자)

 

🔵🔴 Blue & Red

  • '순수한' 파란색 계열(높은 B, 낮은 R) 많이 분포

 

 

6. 마스크 적용

# 마스크 적용 예시
mask = np.zeros(gray.shape, dtype="uint8")
mask[100:300, 150:350] = 255

for (chan, color) in zip(chans, colors):
	hist = cv2.calcHist([chan], [0], mask, [256], [0, 256])
	plt.plot(hist, color=color)
	plt.xlim([0, 256])

 

 


출처

https://pyimagesearch.com/2021/04/28/opencv-image-histograms-cv2-calchist/?_ga=2.266635468.376129011.1750397556-254784589.1749433426

 

OpenCV Image Histograms ( cv2.calcHist ) - PyImageSearch

In this tutorial, you will learn how to compute image histograms using OpenCV and the “cv2.calcHist” function.

pyimagesearch.com

 

 

'PyImageSearch' 카테고리의 다른 글

OpenCV - Histogram Matching  (0) 2025.06.16
OpenCV - Histogram Equalization  (0) 2025.06.16
OpenCV - Edge detection  (0) 2025.06.14
OpenCV - Image Gradients(엣지검출)  (0) 2025.06.13
OpenCV - Thresholding(이진화)  (0) 2025.06.12