5장. 영상 향상과 학습용 전처리
CLAHE
교실 하나를 통째로 밝게 비추면 창가는 눈부시고 구석은 여전히 어둡습니다. 대신 자리마다 작은 스탠드를 하나씩 두고 그 자리에 맞게 밝기를 맞추면 어디서나 책이 잘 보입니다. CLAHE 는 사진을 바둑판 칸으로 나눠 칸마다 따로 평활화합니다. 그리고 한 칸 안에서 막대가 너무 높이 솟으면 깎아서, 잡티까지 크게 키우지 않게 합니다.
그림의 네 단계가 CLAHE 가 하는 일입니다. 사진을 바둑판 칸으로 나누고(tileGridSize), 칸마다 히스토그램을 세어 너무 높은 막대를 깎고(clipLimit), 칸 안에서만 평활화하고, 칸 사이의 이음매가 보이지 않게 부드럽게 잇습니다. 여기서 자리마다 놓은 스탠드가 바둑판 칸 하나이고, 스탠드가 너무 밝지 않게 정해 둔 한도가 clipLimit 입니다.
왼쪽 그래프의 다홍 부분이 자르는 높이(점선)를 넘은 몫입니다. 오른쪽처럼 넘친 몫을 깎아 모든 구간에 살구색으로 고루 나눠 줍니다. 막대가 한 곳에 너무 높이 솟으면 평활화가 그 밝기의 간격을 크게 벌려 놓는데, 깎아 두면 벌어지는 정도가 줄어듭니다. 그래서 넓고 고른 벽에 낀 작은 잡티가 덜 커집니다.
밝은 창을 등진 실내를 도형으로 그린 가상의 그림(ch05_backlit.png)입니다. 왼쪽 그림의 다홍 선이 8×8 바둑판입니다. 가운데의 전체 평활화는 어두운 책장을 크게 밝혔지만, 창이 하얗게 날아가고 벽에 줄무늬가 생겼습니다. 오른쪽 CLAHE 는 책장을 덜 밝히는 대신 창과 벽을 원래 모습에 가깝게 지켰습니다.
두 인자
| 인자 | 뜻 | 작게 주면 | 크게 주면 | 처음 해 볼 값 |
|---|---|---|---|---|
clipLimit | 막대를 깎는 높이 | 원본과 비슷하다 | 전체 평활화에 가까워진다 | 2.0 |
tileGridSize | 바둑판의 (가로 칸 수, 세로 칸 수) | 넓은 칸, 전체 평활화에 가깝다 | 좁은 칸, 작은 부분까지 펼친다 | (8, 8) |
짧은 예시
import cv2
gray = cv2.imread("ch05_backlit.png", cv2.IMREAD_GRAYSCALE)
# cv2.createCLAHE: 설정을 담은 CLAHE 도구를 만든다. 실제 처리는 apply 로 한다
clahe = cv2.createCLAHE(clipLimit=2.0, # 막대를 깎는 높이
tileGridSize=(8, 8)) # 바둑판 8×8칸
out = clahe.apply(gray)
# 책장 부분(세로 40~164, 가로 15~114)의 표준편차: 클수록 책끼리 밝기 차이가 크다
print(round(float(gray[40:165, 15:115].std()), 1), round(float(out[40:165, 15:115].std()), 1)) # 결과: 13.0 18.4책장 부분의 표준편차가 13.0 에서 18.4 로 커졌습니다. 어둠 속의 책들이 서로 더 구별된다는 뜻입니다.
주의할 점
cv2.createCLAHE는 도구를 만들 뿐입니다..apply(gray)를 불러야 처리됩니다. 도구 하나를 만들어 두고 사진 여러 장에 차례로 씁니다.- CLAHE 도 흑백 한 채널만 받습니다. 컬러 사진은 앞 절처럼 밝기 채널에만 씁니다.
- 바둑판을 너무 잘게 나누면 칸 하나에 든 칸 수가 적어 얼룩덜룩해집니다.