import numpy as np
import cv2
import matplotlib.pyplot as plt

2D 이미지 기하학적 변형 (Transformation) → 행렬변환

1. 강체변환 (Ridid-Body) : 크기와 형태를 유지한 채 위치와 방향을 바꾸는 변환 (ex. 위치변경(Translation), 회전(Rotation)) 2. 유사변환 (Similarity) : 강체변환에 크기의 변환도 허용 (ex. 크기변경(Scaling))
3. 선형변환 (Linear) : Vector 공간에서의 이동. (회전, 크기변경 및 반전, 밀림도 가능하지만 위치변경은 못한다.)
4. Affine : 선형변환과 이동변환까지 포함. 선의 수평성은 유지
5. Perspective : Affine 변환에서 수평성이 유지되지 않음 (원근변환)

 


1. Scaling

cv2.resize(src, dsize [, dst [, fx [, fy [, interpolation]]]]) -> dst

이미지 크기 변환 기능을 제공하는 함수 
1. src : 입력 이미지 
2. dsize : 출력 이미지 크기를 픽셀로 지정. 만약 0, None으로 지정하면 fx, fy, 입력이미지의 크기에 따라 다음과 같이 계산한다.
    ( dsize = Size(round(fx*src.cols), round(fy*src.rows)) )

3. fx : 가로 방향의 배율 인자를 지정.  만약 0으로 지정하면 dsize와 입력이미지의 크기에 따라 다음과 같이 계산한다.  
4. fy : 세로 방향의 배율 인자를 지정. 만약 0으로 지정하면 dsize와 입력이미지의 크기에 따라 다음과 같이 계산한다. 
    ( fx = (double) dsize.width / src.cols )
    ( fy = (double) dsize.height / src.rows )
위 같은 조건 때문에 dsize 혹은 fx와 fy가 모두 0 이어서는 안된다.

★★ interpolation (보간법, 내간법) : 이미지의 크기를 조정할 때 발생하는 문제는 이미지를 축소할 때 픽셀값이 누락되거나 이미지를 확대할 때 그 사이를 매꿔줄 픽셀값이 아예 존재하지 않는다는 것이다. 이런 문제를 해결하기 위한 방법으로 openCV는 다양한 interpolation 알고리즘을 제공하고 있다. 
1. cv2.INTER_NEAREST 
2. cv2.INTER_LINEAR 
3. cv2.INTER_CUBIC 
4. cv2.INTER_AREA 
5. cv2.INTER_LANCZOS4 
6. cv2.INTER_LINEAR_EXACT 
7. cv2.INTER_MAX 
8. cv2.WARP_FILL_OUTLIERS 
9. cv2.WARP_INVERSE_MAP 
cv::InterpolationFlags 참고
일반적으로 이미지를 축소할 때는 INTER_AREA 알고리즘을, 이미지를 확대할 때는 INTER_CUBIC(느림, 정확도 높음), INTER_LINEAR(빠름, 정확도 낮음)을 사용하는 것을 추천한다.

img = cv2.imread('The-original-Gaussian-noisy-image-The-Gaussian-noise-parameters-are-zero-mean-and.png')
height, width = img.shape[:2]

# 이미지 축소
shrink = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA)

# Manual Size 지정
zoom1 = cv2. resize(img, (width*2, height*2), interpolation=cv2.INTER_CUBIC)

# 배수 Size 지정
zoom2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)

cv2.imshow('Original', img)
cv2.imshow('Shrink', shrink)
cv2.imshow('Zoom1', zoom1)
cv2.imshow('Zoom2', zoom2)
cv2.waitKey(0)
cv2.destroyAllWindows()

titles = ['Original', 'Shrink', 'zoom1', 'zoom2']
images = [img, shrink, zoom1, zoom2]

plt.figure(figsize=(8, 8))
for i in range(4):
    plt.subplot(2, 2, i+1)
    plt.title(titles[i])
    plt.imshow(images[i])

plt.tight_layout()
plt.show()

 


2.Translation (위치변경)

Translation은 이미지의 모든 픽셀을 x, y 방향으로 일정한 양만큼 이동시키는 과정이며 그 가운데 크기와 형태가 변하지 않으므로 강체변환(Ridid Transformation)이다. openCV에서는 강체변환, 유사변환, 선형변환을 모두 포함하는 아핀 변환을 사용하여 이미지를 변환시키는 함수를 제공하고 있다. 이 이미지를 이동시키기 위해서는 cv2.wrapAffine() 함수를 사용해야 한다.

Affine Transformation(아핀 변환) : 2차원 이미지와 변환을 위한 Affine Transform 행렬이 존재한다고 하자. 원본 이미지의 (x, y)의 이동, 회전 및 크기 등의 변화를 거친 후 표현되는 (x^, y^)이 있을 때, 이 둘 사이의 관계를 나타낼 때 Affine Transform 행렬이 사용된다. 이 Affine Transformation 방법으로 회전, 크기변경, 평행이동, 반전 및 밀어내기 등이 가능하다.
        [x^] = [ a, b ][ x ] + [ e ]
        [y^] = [ c, d ][ y ] + [ f ]

openCV에서는 아핀 변환을 수행하는 함수가 cv2.warpAffine, cv2.getRotationMatrix2D 로 총 2가지 함수가 있는데, 전자의 경우에는 주어진 인자들을 바탕으로 아핀 변환을 수행하고, 후자의 경우 2 * 3 크기의 회전 행렬을 얻을 수 있다.

 

cv2.warpAffine(src, M, dsize [, dst [, flags [, borderMode [, borderValue]]]]) → dst

이미지에서 아핀 변환을 적용하는 함수이다. 
1. src : 입력 이미지
2. M : 2 * 3 크기의 변환 행렬
3. dsize : 출력 이미지 크기

openCV에서 이동을 위한 변환 행렬은 다음과 같이 정의할 수 있다.
        [ 1, 0, X ]
        [ 0, 1, Y ]
이때, X, Y는 이미지를 이동할 픽셀 단위의 크기이다. 이미지 이동은 좌상단에서 가로방향으로 X만큼, 세로방향으로 Y만큼 움직인다. 이렇게 만들어진 이동 변환 행렬을 warpAffine 함수의 인자로 전달하면 아핀 변환을 적용하여 이미지를 X, Y만큼 이동시키게 된다.

img = cv2.imread('The-original-Gaussian-noisy-image-The-Gaussian-noise-parameters-are-zero-mean-and.png')
rows, cols = img.shape[:2]

# 변환 행렬, X축으로 10, Y축으로 20 이동
M = np.float64([[1, 0, 100], [0, 1, 200]])
dst = cv2.warpAffine(img, M, (cols, rows))

cv2.imshow('Original', img)
cv2.imshow('Translation', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.imshow(img)
plt.title('Image')

plt.subplot(1, 2, 2)
plt.imshow(dst)
plt.title('Translation')
plt.tight_layout()
plt.show()

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기