기하학적 변환: 아핀 변환
아핀 변환 Affine transform
- 선형 변환(a)과 평행 이동(b)을 합친 것
- 변환 후에서 평행과 비율은 보존. 길이와 각도는 X
- 영상의 이동, 전단, 확대, 회전을 조합
- 3개의 점이 주어지면 아핀 변환을 결정할 수 있음

평행 이동
image = cv.imread('balls.png') # 예제 이미지
image = cv.resize(image, (0, 0), fx=0.25, fy=0.25, interpolation=cv.INTER_AREA)
height, width, channel = image.shape # 이미지의 높이, 너비, 채널 수
# 수평 이동
matrix = np.array([[1, 0, 50], [0, 1, 0]], dtype=np.float32) # x축으로 50픽셀 이동
translated = cv.warpAffine(image, matrix, (width, height)) # 이미지 이동
show(translated) # 이미지 출력
# 수직 이동
matrix = np.array([[1, 0, 0], [0, 1, 50]], dtype=np.float32) # y축으로 50픽셀 이동
translated = cv.warpAffine(image, matrix, (width, height)) # 이미지 이동
show(translated) # 이미지 출력
확대
wr = 2 # 가로는 2배
hr = 3 # 세로는 3배
matrix = np.array([[wr, 0, 0], [0, hr, 0]], dtype=np.float32)
resized = cv.warpAffine(
image,
matrix,
(width * wr, height * hr), # 새로운 크기
flags=cv.INTER_LANCZOS4) # 보간
회전
matrix = np.array([[0, -1, height], [1, 0, 0]], dtype=np.float32) # 90도 회전 행렬
resized = cv.warpAffine(
image,
matrix,
(height, width)) # 가로, 세로의 크기가 바뀜
회전 행렬 계산
center = width // 2, height // 2 # 이미지의 중심 좌표
angle = 45 # 회전 각도
ratio = 1 # 확대 비율
matrix = cv.getRotationMatrix2D(center, angle, ratio) # 회전 행렬 계산
rotated = cv.warpAffine(image, matrix, (width, height)) # 이미지 회전
show(rotated) # 이미지 출력

크기 맞추기 및 배경 채우기
cos = abs(matrix[0, 0])
sin = abs(matrix[0, 1])
new_width = int((height * sin) + (width * cos)) # 새로운 너비
new_height = int((height * cos) + (width * sin)) # 새로운 높이
image_center = (width // 2, height // 2) # 원본 이미지의 중심 좌표
matrix[0, 2] += (new_width / 2) - image_center[0] # 새로운 x좌표로 이동
matrix[1, 2] += (new_height / 2) - image_center[1] # 새로운 y좌표로 이동
rotated = cv.warpAffine(
image, matrix,
(new_width, new_height), # 새로운 크기
borderMode=cv.BORDER_CONSTANT, # 배경 색은 한 가지로
borderValue=image[0, 0].tolist()) # 왼쪽 위 (0, 0)의 픽셀 값으로 배경을 채움
변환 행렬에서 회전각 역산
회전 행렬의 성분은 회전각 와 확대 비율 scale로 다음처럼 표현할 수 있음
matrix[0, 0] == scale * cos θ
matrix[0, 1] == scale * sin θ
# np.arctan2(y, x)는 tan의 역함수
angle_rad = np.arctan2(matrix[0, 1], matrix[0, 0])
angle_deg = np.degrees(angle_rad)
- : 회전각
