어파인 변환 : 영상을 평행 이동시키거나 회전, 크기 변환, 전단 변환 등을 통해 만들 수 있는 변환을 통칭한다.
영상에서 어파인 변환을 적용할 경우, 직선은 그대로 직선으로 나타나고, 직선 간의 길이 비율과 평행 관계가 그대로 유지된다. 어파인 변환에 의해 직사각형 영상은 평행 사변형 형태로 변환될 수 있다.
어파인 변환은 여섯 개의 파라미터를 이용한 수식으로 정의할 수 있다. 어파인 변환에 의해 입력 영상의 좌표가 (x, y)가 결과 영상의 좌표(x’, y’)으로 이동하는 결과는 다음과 같은 어파인 변환 행렬로 표현된다.
어파인 변환 행렬을 알기 위해서는 적어도 3개의 점을 알아야한다. 그리고 어파인 변환은 점 세 개의 이동관계만 정의할 수 있다.
from __future__ import print_function
import cv2 as cv
import numpy as np
src = cv.imread(cv.samples.findFile('lena.jpg'))
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
srcTri = np.array( [[0, 0], [src.shape[1] - 1, 0], [0, src.shape[0] - 1]] ).astype(np.float32)
dstTri = np.array( [[0, src.shape[1]*0.33], [src.shape[1]*0.85, src.shape[0]*0.25], [src.shape[1]*0.15, src.shape[0]*0.7]] ).astype(np.float32)
warp_mat = cv.getAffineTransform(srcTri, dstTri)
warp_dst = cv.warpAffine(src, warp_mat, (src.shape[1], src.shape[0]))
# Rotating the image after Warp
center = (warp_dst.shape[1]//2, warp_dst.shape[0]//2)
angle = -50
scale = 0.6
rot_mat = cv.getRotationMatrix2D( center, angle, scale )
warp_rotate_dst = cv.warpAffine(warp_dst, rot_mat, (warp_dst.shape[1], warp_dst.shape[0]))
cv.imshow('Source image', src)
cv.imshow('Warp', warp_dst)
cv.imshow('Warp + Rotate', warp_rotate_dst)
cv.waitKey()
https://docs.opencv.org/3.4/d4/d61/tutorial_warp_affine.html
투시 변환(perspective transform) : 직사각형 형태의 영상을 임의의 볼록 사각형 형태로 변경할 수 있는 변환이다.
투시 변환은 grid의 평행 상태가 유지되지 않기 때문에 결과 영상의 형태가 임의의 사각형으로 나온다.
점 하나의 이동관계로부터 x 좌표에 대한 방정식 하나와 y 좌표에 대한 방정식 하나를 얻을 수 있기 때문에 점 네개의 이동 관계로부터 여덟 개의 방정식을 얻을 수 있게 된다.
이 여덟 개의 방정식으로부터 투시 변환을 표현하는 파라미터 정보를 계산할 수 있다.
투시 변환은 보통 3 x 3 크기의 실수 행렬로 표현한다.
투시 변환은 여덟 개의 파라미터로 표현할 수 있지만, 좌표 계산의 편의상 아홉 개의 원로를 갖는 3 x 3 행렬을 사용한다.
입력 영상의 픽셀 좌표 (x, y)가 투시 변환을 표현하는 행렬에 의해 이동하는 결과 영상 픽셀 좌표 (x’, y’)는 다음과 같이 계산된다.
행렬 수식에서 입력 좌표와 출력 좌표를 (x, y, 1), (wx’, wy’, w) 형태로 표현한 것을 동차 좌표계(homogeneous coordinates)라고 하며, 좌표 계산의 편의를 위해 사용하는 방식이다.
w는 결과 영상의 좌표를 표현할 때 사용되는 비례 상수이다.
import numpy as np
import cv2
# read input
img = cv2.imread("sudoku.jpg")
# specify desired output size
width = 350
height = 350
# specify conjugate x,y coordinates (not y,x)
input = np.float32([[62,71], [418,59], [442,443], [29,438]])
output = np.float32([[0,0], [width-1,0], [width-1,height-1], [0,height-1]])
# compute perspective matrix
matrix = cv2.getPerspectiveTransform(input,output)
print(matrix.shape)
print(matrix)
# do perspective transformation setting area outside input to black
imgOutput = cv2.warpPerspective(img, matrix, (width,height), cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(0,0,0))
print(imgOutput.shape)
# save the warped output
cv2.imwrite("sudoku_warped.jpg", imgOutput)
# show the result
cv2.imshow("result", imgOutput)
cv2.waitKey(0)
cv2.destroyAllWindows()
https://stackoverflow.com/questions/63954772/perspective-transform-in-opencv-python