프로그래밍 언어 및 IT 정보/opencv_python

[opencv_python] 4.2 기하학적 변환 (자르기(ROI), 어핀변환,원근변환 )

Himer_torr 2022. 7. 22. 15:47
반응형

저번 포스팅에 이어 opencv로 기하학적 변환 두 번째 공부를 진행해보겠습니다.

이번 강의에는 크기조절, 자르기, 기하학적의 기본 바탕이 되는 아핀 변환, 원근 변환을 공부해보도록 하겠습니다.

 

저는 Visual studio code와opencv 4.5.5 버전을 이용하였습니다.

 

자르기(Slice)

자르기(Slice)는 영상이나 이미지에서 특정 영역을 잘라내는 연산이라고 보시면 됩니다.

특정 영역을 잘라내는 것을 ROI (Region Of Interest) 라고 하며, 이미지상 관심 있는 영역이라고 보시면 됩니다.

관심 영역만 잘라 알고리즘을 적용한다면, 불필요한 연산이 줄어들게 되겠죠?

 

import cv2

img = cv2.imread('./img/torr.jpg')
cp = img[150:250, 100:250].copy()

cv2.imshow('img',img)
cv2.imshow('cp',cp)

cv2.waitKey()
cv2.destroyAllWindows()

예제소스 결과

이미지는 numpy 배열과 동일하기 때문에 img[행,열] 형태로 자르실 수 있습니다.

예를 들어 예제 소스는 150에서 200까지의 을 가져오고, 100에서 250까지의 의 위치 가져온다고 보시면 됩니다.

여기서 알아두셔야 할 점은 copy() 입니다.

이미지를 복사 할 때 복사 방법으로는 깊은 복사(deep copy) , 얕은 복사(shallow copy)가 있는데,

얕은 복사(shallow copy)는 원본의 영향을 받게됩니다. ex) cy = img

copy() 함수는 깊은복사(deep copy)를 적용하므로 원본 이미지에 영향을 주지 않습니다.

 

import cv2

img = cv2.imread('./img/torr.jpg')
cp = img.copy()
roi = cp[150:250,100:250]
img[0:100,0:150] = roi

cv2.imshow('img',img)
cv2.imshow('cp',cp)

cv2.waitKey()
cv2.destroyAllWindows()

 

예제소스 결과

위 예제 소스는 ROI를 원본 이미지에 합쳐 보여주는 예제입니다.

이미지는 Numpy 배열이기 때문에 원하는 위치에 내 ROI영역을 넣을 수 있습니다.

 

어핀 변환(Affine Transformation)

어핀 변환(Affine Transformation) 은 사실 앞서 다뤘던 이동, 확대/축소, 회전을 포함한 변환으로 직선, 길이의 비율, 

평행성 등을 보존하는 변환을 말합니다. 어핀 변환은 2X3 행렬을 사용하며 행렬 곱셈에 벡터 합을 활용해 표현할 수 있는데,  변환 전과 후의 3개의 점을 짝 지어 매핑할 수 있다면 변환 행렬을 거꾸로 계산할 수 있습니다.
Opencv에서 변환행렬를 구해주는 함수를 제공하는데 아래의 함수가 변환 행렬을 구해주는 함수입니다.

cv.getAffineTransform(pts1, pts2)

Parameters

  • pts1: 변환 전 영상의 좌표 3개, 3 X 2 Numpy 배열(float32)
  • pts2: 변환 후 영상의 좌표 3개, pts1과 동일
import cv2
import numpy as np
img = cv2.imread('./img/torr.jpg')

rows, cols = img.shape[:2]

pts1 = np.float32([[100,50],[250,50],[100,400]])
pts2 = np.float32([[100,90],[240,90],[290,170]])

cv2.circle(img,(100,50),5,(255,0,0), -1)
cv2.circle(img,(250,50),5,(0,255,0), -1)
cv2.circle(img,(100,300),5,(0,0,255), -1)

mtrx = cv2.getAffineTransform(pts1,pts2)

dst = cv2.warpAffine(img,mtrx,(int(cols* 1.2),rows))


cv2.imshow('img',img)
cv2.imshow('affine',dst)
cv2.waitKey()
cv2.destroyAllWindows()

예제소스 결과

 

위 보시면 사각형의 영상이 마름모꼴 모양으로 변형된 것을 볼 수 있습니다.

이런 변환 행렬은 개발자가 일일이 계산하기 불편한데 , Opencv에서는 간단히 변한 행렬을 구해줍니다.

 

 

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

Parameters

  • src: 입력 영상
  • M : 변환 행렬 (2X3)
  • dsize : 출력 영상 크기

 

위 함수는 지정된 행렬을 사용하여 소스 이미지를 변환시켜주는 함수입니다.

현재까지 다양하게 조절하고 회전하고, 이동시키는 모든 변환들은 변화시킬 행렬만 가지고 있다면 저 함수로도
대체가 가능합니다.

 

 

원근 변환(Affine Transformation)

원근 변한은  가까운 것은 크게, 먼 것은 작게, 이런 식으로 원근감을 주는 변환을 말합니다.

영상은 2차원 좌표계인데 우리가 사는 세상은 3차원 좌표계이기 때문에, 차원 간의 차이를 보정해줄 추가 연산과 시스템이 필요합니다. 이때 사용하는 좌표계를 동차 좌표(homogeneous coordinates)라고 합니다. 이 때문에 원근 변환을 다른 말로

호모그래피(Homography) 라고 불립니다. 원근 변환은 3 x 3 행렬을 사용합니다

 

cv.getPerspectiveTransform(pts1, pts2)

Parameters

  • pts1: 변환 이전 좌표 4개 , 4 x 2 Numpy 배열(float32)
  • pts2: 변환 이후 좌표 4개 , pts1과 동일
cv.warpPerspective(src, mtrx, dsize [,dst, flags, borderMode, borderValue])

Parameters

  • 파라미터들은 위에서 소개한 WarpAffine() 함수와 동일합니다.
import cv2
import numpy as np
import matplotlib.pyplot as plt

file_name = './img/torr.jpg'
img = cv2.imread(file_name)
rows, cols = img.shape[:2]

pts1 = np.float32([[0,0],[0,rows],[cols,0],[cols,rows]])
pts2 = np.float32([[100,50],[10,rows-50],[cols-100,50],[cols-10,rows-50]])


cv2.circle(img,(0,0),10, (255,0,0), -1)
cv2.circle(img,(0,rows),10, (0,255,0), -1)
cv2.circle(img,(cols,0),10, (0,0,255), -1)
cv2.circle(img,(cols,rows),10, (0,255,255), -1)

mtrx = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,mtrx,(cols,rows))

cv2.imshow('origin',img)
cv2.imshow('perspective',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

결과값

 

반응형