5장. 영상 향상과 학습용 전처리
대비 조정
고무줄에 점을 몇 개 찍어 두고 양쪽으로 당기면, 점 사이의 거리가 모두 같은 비율로 벌어집니다. 칸의 밝기에 1 보다 큰 수를 곱하는 것이 이와 같습니다. 100 과 160 은 60 차이였지만, 1.5 를 곱하면 150 과 240 으로 90 차이가 됩니다. 밝은 곳과 어두운 곳의 차이, 곧 대비가 커집니다.
그림의 세 단계가 대비 조정 식 g = alpha × f + beta 입니다. f 는 원래 밝기, g 는 바뀐 밝기입니다. 먼저 alpha 를 곱해 차이를 넓히고, beta 를 더해 전체 밝기를 맞추고, 0~255 를 벗어난 값을 끝 값으로 맞춥니다. 여기서 고무줄을 당기는 힘이 alpha, 고무줄을 통째로 옆으로 옮기는 것이 beta 입니다.
가로축이 원래 밝기 f, 세로축이 바뀐 밝기 g 입니다. 초록 선(alpha 1, beta 0)은 그대로입니다. 갈색 선은 beta 만 50 이라 위로 평행하게 올라갔고, 다홍 선(alpha 1.5)은 기울기가 가팔라서 차이를 키웁니다. 보라 선(alpha 0.5)은 기울기가 완만해서 차이를 줄입니다. 선이 가파를수록 대비가 커진다고 읽으면 됩니다.
손으로 계산해 보기
alpha 1.5, beta -64 를 넣어 봅니다.
| 원래 밝기 f | 1.5 × f | + (-64) | 바뀐 밝기 g |
|---|---|---|---|
| 100 | 150 | 150 - 64 | 86 |
| 160 | 240 | 240 - 64 | 176 |
| 차이 | 60 | 90 | |
| 20 | 30 | 30 - 64 = -34 | 0 이어야 하는데 convertScaleAbs 는 34 |
100 과 160 의 차이 60 이 90 으로 벌어졌습니다. beta 를 -64 로 둔 까닭은, 곱하기만 하면 전체가 너무 밝아지므로 다시 끌어내리기 위해서입니다.
짧은 예시
import cv2
import numpy as np
f = np.array([[100, 160, 20]], dtype=np.uint8)
# convertScaleAbs(src, alpha, beta): alpha 를 곱하고 beta 를 더한 뒤 절댓값을 내어 0~255 로 맞춘다
print(cv2.convertScaleAbs(f, alpha=1.5, beta=-64)) # 결과: [[ 86 176 34]]
# 음수를 0 으로 막으려면 소수로 계산하고 np.clip 으로 0~255 를 자른 뒤 uint8 로 바꾼다
g = np.clip(1.5 * f.astype(np.float32) - 64, 0, 255).astype(np.uint8)
print(g) # 결과: [[ 86 176 0]]np.clip 의 clip 은 "잘라 내다"라는 뜻으로, 범위 밖의 값을 끝 값으로 바꿉니다.
주의할 점
cv2.convertScaleAbs는 이름처럼 절댓값(Abs)을 냅니다. 계산이 -34 가 되면 0 이 아니라 34 가 됩니다. beta 를 음수로 크게 줄 때는 결과에 이런 칸이 섞일 수 있으니, 위의np.clip방법을 씁니다.- alpha 를 너무 크게 주면 많은 칸이 0 과 255 에 몰려 정보가 지워집니다. 히스토그램의 양 끝에 막대가 솟으면 지나친 것입니다.