본문 바로가기
AI/컴퓨터 비전

OpenCV - getRotationMatrix2D| getPerspectiveTransform

by 바다의 공간 2025. 3. 17.

▶ 이미지 로테이션

 

import cv2

img = cv2.imread('D:/PJ/DLHJ/ong.jpg')
img = cv2.resize(img, (300,300))

#이미지 회전을 위한 중심좌표 조건 설정
cp = (img.shape[1]/2, img.shape[0]/2)
print(cp) #(1512.0, 1512.0)

#회전조건 설정
rot = cv2.getRotationMatrix2D(cp, 30, 0.5)


#이미지 적용(Affine)
dst = cv2.warpAffine(img, rot, (0,0))

#이미지 확인
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()

 

이미지로테이션을 하기 위해서 이미지를 불러왔다. 

내가 좋아하는 우리 옹이를 사진으로 사용하기 위해서 가져왔는데 이미지가 너무 커서 300,300으로 리사이즈 먼저 시켜주었다. 해상도를 보기 위한건 아니라서 따로 보간법을 사용해주진 않았다.

 

그 이후로 이미지 회전을 하기 위한 중심좌표(center piont)를 잡았고 변수를 cp로 두었다.

cp를 프린트해보니 1512로 중심이 잡혔다. 앞으로 모든 회전의 중심은 저 cp가 될 것이다.

 

이후로 rot라는 변수를 만들어서 로테이션을 해주었는데 여기서 나오는 함수가

cv2.getRotationMatrix2D이다. 이 함수는 이미지 변환 행렬을 계산하는 함수이고,

사용방법은 (중심좌표, 회전각도, 크기비율)을 순서대로 작성한다.

나같은경우는 0.7으로 작성했고 크기비율을 70%로 축소시킨다는 의미가 된다.

 

사실 여기서 cv2.imshow()를 해보았는데 뭔가 이상한것이다. 

그래서 코드를 위에서 다시 살펴보니 내가 바꿀 이미지를 직접적으로 언급한건 아니였다는것을 깨달았다.

 

그럼 지금까지 한 건 뭐냐! '단순 조건'만 설정해준것이다.

 

이후에 dst라는 변수에 이미지를 적용하는 warfAffine을 적용해주었다.

나는 간단하게 (이미지, 변환행렬, 출력크기) 를 주었고 출력크기는(0,0) = 자동조정 이다.

 

원래 방법은아래와 같다.

dst = cv2.warpAffine(src, M, dsize, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=0)

 

매개변수 설명

src 원본 이미지

M 2×3 아핀 변환 행렬 (예: cv2.getRotationMatrix2D())

dsize 변환된 이미지의 출력 크기 (width, height)

flags 보간법(픽셀 보정) - 기본값 cv2.INTER_LINEAR

borderMode 이미지 경계 처리 방법

borderValue 경계 처리 값 (기본값 0, 검은색)


▶ PerspectiveTransform

이미지를 투시변환을 해보려고합니다. 기울어진 사진같은걸 펼쳐서 보여주는것을 해보려고합니다.

예를들어 보험서류를 기울이게 찍어도 각 꼭지점을 표시하고 확인을 누르면 평면으로 변환하는것을 투시변환이라고 합니다. 저는 옹이사진을 가지고 좀 움직여보려고합니다.

#srcQuad = np.array[[#왼쪽상단],[#우측상단],[#우측하단],[#좌측하단]]
srcQuad = np.array([[67,753],[2457,753],[2465,2969],[633,2969]], np.float32)

 

옹이만 딱 따오려고합니다!

원하는 파트는 아래 사진입니다.

 

위 노랑색 테두리만큼만 따오려고 합니다.

import cv2
import numpy as np

img = cv2.imread('D:\PJ\DLHJ\ong.jpg')
w, h = 600, 400

 

원하는 이미지를 가져온 후 w,h를 정해줍니다.

w,h를 정하는 이유는 출력될 이미지 사이즈를 미리 정하는것입니다.

 

그리고 srcQua라는 변수를 사용해서 내가 ROC할 포인트를 작성해줍니다. 좌표를 어디서 구하냐면 

그림판들어가면 내가 원하는 지점에 커서를 올려놓은 뒤 하단을 보면 좌표가 보이게 됩니다.

 

그 좌표를 따온 것이 바로 아래 좌표입니다.

#srcQuad = np.array[[#왼쪽상단],[#우측상단],[#우측하단],[#좌측하단]]
srcQuad = np.array([[67,753],[2457,753],[2465,2969],[633,2969]], np.float32)

 

순서를 꼭 기억해야하는데 왼상, 우상, 우하,좌하입니다. 이건 내가 따올 좌표를 입력만 한것이다.

역 'ㄷ'

 

 

그 다음 변수로 dstQuad를 입력할건데 이 변수는 투시변환 후 목적지 좌표(출력될 이미지 좌표)를 정의한것이다.

dstQuad = np.array([[0,0], [w,0], [w,h], [0,h]], np.float32)

 

그러니까 SRC는 원본 이미지에서의 꼭지점을 가져오고 DST에서는 그 이미지를 각 펴주는 역할을 하는것이다.

이제 이런 이미지로 만들고싶어! 라는 워너비를 만든것이고 이미지를 변환하는 함수를 만들어주어야하는데

 

cv2.getPerspectiveTransform이라는 함수를 활용해서 이미지를 재배치하게된다.

cv2.getPerspectiveTransform(원본좌표, 변환자표)이다.

이함수같은경우는 3*3 투시변환행렬을 만듭니다. 그래서 픽셀을 새로운 위치로 이동시켜서 원본이미지(src)를 변환목표(dst)에 맞게 자동정렬해주게되는겁니다

#getPerspectiveTransform : 투시 변환을 위한 변환 행렬을 계산하는 함수
#getPerspectiveTransform(원본좌표, 변환좌표)
pers = cv2.getPerspectiveTransform(srcQuad,dstQuad)

 

이제 그러면 print를 해보면 3*3행렬이 반환될것이다.

[[ 2.32593371e-01 -5.94078735e-02  2.91503729e+01]
 [-5.18854736e-17  1.28192255e-01 -9.65287679e+01]
 [-1.07032546e-19 -9.76136438e-05  1.00000000e+00]]

 

이제는 warpPerspective를 이용해서 이미지에 직접적으로 변환을 주고 결과를 보려고 한다.

dst라는 변수에 원본이미지, 변환행렬, 출력크기를 작성해준 후 imshow()로 보면 된다.

 

#warpPerspective(원본이미지, 변환행렬, 출력크기)
dst = cv2.warpPerspective(img, pers, (w,h))

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

★결과

 

보고싶은 옹이 완성입니다. 출력 사이즈가 600,400이기때문에 좀 더 늘어나서

살짝 좀 더 부해보이긴하지만 그래도 원하는 부분만큼 잘 따지는것을 볼 수 있습니다.

더보기

관련 프로젝트

github.com/selfhiam/overloaded-truck-detection-project