Affine 변환이란?

Affine 변환은 선형 변환 중 하나로 점, 직선, 평면을 보존하며, 변환후에도 평행성이 보존되는 특징을 가지고 있다.

Affine 변환을 통해 표현할 수 있는 변환은 다음과 같다.

  • 회전
  • 이동
  • 확대 / 축소
  • 반전
  • 전단(Shearing)

Affine 변환은 일반적으로 2*3행렬을 사용하며 두 이미지의 관계를 표현한다. 그 내용은 다음과 같다.

자세한 내용은 이전에 작성한 OpenGL의 매트릭스와 비슷한 내용이므로 생략한다.

OpenCV에서는 warpAffine()을 사용하여 affine 변환을 할 수 있다.

warpAffine(Mat src, Mat dst, Mat M, Size dsize)
src : 원본 이미지
dst : 결과 이미지
M : 변환 행렬
dsize : 결과 영상 크기. (0,0)이면 원본과 같은 사이즈로 지정

변환 행렬의 요소들을 직접 입력하여 결과를 볼 수 있는 화면을 먼저 준비한다. (소스코드)

이동 변환

이미지를 가로 또는 세로 방향으로 특정 크기 만큼 이동시켜보자

x축으로 100만큼, y축으로 200만큼 이동한 결과는 다음과 같다.

전단 변환

좌표평면상에서 고정된 방향으로 각 포인트를 그 방향과 평행한 라인에서 부호가 있는 거리에 비례하는 양만큼 이동시키는 선형 변환방법이다.

Mesh Shear 5/4

수평과 수직 전단은 다음과 같은 표현식으로 나타낸다.

수평전단

수직전단

수평 전단변환 예제를 살펴보자

확대/축소 변환

영상의 크기를 원본의 영상보다 크게 또는 작게 만드는 변환이다.

x축 또는 y축 방향으로 스케일 비율을 지정할 수 있다.

Sx = 1, Sy = 1로 지정하면 원본 비율로 나오고
Sx = 2, Sy = 2로 지정하면 2배 확대 된 이미지를 얻는다.
Sx = 0.5, Sy = 0.5로 지정하면 0.5배 확대된 이미지를 얻는다.

warpAffine함수와 변환행렬을 통해 이미지를 확대/축소 할수도 있지만, OpenCV에서는 resize 함수를 별도로 제공한다.

resize(Mat src, Mat dst, Size dsize, double fx, double fy, int interpolation)
src : 원본 영상
dst : 결과 영상
dsize : 결과 영상 크기. (0,0)으로 지정하면 fx,fy 값을 이용하여 결정
fx,fy : x와 y 방향으로의 scale factor
interpolation : 보간법, 기본값은 INTER_LINEAR

보간법에는 몇가지 종류가 있다.

INTER_NEAREST : 최근방 이웃 보간법
INTER_LINEAR : 양선형 보간법 (2×2 이웃 픽셀 참조)
INTER_CUBIC : 3차회선 보간법  (4×4 이웃 픽셀 참조)
INTER_LANCZOS4 : Lanczos 보간법 (8×8 이웃 픽셀 참조)
INTER_AREA : 영상 축소 시 효과적

이미지의 해상도 그리고 보간법에 따라 퍼포먼스와 이미지 품질의 차이가 있다. 기본값 사용을 추천한다. 

다음 소스코드를 이용하여 테스트 해볼 수 있다.

보간법 종류에 따른 품질 차이

회전 변환

영상을 특정 각도만큼 반시계 방향으로 회전 시키는 변환이다.

회전에는 삼각함수 연산이 필요하기 때문에 위의 예제들처럼 단순히 특정요소값을 변경하며 원하는 결과를 얻기는 어렵다. 그래도 대충 회전해보자면 다음과 같다.

실제로 영상을 회전할 때는 좌상단 기준으로 회전하기 때문에 또 어려운 부분이 있는데, OpenCV에서는 이러한 회전변환행렬을 구하기 위한 함수를 제공한다. getRotationMatrix2D는 주어진 파라미터로 회전 행렬을 반환한다.

Imgproc.getRotationMatrix2D(Point center, double angle, double scale)
center : 회전 중심 좌표
angle : 회전각도
scale : 추가적인 확대/축소 비율

getRotationMatrix2D를 사용하는 예제코드를 이용하여, 이미지를 60도 회전해보자.

이미지 대칭 변환

영상의 대칭 변환은 flip 또는 reflection이라고 한다. 3가지의 대칭 방법이 있다.

  • 좌우 대칭
  • 상하 대칭
  • 좌우 & 상하 대칭

다음과 같이 변환행렬의 scale factor 및 traslation factor를 지정하고 warpAffine() 함수를 사용하여 대칭 변환하는 것이 가능하다.

하지만 이렇게 구하는 것은 복잡할 수 있기 때문에 OpenCV에서는 flip이라는 함수를 제공한다.

Core.flip(Mat src, Mat dst, int flipCode)
src : 원본 이미지
dst : 출력 이미지
flipCode : 양수 = 좌우대칭, 0 = 상하 대칭, 음수 = 좌우 & 상하 대칭

예제코드를 통해 flip함수를 사용한 결과는 다음과 같다.

Affine 변환 행렬 구하기 

Affine 변환에서는 원본이미지의 모든 평행선들이 출력되는 이미지에서도 유지된다.

즉, 입력된 이미지와 출력될 이미지에 매핑될 3개의 점만 알면 두 이미지간 affine 변환 행렬을 구할 수 있다.  OpenCV에서는 getAffineTransform 함수를 사용하여 계산된 변환 행렬을 반환받는다.

Mat getAffineTransform(MatOfPoint2f src, MatOfPoint2f dst)
src : 원본 이미지에서의 3개의 좌표
dst : 출력 이미지에서의 3개의 좌표

 

1000px*1000px 사이즈의 이미지에서 다음의 3개의 좌표를 통해 Affine 변환 행렬을 구하여 결과물을 얻는 예제코드를 살펴보자.

원본이미지 상의 3개의 좌표
(150,150), (150,850), (850,150)

출력이미지 상의 3개의 좌표
(150,150), (150,850), (850,500)

 

Buy me a coffeeBuy me a coffee
카테고리: AndroidOpenCV

0개의 댓글

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.