4장. 채널 처리와 히스토그램 분석
실습 3 — 채널 평균으로 사진의 색 경향 분석하기
색 경향이 다른 가상의 풍경 세 장(ch04_scenes/ 의 노을, 호수, 숲)에서 채널마다 평균을 구해 표로 만들고, 기준에 따라 "따뜻함, 차가움, 초록"을 판정한 뒤 막대그래프로 견줍니다.
1단계. 세 장의 채널 평균 표 만들기
import cv2
import pandas as pd
scenes = {"sunset.png": "노을", "lake.png": "호수", "forest.png": "숲"}
rows = []
for file, label in scenes.items():
img = cv2.imread(f"ch04_scenes/{file}")
# cv2.mean: (B 평균, G 평균, R 평균, 0) 네 칸을 돌려준다. 앞의 세 칸만 쓴다
b, g, r = cv2.mean(img)[:3]
rows.append({"그림": label, "B": round(b, 1), "G": round(g, 1), "R": round(r, 1)})
table = pd.DataFrame(rows)
print(table.to_string(index=False))그림 B G R
노을 61.1 86.6 185.5
호수 200.2 151.0 104.2
숲 93.6 161.3 109.92단계. 기준으로 색 경향 판정하기
def judge(b, g, r, gap=30):
"""채널 평균 세 개로 색 경향을 판정한다. gap 은 '뚜렷이 크다'의 기준."""
if g > b and g > r:
return "초록이 많음"
if r - b > gap:
return "따뜻함"
if b - r > gap:
return "차가움"
return "쏠림 적음"
# 가장 큰 채널의 이름: B, G, R 세 칸 가운데 값이 가장 큰 칸의 이름
table["가장 큰 채널"] = table[["B", "G", "R"]].idxmax(axis=1)
table["R-B"] = (table["R"] - table["B"]).round(1)
table["판정"] = [judge(row.B, row.G, row.R) for row in table.itertuples()]
print(table.to_string(index=False))그림 B G R 가장 큰 채널 R-B 판정
노을 61.1 86.6 185.5 R 124.4 따뜻함
호수 200.2 151.0 104.2 B -96.0 차가움
숲 93.6 161.3 109.9 G 16.3 초록이 많음3단계. 막대그래프로 견주기
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False
x = np.arange(len(table)) # 그림 세 장의 가로 자리: 0, 1, 2
width = 0.25 # 막대 하나의 너비
fig, ax = plt.subplots(figsize=(8, 4))
# 채널마다 막대를 조금씩 옆으로 밀어 나란히 세운다. 막대 색은 채널의 색으로 정한다
for k, (ch, color) in enumerate([("B", "blue"), ("G", "green"), ("R", "red")]):
ax.bar(x + (k - 1) * width, table[ch], width, label=ch, color=color)
ax.set_xticks(x, labels=[f"{n}\n({j})" for n, j in zip(table["그림"], table["판정"])])
ax.set_ylabel("채널 평균 (0~255)")
ax.set_ylim(0, 255)
ax.legend(loc="upper center", ncol=3)
ax.set_title("그림마다의 B·G·R 평균")
plt.tight_layout()
plt.show()
코드 설명
cv2.mean(img)[:3]은 B, G, R 평균 세 개입니다. 그림 한 장의 색을 숫자 세 개로 줄여 견줄 수 있게 합니다.idxmax(axis=1)은 줄마다 값이 가장 큰 칸의 이름을 돌려줍니다. idxmax 는 index of maximum(가장 큰 값의 이름)이라는 뜻입니다.judge함수는 초록이 가장 크면 "초록이 많음", 아니면 R 과 B 의 차이가 30 을 넘는 쪽으로 판정합니다. 노을은 R-B 가 124.4 라 따뜻함, 호수는 -96.0 이라 차가움, 숲은 G 가 161.3 으로 가장 커서 초록이 많음입니다. 숲의 R-B 는 16.3 이라, 초록 칸을 먼저 따지지 않았다면 쏠림 적음이 됐을 것입니다.- 막대 색은
color="blue"처럼 채널의 색으로 직접 정했습니다. 기본 색을 쓰면 G 막대가 주황으로 나와 헷갈리기 때문입니다.