[openCV] Image Geometric Transformation (1)
openCV

[openCV] Image Geometric Transformation (1)

오늘은 openCV에서 이미지의 기하학적 변환에 대해서 정리를 해보려고 한다.

 

사실 제목에서도 알 수 있듯이 기하학적인 요소가 들어가 있어서

함수에 대해서 심화적인 이해를 하기 위해서는

수학에 대한 조금의 선수지식이 필요하다.

 

수학 어려워

 

0. 행렬의 필요성

 

github.com/ndb796/Python-Data-Analysis-and-Image-Processing-Tutorial.git

 

 

ndb796/Python-Data-Analysis-and-Image-Processing-Tutorial

파이썬을 활용한 데이터 분석과 이미지 처리 - 강의 자료 및 소스코드 Repository입니다. - ndb796/Python-Data-Analysis-and-Image-Processing-Tutorial

github.com

행렬의 필요성을 읽어보자

깔끔하게 정리를 잘 해놓으셨다👻

 

1. Rotation

 

이미지를 회전할 때 회전 행렬을 사용하게 된다.

 


회전횡렬이란?

 

2차원의 회전 횡렬

오른쪽은 회전 후 좌표가 되는 값들이다.

[x' (회전된 x좌표), y' (회전된 y좌표), 1 (2차원 평면이므로 1)]

 

회전된 좌표를 구하는 방법은 왼쪽의 vecter와 가운데의 행렬을 곱해주면 된다.

 

vector의 방향이 세로이므로 행렬은 그에 대비되는 방향으로 곱해주자.

 

그러면 이런식으로 최종 식이 나온다.

 

x' (회전된 x좌표) = xCosθ - ySinθ

y' (회전된 y좌표) = xSinθ + yCosθ

 

이걸 실제로 2차원 평면에 공식을 유도해보면

 

회전행렬

이런식으로 나오게 된다.

 

www.youtube.com/watch?v=OVPyMijFiEQ&ab_channel=%ED%8C%8C%EA%B9%A8%EB%B9%84TV

 

참고하면 그뤠잇😦


getRotationMatrix2D 회전 행렬

openCV에서는 getRotationMatrix2D 함수를 사용하여서 위와 같은 회전 행렬을 생성하고

warpAffine 함수를 사용하여서 이미지에 회전 변환을 적용한다.

 

getRotationMatrix2D 함수는 배율 및 회전 중심 좌표가 추가된 회전 행렬을 사용한다.

 

코드를 살펴보자

 

import cv2
import imutils

img_color = cv2.imread("./cat.jpg")

img_color = imutils.resize(img_color, width=500, height=500)

cv2.imshow("Cuttyyyyyyy", img_color)

height, width = img_color.shape[:2]

M = cv2.getRotationMatrix2D((width / 2.0, height / 2.0), 45, 1)

print(type(height), width)

img_rotated = cv2.warpAffine(img_color, M, (width, height))

cv2.circle(img_rotated, (int(height / 2.0) , int(width / 2.0)), 3, (0, 255, 0), -1)

cv2.imshow("rotation", img_rotated)
cv2.waitKey(0)

cv2.destroyAllWindows()

 

하나하나 뜯어서 보자

 

height, width = img_color.shape[:2]

M = cv2.getRotationMatrix2D((width / 2.0, height / 2.0), 45, 1)

 

cv2.getRotationMatrix2D( CenterPosition, Rotation Angle, Magnification Of Image (scale) )

 

CenterPosition = 회전 할 때 중심

Rotation Angle = 회전할 각도Magnification Of Image = 이미지 배율 ( 1이면 이미지의 원래 크기 )

 

 

위의 Argument를 참고해보면

image의 중심이 회전의 중심점이 되며, 45도 만큼 회전하고, 이미지의 원래 크기 만큼

출력한다는 정보가 들어가있는 회전 행렬을 만들게 된다.

 

img_rotated = cv2.warpAffine(img_color, M, (width, height))

 

cv2.warpAffine( src, M, dsize )

 

src = 회전행렬을 적용할 Image

M = cv2.getRotationMatrix2D를 활용하여 생성된 변환 행렬

dsize = Image 출력 사이즈

 

[ Result ]

 

Original Image
Rotation Image

 

 

2. Scaling

 

Scaling

S(x, y) :  사용자 지정 이미지 변환 값

 


x' = x * S(x)

y' = y * S(y)


코드를 살펴보기 전에  Interpolation (보간법)을 알아보자

 

openCV에서 Image를 Resize하는데 6가지의 Interpolation이 쓰인다

 

Interpolation은 픽셀로 이루어진 이미지를 사이즈를 키울 때 어떤 픽셀을 넣을지,

크기를 줄일 경우에는 손실되는 픽셀을 어떻게 선정하는지에 대한 방법이다.

 


이미지를 확대할 때 많이 사용하는 Interpolation

 

cv2.INTER_CUBIC : 바이큐빅 보간법

cv2.INTER_LINEAR : 쌍 선형 보간법

 

이미지를 축소할 때 많이 사용하는 interpolation

 

cv2.INTER_AREA : 영역 보간법


사실 Interpolation은 저것 외에도 굉장히 종류가 많아서

나중에 한번 정리를 해볼려고 계획하고 있는 중이다

 

 

이제 코드를 살...펴보자..

 

import cv2
import imutils

img_color = cv2.imread('cat.jpg')
img_color = imutils.resize(img_color, width=500, height=500)

cv2.imshow("Cuttyyyy", img_color)

img_result = cv2.resize(img_color, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
cv2.imshow("x2 INTER_CUBIC", img_result)

height, width = img_color.shape[:2]

img_result = cv2.resize(img_color, (3 * width, 3 * height), interpolation=cv2.INTER_LINEAR)
cv2.imshow("x3 INTER_LINEAR", img_result)

img_result = cv2.resize(img_color, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
cv2.imshow('x0.5 INTER_AREA', img_result)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

cv2.resize( img, dsize, fx, fy, interpolation )

 

img = 확대, 축소할 이미지

dsize = 이미지를 확대, 축소를 할 width, height 값 지정

fx, fy = 만약 dsize가 None이라면 원본 이미지의 상대적인 크기 지정 가능

interpolation = 보간법 선택

 

img_result = cv2.resize(img_color, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
cv2.imshow("x2 INTER_CUBIC", img_result)

현재 disize가 None이므로 fx, fy에 2를 넣어서 원본 이미지의 2배로 만들어줬다.

 

원본 이미지에 2배가 되는 것은 확대를 의미하므로 interpolation은 cv2.INTER_CUBIC을 지정했다.

 

img_result = cv2.resize(img_color, (3 * width, 3 * height), interpolation=cv2.INTER_LINEAR)
cv2.imshow("x3 INTER_LINEAR", img_result)

이건 위의 코드와 다르게 dsize를 지정해준것이다.

 

원본 이미지에 width, height에 3을 곱해주므로 3배가 된다.

 

interpolation은 cv.INTER_LINEAR로 지정한다.

 

img_result = cv2.resize(img_color, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)
cv2.imshow('x0.5 INTER_AREA', img_result)

이건 원본 이미지를 축소하는 코드이다.

 

interpolation은 cv2.INTER_AREA로 지정했다.

 

[ Result ]

 

Original
x2
x3
x0.5

x3배는 너무 커서 화면에 안들어오지만 직접 해보면 차이를 알 것이다.

 

사실 난 cv2.resize()는 잘 안쓴다.

왜냐하면 Argument 자체가 너무 복잡하고

 

우리에겐 너무나 편한 imutils.resize()가 존재하기 때문이다.

 

 

3. Translation

 

이동 행렬은 이렇게 정의할 수 있습니다

 

T(x,y) = 사용자 지정 Postion

 

x' = x + T(x)

y' = y + T(y)

 

바로 코드로 넘어가보자

 

import cv2
import numpy as np 
import imutils

img_color = cv2.imread('cat.jpg')
img_color = imutils.resize(img_color, width=500, height=500)
cv2.imshow("Cuttyyy", img_color)

height, width = img_color.shape[:2]

M = np.float32([[1, 0 ,100], [0, 1, 50]])

img_translation = cv2.warpAffine(img_color, M, (width, height))
cv2.imshow("translation", img_translation)

cv2.waitKey(0)
cv2.destroyAllWindows()

하나 하나 보자

M = np.float32([[1, 0 ,100], [0, 1, 50]])

numpy 배열을 활용해서 변환행렬을 만들어 주었다.

 

M = [1, 0, 100 = T(x)]

      [0, 1, 50 = T(y)]

 

굳이 위 사진과 같이 표현을 해보자면 이런 식이 되는거다.

 

그럼 x' = x + 100이 되며

y' = y + 50이 되는 것이다.

 

그럼 x 좌표로 +100 이동하며

y 좌표로 +50 이동할 수 있다.

img_translation = cv2.warpAffine(img_color, M, (width, height))

이건 위에서도 했으니 큰 설명은 하지 않겠다.

 

[ Result ]

 

Original Image
Translate

 

 

오늘은 내용이 너무 길어져 다음에 이어서 정리를 해야겠다ㅏ🙄

 

수학 열심히 해야겠다...

 

오늘도 끄-읕😶

'openCV' 카테고리의 다른 글

[openCV] Convolution & Mask (1)  (0) 2021.03.06
[openCV] Image Geometric Transformation (2)  (0) 2021.02.21
[openCV] ROI  (0) 2021.02.17
[openCV] Draw Function  (0) 2021.02.06
[ openCV ] Image Operation ( Blending, Operate Image Bit, ROI )  (0) 2021.02.02