티스토리 뷰

반응형
[영상처리] 원근 변환 Perspective Transform (OpenCV-Python)

원근 변환

원근 변환(perspective transform)은 보는 사람의 시각에 따라 같은 물체도 먼 것은 작게, 가까운 것은 크게 보이는 현상인 원근감을 주는 변환이다.

opencv에서 변환 전과 후를 짝짓는 4개의 매핑 좌표만 지정해 주면 원근 변환에 필요한 3x3 변환행렬을 계산해주는 cv2.getPerspectiveTransform() 함수를 제공한다. 이 함수를 이용하여 얻은 변환행렬을 cv2.warpPerspective() 함수를 이용해 적용한다.

코드

아래 코드는 이미지에서 마우스로 4개의 꼭짓점을 클릭하면, 해당 영역에 대해 평면처럼 보이도록 원근변환을 해주는 코드이다.

import cv2
import numpy as np

win_name = "scanning"
img = cv2.imread("imgs/paper.jpg")
rows, cols = img.shape[:2]
draw = img.copy()
pts_cnt = 0
pts = np.zeros((4, 2), dtype=np.float32)

def onMouse(event, x, y, flags, param):
    global pts_cnt
    if event == cv2.EVENT_LBUTTONDOWN:
        # 좌표에 초록색 동그라미 표시
        cv2.circle(draw, (x, y), 10, (0, 255, 0), -1)
        cv2.imshow(win_name, draw)

        # 마우스 좌표 저장
        pts[pts_cnt] = [x, y]
        pts_cnt += 1
        if pts_cnt == 4:
            # 좌표 4개 중 상하좌우 찾기
            sm = pts.sum(axis=1)  # 4쌍의 좌표 각각 x+y 계산
            diff = np.diff(pts, axis=1)  # 4쌍의 좌표 각각 x-y 계산

            topLeft = pts[np.argmin(sm)]  # x+y가 가장 값이 좌상단 좌표
            bottomRight = pts[np.argmax(sm)]  # x+y가 가장 큰 값이 우하단 좌표
            topRight = pts[np.argmin(diff)]  # x-y가 가장 작은 것이 우상단 좌표
            bottomLeft = pts[np.argmax(diff)]  # x-y가 가장 큰 값이 좌하단 좌표

            # 변환 전 4개 좌표 
            pts1 = np.float32([topLeft, topRight, bottomRight, bottomLeft])

            # 변환 후 영상에 사용할 서류의 폭과 높이 계산
            w1 = abs(bottomRight[0] - bottomLeft[0])
            w2 = abs(topRight[0] - topLeft[0])
            h1 = abs(topRight[1] - bottomRight[1])
            h2 = abs(topLeft[1] - bottomLeft[1])
            width = max([w1, w2])  # 두 좌우 거리간의 최대값이 서류의 폭
            height = max([h1, h2])  # 두 상하 거리간의 최대값이 서류의 높이

            # 변환 후 4개 좌표
            pts2 = np.float32([[0, 0], [width - 1, 0],
                               [width - 1, height - 1], [0, height - 1]])

            # 변환 행렬 계산 
            mtrx = cv2.getPerspectiveTransform(pts1, pts2)
            # 원근 변환 적용
            result = cv2.warpPerspective(img, mtrx, (width, height))
            cv2.imshow('scanned', result)

cv2.imshow(win_name, img)
cv2.setMouseCallback(win_name, onMouse)
cv2.waitKey(0)
cv2.destroyAllWindows()

아래 두 줄이 원근변환 적용의 핵심 코드라고 할 수 있다. 원근 변환을 원하는 4개의 전/후 좌표를 통해 변환행렬을 구하고, 이 변환행렬로 영상을 변환시킨다.

# 변환 행렬 계산 
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
# 원근 변환 적용
result = cv2.warpPerspective(img, mtrx, (width, height))

결과 영상

왼쪽 영상에서 문서의 4개의 꼭짓점을 클릭하면 이 좌표를 기준으로 원근변환하여 오른쪽 영상처럼 보이게 된다.

참고자료

[도서] 파이썬으로 만드는 OpenCV 프로젝트

[코드] 파이썬으로 만드는 OpenCV 프로젝트

반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday