< 4-3. Geometric Transformations of Images >
이미지를 변형시키는 다른 기하학적인 방법인 translation, rotation, affine transform 등에 대해서 배워볼 것이다.
- cv2.getPerspectiveTransform() 함수에 대해 볼 것이다.
Transformations
OpenCV는 두 가지 변형 함수 cv2.warpAffine과 cv2.warpPerspective를 제공합니다. cv2.warpPerspective가 3x3 변환 매트릭스를 입력으로 받을 때, cv2.warpAffine은 2x3 변환 매트릭스를 받는다.
Scaling
스케일링은 그저 이미지를 resizing하는 것이다. OpenCV는 이러한 목적으로 cv2.resize 함수가 제공된다. 이미지의 크기는 수동으로 조절하거나, 스케일링 계수를 지정할 수 있다. 서로다른 보간법이 사용된다. 선호되는 보간법은 줄이기 위한 cv2.IMTER_AREA, cv2.INTER_CUBIC(느리다) & 확대/축소를 위한cv2.INTER_LINEAR을 사용한다. 기본적으로 사용되는 보간법은 모든 resizing 목적을 위한 cv2.INTER_LINEAR이다. 아래의 방법을 따라서 입력 이미지의 크기를 조정할 수 있다.
import numpy
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('golden.jpg')
print("기존 크기 : ",img.shape)
# 두 배로 만들기
res = cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
# or
height, width = img.shape[:2]
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
plt.imshow(res[:,:,::-1])
plt.show()
Translation
평행 이동은 물체의 위치를 이동시키는 것이다. (x,y) 방향의 이동을 알고있는 경우
np.float32 유형의 Numpy 배열을 만들어 cv2.warpAffine() 함수에 전달하면 된다. (100,50) 이동은 아래의 예를 보자
img = cv2.imread('golden.jpg')
rows,cols = img.shape[0], img.shape[1]
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
plt.imshow(dst[:,:,::-1])
plt.show()
가로로 100, 세로는 50만큼 이동시킨 것을 볼 수 있다.
- 폭 = cols의 수, 그리고 높이 = rows의 수인 것을 기억하자!
Rotation
각도 θ 에 대한 이미지 회전은 아래의 매트릭스 형태로 이뤄진다.
M=[cosθsinθ−sinθcosθ] 하지만 OpenCV는 원하는 위치에서 회전할 수 있도록 조정 가능한 회전 중심과 함께 스케일링된 회전을 제공한다. 수정된 변환 매트릭스는 다음과 같다.
[α−ββα(1−α)⋅center.x−β⋅center.yβ⋅center.x−(1−α)⋅center.y] α:scale⋅cosθ,
β:scale⋅sinθ
이 변환 매트릭스를 찾기 위해서, OpenCV는 cv2.getRotationMatrix2D 함수를 제공한다. 아래의 예를 보고, 아무런 스케일링 없이 중심에 대해 90도 회전한 것을 볼 수 있다.
img = cv2.imread('golden.jpg')
rows,cols = img.shape[0], img.shape[1]
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(img,M,(cols,rows))
plt.imshow(dst[:,:,::-1])
plt.show()
Affine Transform
Affine Transform에서는, 원본 이미지에서의 평행선이 결과 이미지에서 여전히 평행해야한다. 변환 매트릭스를 찾기 위해서는, 입력 이미지로부터 3 점 그리고 그에 대응하는 출력 이미지에서의 위치를 필요로한다. cv2.getAffineTransform은 2x3 매트릭스를 만들어 cv2.warpAffine에 전달할 것이다.
아래 예를 보자, 그리고 선택한 점 또한 확인하자.
img = cv2.imread('golden.jpg')
rows,cols,channels = img.shape
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(cols,rows))
plt.subplot(121), plt.imshow(img[:,:,::-1]), plt.title('input')
plt.subplot(122), plt.imshow(dst[:,:,::-1]), plt.title('Output')
plt.show()
Perspective Transformation
관점 변환에서는, 3x3 변환 매트릭스가 필요하다. 직선은 변환 후에도 직선으로 유지될 것이다. 이 변환 매트릭스를 찾으려면 입력 이미지에서 4개의 점과 출력 이미지에서 해당 포인트가 필요하다. 이 4점 중 3점은 동일 직선 상에 있으면 안된다. 그리고 cv2.getPerspectiveTransform 함수에 의해 변환 행렬을 찾을 수 있다. 그런 다음 이 3x3 변환 매트릭스를 사용하여 cv2.warpPerspective를 적용하면 된다.
img = cv2.imread('paper.jpg')
rows,cols,channels = img.shape
pts1 = np.float32([[0,200],[725,210],[5,1300],[900,1250]])
# Outputs 크기
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()