image transform 이란 원본 이미지를 회전, 이동, 확대, 축소 하여 변환 이미지를 만드는 과정을 의미하며,
특히 Forward warping 이란 픽셀값(0~255) 또는 픽셀 좌표값 (x,y) 하나하나를 변환하여 새로운 이미지에 붙여주는 과정을 의미한다. 가령 코드는 다음과 같다.
for y in range(h):
for x in range(w):
new_x = np.int(np.cos(theta) * (x-ww) - np.sin(theta) * (y-hh))+ww
new_y = np.int(np.sin(theta) * (x-ww) + np.cos(theta) * (y-hh))+hh
# 변환 행렬 계산 수행
if new_x < 0 or new_x >= w or new_y < 0 or new_y >= h:
continue
new_gray[new_y, new_x] = gray[y, x]
그런데 단순히 Forwad warping 을 적용하게 되면, 이미지를 확대 / 축소 할 때, 이미지를 rotation 할 때 Black Hole 문제가 생기게 된다. 이는 다음과 같은 이유 때문이다.
point rich 한 이미지(= 원본 이미지, 모든 픽셀 좌표에 픽셀값이 존재하는 이미지를 의미함)
(x, y) 픽셀값 가져옴
(x, y)에 변환행렬 적용해서 (new_x, new_y) 구함
x,y 로 부터 new_x, new_y 를 계산후에 int 타입으로 변환하는 과정이 수반
완벽하게 1:1로 매칭되는 값이 new_x, new_y 존재한다는 보장이 없음.
같은 픽셀 좌표가 구해지는 존재하는 경우 완벽하게 메꾸는 것이 불가능
예를 들어 원본 포인트가 인 지점을 roatation 변환했더니 였고, 인 점을 rotation 변환했더니 이었다 가정하자. 모두 int 로 변환시 로 변환된다. 즉 원본 이미지와 1:1 매칭이 되지 않는 지점이 생긴다는 것이다.

BackWard Warping 은 반대로 변환된 이미지를 원본 이미지라고 생각하고, 원본이미지를 변환 이미지라고 생각한다. 그래서 변환 이미지의 픽셀 하나하나에 원래의 변환 행렬의 역 행렬을 곱해, 그 값이 원본이미지에 대응하는 값이라고 처리해준다. 가령 아래와 같은 방식이다.
def rotation(self, img, r):
''' code here '''
src = img
img_h, img_w, img_channel = src.shape
center_h, center_w = np.int(img_h/ 2), np.int(img_w/2)
img_result = np.zeros((img_h, img_w, img_channel), src.dtype)
theta = - r * np.pi /180.0 # 내가 회전 시키고자 하는 각도는, 반시계방향일 경우 (-) 로, 시계방향일 경우 (+) 로 받아와야 합니다.
for y in range(img_h):
for x in range(img_w):
new_x = int((np.cos(theta) * (x - center_w) + np.sin(theta) * (y - center_h) ) + center_w)
new_y = int((-np.sin(theta) * (x - center_w) + np.cos(theta) * (y - center_h)) + center_h)
# backward 로 계산하기 위해, 회전된 이미지를 원본으로, 원본 이미지를 변환 이미지로 생각했습니다.
# 회전된 이미지로 부터 로테이션 매트릭스의 역행렬을 곱해 new_x, new_y 라는 원본 이미지 상의 대응 되는 좌표를 찾습니다.
# 원본이미지는 모든 픽셀 좌표에서 rgb 값을 가지고 있기 때문에, 어떤 new_x, new_y 좌표에서든지 색상 정보를 가져올 수 있습니다.
# 그래서 검은색 홀이 생기지 않게 될 것입니다.
if new_x < 0 or new_x >= img_w or new_y < 0 or new_y >= img_h:
continue
img_result[y,x] = src[new_y, new_x]
return img_result
