이미지의 크기를 조절할때 가로세로 비율을 계산하고 조절했던것처럼 변환 및 회전도 이미지가 뒤틀리지 않게 조절을 해줘야한다.
먼저 imshow라는 함수를 만들어주고 이미지를 다운로드해준다.
변환 - Translations
이미지를 translation 하는 코드이다. 그냥 수평,수직이동 이다.
# Load our image
image = cv2.imread('images/Volleyball.jpeg')
imshow("Original", image)
# Store height and width of the image
# 영상의 높이 및 너비 저장
height, width = image.shape[:2]
# We shift it by quarter of the height and width
# 높이와 너비의 4분의 1로 이동합니다
quarter_height, quarter_width = height/4, width/4
# Our Translation
# | 1 0 Tx |
# T = | 0 1 Ty |
# T is our translation matrix
T = np.float32([[1, 0, quarter_width], [0, 1,quarter_height]])
# We use warpAffine to transform the image using the matrix, T
# warpAffine을 사용하여 행렬 T를 사용하여 영상을 변환합니다
img_translation = cv2.warpAffine(image, T, (width, height))
imshow("Translated", img_translation)
imshow를 통해 이미지를 불러왔고,
아래 image의 shape의 [:2] 를 가져오는데 image.shape[:2]의 뜻은
"이미지의 높이와 너비를 나타내는 튜플을 가져오는 것" 이다.
height, width = image.shape[:2]
이미지의 크기정보는 shape 속성에 저장돼있는데, 이 속성은 (높이, 너비, 채널) 형식의 튜플을 반환하는데, [:2]는 튜플의 처음 두 요소인 높이와 너비를 가져오게 되는것이다.
아래는 이미지의 높이와 너비의 1/4 값을 계산하여 변수에 할당
변수는 이미지 이동량을 나타낸다.
quarter_height, quarter_width = height/4, width/4
이미지 이동에 사용될 변환 행렬(T)인데, x축과 y축 각각으로 quarter_width와 quarter_height 만큼 이동하도록 설정
T = np.float32([[1, 0, quarter_width], [0, 1,quarter_height]])
Tx(quarter_width)는 수평이동, Ty(quarter_height) 는 수직이동 의 값을 나타내는데,
앞에 1,0은 뭘까 알아보기 위해 행렬을 다시보자
[[a, b, Tx],
[c, d, Ty]]
a와 d는 크기를 조절하는 요소
b와 c는 이미지의 회전을 담당하는 요소
이때 a,d는 각각 1로 나와있고 크기를 변경하지 않으니까 맞다.
b,c는 회전을 담당하는 요소인데, 일반적으로 이미지 이동에는 사용되지 않고 보통 이 값들은 0으로 설정된다한다.
img_translation = cv2.warpAffine(image, T, (width, height))
warpAffine 라는 함수를 사용하여 이미지를 변환하는데 변환 행렬(T)를 인자로 받아 이동시키는데, 뒤에 이미지 원본의 너비와 높이도 같이 들어가게된다.
이는 변환된 이미지의 크기가 원본 이미지와 동일하도록 설정하는 것
위의 코드를 한줄로 풀어보면
"이동 행렬(T)을 사용하여 이미지를 변환하고, 그 결과로서 지정된 크기(원본)의 이미지를 반환"
이 코드들을 실행했을때, T만큼 이동한 이미지와 원본이 함께 출력되는데
이미지는 1300x720 정도의 크기이고 1/4을 했을때 330,180 만큼 이동을 해야하는데
선을 그어봤을때 해당 수치만큼 이동한것을 볼 수 있다.
검증을 위해 정확한 T와 높이, 너비를 출력을 해보자
눈대중과 비슷하다.
회전 - Rotations
이동은 warpAffine라는 함수를 사용했고
회전은 getRotationMatrix2D 라는 함수를 이용한다.
사용법은 cv2.getRotationMatrix2D(rotation_center_x, rotation_center_y, angle of rotation, scale)으로
인자는 총 4가지로 angle of rotation은 움직일 각도 scale은 크기, 비율을 의미하는데 앞에 rotation_center는 말 그대로 회전하는 이미지의 중심을 잡아주는것이다.
선택한 중점으로 입력한 각도값 만큼 회전시킨다는 뜻이다. 양수는 시계방향 음수는 반시계 방향으로 회전
당연히 이미지의 중심을 중점으로 잡으려고하니 (너비/2, 높이/2) 가 이미지의 중점이 된다.
예제 코드는 아래와 같다.
# Divide by two to rototate the image around its centre
# 영상을 중심을 중심으로 회전시키기 위해 두 개로 나눕니다
rotation_matrix = cv2.getRotationMatrix2D((width/2, height/2), 90, 0.5)
print(rotation_matrix)
# Input our image, the rotation matrix and our desired final width and height
# 이미지, 회전 매트릭스 및 원하는 최종 너비 및 높이를 입력합니다
rotated_image = cv2.warpAffine(image, rotation_matrix, (width, height))
imshow("Rotated 90 degrees with scale = 0.5", rotated_image)
결과부터 보면
getRotationMatrix2D 함수를 사용하는데 중점을 설정해주고, 90도를 이동하고 이미지의 비율은 0.5으로설정했다.
rotation_matrix = cv2.getRotationMatrix2D((width/2, height/2), 90, 0.5)
만약 scale = 1로 하면?
이미지가 밖으로 나간다.
그래서 전체 이미지를 프레임에 유지하고 싶다면 scale을 설정해줘야한다.
사용법을 보면 Matrix에 대한 내용도 나오게 되는데
Matrix인 rotation_matrix 의 값을 출력해보면
[[ 3.061617e-17 5.000000e-01 4.600000e+02]
[-5.000000e-01 3.061617e-17 6.800000e+02]]
이렇게 값이 출력이 되는데 이 값을 통해 얼만큼 어느방향으로 회전했는지 알수있다.
그러면 반대로 matrix를 통해서 회전각도를 알아보자.
아래는 matrix를 arctan2를 사용해서 각도를 알아보는건데
import numpy as np
# 주어진 회전 변환 행렬
rotation_matrix = np.array([[3.061617e-17, 5.000000e-01, 4.600000e+02],
[-5.000000e-01, 3.061617e-17, 6.800000e+02]])
# 회전 각도 계산
rotation_angle = np.arctan2(rotation_matrix[1, 0], rotation_matrix[0, 0])
# 각도를 라디안에서 도로 변환
rotation_angle_degrees = np.degrees(rotation_angle)
print("회전 각도:", rotation_angle_degrees)
결과가 -90이 나왔다.
회전 각도: -90.0
이것은 actan2함수의 특성 때문이라, actan2의 -90도가 나왔다는 뜻은 회전 방향이 시계방향으로 90도 회전하였다는것을 나타내는것이므로 위의 이미지를 시계방향으로 회전시킨 90도가 나오는것과 동일하다.
지금 회전시킨 이미지를 보았을땐 검은 부분이 많은데 변환된, 회전된 이미지에 맞게 프레임을 맞추는것도 해보자.
정의는 이미지나 행렬의 전치(transpose)를 수행하는 함수
전치란 행렬의 행과 열을 서로 바꾸는것을 말한다.
한마디로 회전했다라는 개념보다는 행과열을 바꿧다라는것이 맞다.
한번 전치했을때,
rotated_image = cv2.transpose(image)
imshow("Original", image)
imshow("Rotated using Transpose", rotated_image)
두번 전치했을때,
rotated_image = cv2.transpose(image)
imshow("Rotated using Transpose", rotated_image)
rotated_image = cv2.transpose(rotated_image)
imshow("Rotated using Transpose", rotated_image)
당연히 두번 전치했을때에는 원본 이미지와 같아진다.
이미지나 동영상을 좌우로 또는 상하로 뒤집는 데 사용되는 함수이고
flipped_image = cv.flip(image, flipCode)
인자는 이미지와 flipcode이다.
flipcode의 값은 3가지가 존재한다.
이미지와 목적에 맞는 코드를 입력하면 이미지가 변환되는것으로
세가지 모두 출력해보자.
# 수평 방향으로 뒤집기
flipped = cv2.flip(image, 1)
imshow("Horizontal Flip", flipped)
# 수직 방향으로 뒤집기
flipped = cv2.flip(image, 0)
imshow("Vertical Flip", flipped)
# 수평 및 수직 방향으로 동시에 뒤집기
flipped = cv2.flip(image, -1)
imshow("Horizontal and Vertical Flip", flipped)
양수일땐 수평 반전
0일땐 수직반전
음수일땐 수평,수직 반전으로 옳게 출력이됐다.