OpenCV 비전 실무14장 · 영상 기하학 변환과 Affine, Perspective9 / 21← 이전목차다음 →MetaContents

14장. 영상 기하학 변환과 Affine, Perspective

회전

회전목마를 떠올려 봅시다. 가운데 기둥은 제자리에 있고, 말들은 기둥을 중심으로 원을 그리며 돕니다. 기둥에서 멀리 있는 말은 크게, 가까운 말은 작게 돕니다. 그림을 돌릴 때도 중심점 하나를 정하고, 모든 칸이 그 점을 중심으로 같은 각도만큼 원 위를 돕니다.

중심점을 기준으로 점이 원 위를 도는 모습과, 원본 크기로 돌려 모서리가 잘린 결과, 크기를 키워 안 잘리게 돌린 결과

왼쪽은 중심점 둘레의 점이 원 위를 30도씩 도는 모습입니다. 가운데는 모눈 그림을 원본 크기 그대로 30도 돌린 결과로, 네 모서리가 그림 밖으로 나가 잘리고 빈 곳은 검게 칠해졌습니다. 오른쪽은 결과 그림을 키워 모서리까지 모두 담았습니다. 여기서 회전목마의 기둥이 center, 도는 각도가 angle 입니다.

cv2.getRotationMatrix2D 의 인자

돌리는 2×3 표의 숫자는 각도에 따라 복잡하게 바뀝니다. 손으로 계산하지 않고 cv2.getRotationMatrix2D(get rotation matrix 2D, 2차원 회전 표 얻기)가 계산해 줍니다.

getRotationMatrix2D 에 주는 중심, 각도, 배율의 세 인자를 견준 비교 그림

그림의 세 상자가 이 함수의 세 인자입니다. 각도는 양수면 반시계 방향으로 돕니다.

인자뜻보통 값
center돌 때 제자리에 있는 중심점 (x, y)그림 한가운데 (w / 2, h / 2)
angle돌릴 각도(도). 양수는 반시계 방향, 음수는 시계 방향30, -15
scale돌리면서 키울 배율. 1 이면 크기 그대로1.0

90도를 돌리면

중심을 (0, 0) 으로, 각도를 90 으로 주면 표는 [[0, 1, 0], [-1, 0, 0]] 이 됩니다. 점 (1, 0) 에 곱해 더하면 새 x = 0 × 1 + 1 × 0 = 0, 새 y = −1 × 1 + 0 × 0 = −1 입니다. 오른쪽에 있던 점이 위로(그림의 y 는 아래로 갈수록 커지므로 −1 은 위) 갔습니다. 화면에서 보면 반시계 방향으로 90도 돈 것입니다.

돌려도 안 잘리게 하기

원본 크기 그대로 돌리면 모서리가 잘립니다. 안 잘리게 하려면 돌린 그림을 모두 담는 새 가로·세로를 계산하고, 표의 셋째 칸(옮길 거리)을 고쳐 그림을 새 한가운데로 옮깁니다. 새 가로·세로는 표의 첫째·둘째 칸 숫자로 계산할 수 있어서 코드 두 줄이면 됩니다(실습 4). 30도 돌린 320×240 그림은 397×368 이 되어야 모두 담깁니다.

짧은 예시

Python
import cv2

img = cv2.imread("ch14_grid.png")
h, w = img.shape[:2]

# 그림 한가운데 (160, 120) 를 중심으로 30도(반시계 방향), 크기 그대로
M = cv2.getRotationMatrix2D((w / 2, h / 2), 30, 1.0)
print(M.round(3))
# 결과: [[  0.866   0.5   -38.564]
#        [ -0.5     0.866  96.077]]

# borderValue: 빈 곳을 흰색으로 칠한다
rotated = cv2.warpAffine(img, M, (w, h), borderValue=(255, 255, 255))
print(rotated.shape)                         # 결과: (240, 320, 3) → 크기 그대로, 모서리는 잘린다

# 중심점은 돌아도 제자리다: (160, 120) 에 표를 곱해 더해 본다
print(round(float(M[0, 0] * 160 + M[0, 1] * 120 + M[0, 2]), 1),
      round(float(M[1, 0] * 160 + M[1, 1] * 120 + M[1, 2]), 1))   # 결과: 160.0 120.0

표의 숫자 0.866 과 0.5 는 30도에 맞춰 함수가 계산한 값입니다. 셋째 칸(−38.564, 96.077)은 중심점이 제자리에 있도록 함수가 맞춘 옮길 거리입니다.

주의할 점

  • OpenCV 의 각도는 양수가 반시계 방향입니다. 시계 방향으로 돌리려면 음수를 줍니다.
  • 90도, 180도, 270도만 돌릴 때는 cv2.rotate 가 낫습니다. 칸을 그대로 옮기므로 값이 바뀌지 않고 잘리지도 않습니다.
  • 30도처럼 비스듬히 돌리면 칸이 정확히 칸 위에 떨어지지 않아 보간이 일어납니다. 여러 번 나눠 돌리면 그때마다 조금씩 흐려지므로, 한 번에 돌립니다.
← 이전 절14장 · 옮기기와 아핀 변환의 짜임다음 절 →14장 · 세 점으로 아핀 변환