14장. 영상 기하학 변환과 Affine, Perspective
보간법
모자이크 타일 벽을 두 배로 넓힌다고 해 봅시다. 원래 타일 사이에 새 타일을 끼워야 하는데, 무슨 색으로 할까요? 옆 타일 색을 그대로 쓰면 빠르지만 경계가 계단처럼 보입니다. 양옆 색을 섞어 중간색을 쓰면 부드럽습니다. 크기를 바꿀 때 새로 생긴 칸의 값을 정하는 방법이 보간법입니다.
밝기 100 과 200 인 두 칸을 네 칸으로 키운 결과입니다. 최근접 이웃(INTER_NEAREST)은 가까운 칸의 값을 그대로 가져와 100, 100, 200, 200 이 됩니다. 양선형 보간(INTER_LINEAR)은 사이를 고르게 나눠 100, 125, 175, 200 이 됩니다. 여기서 옆 타일 색을 그대로 쓰는 것이 최근접 이웃, 양옆 색을 섞는 것이 양선형 보간입니다.
양선형 보간을 손으로 계산하기
새 칸 하나가 원래 두 칸 사이의 어디에 놓이는지 보고, 가까운 쪽에 더 큰 무게를 줍니다. 위 그림의 둘째 칸은 100 쪽에서 4분의 1, 200 쪽에서 4분의 3 떨어진 자리입니다.
| 새 칸 | 100 에 주는 무게 | 200 에 주는 무게 | 계산 | 값 |
|---|---|---|---|---|
| 둘째 칸 | 0.75 | 0.25 | 100 × 0.75 + 200 × 0.25 | 125 |
| 셋째 칸 | 0.25 | 0.75 | 100 × 0.25 + 200 × 0.75 | 175 |
무게 둘을 더하면 늘 1 입니다. 가까운 쪽 값을 더 많이 섞는 가중 평균입니다. 그림은 가로와 세로가 있으므로, 가로로 한 번 섞고 세로로 한 번 더 섞습니다. 그래서 "양(兩, 둘)선형"입니다.
위 줄은 32×24 아이콘을 8배로 키운 결과입니다. 최근접 이웃은 네모 계단이 그대로 커지고, 양선형과 바이큐빅은 경계가 부드럽게 번집니다. 아래 줄은 촘촘한 동심원 무늬를 4분의 1로 줄인 결과입니다. 최근접 이웃은 칸을 띄엄띄엄 골라 원래 없던 굵은 물결무늬가 생겼고(계단 현상), 넓이 평균(INTER_AREA)은 검고 흰 고리를 평균 내어 고른 회색이 되었습니다. 6장에서 "크기 줄이기 전에 블러로 들쭉날쭉한 무늬를 막는다"고 한 것이 이 무늬입니다. INTER_AREA 는 줄이면서 평균을 내므로 블러를 따로 걸지 않아도 됩니다.
보간법 고르기
그림의 네 상자는 OpenCV 의 대표 보간법 네 가지입니다. 줄일 때는 넓이 평균, 키울 때는 양선형이나 바이큐빅을 고르는 것이 보통입니다.
| 상수 | 이름 | 채우는 법 | 속도 | 알맞은 곳 |
|---|---|---|---|---|
cv2.INTER_NEAREST | 최근접 이웃 | 가장 가까운 칸 하나를 복사 | 가장 빠름 | 정답 마스크, 라벨 그림(값이 바뀌면 안 될 때) |
cv2.INTER_LINEAR | 양선형 | 둘레 4칸을 무게대로 섞음 | 빠름 | 키우기, cv2.resize 의 기본값 |
cv2.INTER_CUBIC | 바이큐빅 | 둘레 16칸으로 매끈한 곡선 | 느림 | 키우기(더 또렷하게) |
cv2.INTER_AREA | 넓이 평균 | 덮는 칸들의 평균 | 보통 | 줄이기 |
짧은 예시
import cv2
import numpy as np
# 밝기 100 과 200 인 두 칸짜리 그림(세로 1, 가로 2)
pair = np.array([[100, 200]], dtype=np.uint8)
# 가로 4칸, 세로 1칸으로 키운다. 방법마다 새 칸을 다르게 채운다
for name, flag in [("NEAREST", cv2.INTER_NEAREST), ("LINEAR", cv2.INTER_LINEAR),
("CUBIC", cv2.INTER_CUBIC)]:
big = cv2.resize(pair, (4, 1), interpolation=flag)
print(name, [int(v) for v in big[0]])
# 결과: NEAREST [100, 100, 200, 200]
# LINEAR [100, 125, 175, 200]
# CUBIC [89, 123, 177, 211]바이큐빅은 89 와 211 처럼 원래 범위(100~200)를 조금 넘는 값을 만듭니다. 매끈한 곡선이 경계에서 살짝 넘쳤다 돌아오기 때문입니다. 경계가 더 또렷해 보이는 대신, 경계 둘레에 옅은 테두리가 생길 수 있습니다.
주의할 점
- 정답 마스크(0 과 255 만 있는 그림)를 양선형으로 키우면 경계에 128 같은 중간값이 생깁니다. 마스크나 라벨 그림은
INTER_NEAREST로 바꿉니다. - 촘촘한 무늬를
INTER_NEAREST로 줄이면 계단 현상이 생깁니다. 줄일 때는INTER_AREA를 씁니다. interpolation을 주지 않으면INTER_LINEAR입니다. 줄일 때도 기본값이 쓰이므로, 줄이는 코드에는INTER_AREA를 적어 줍니다.