Skip to content

Perspective transform

OpenCV APIs

Perspective(원근법) 변환은 직선의 성질만 유지가 되고, 선의 평행성은 유지가 되지 않는 변환입니다. 기차길은 서로 평행하지만 원근변환을 거치면 평행성은 유지 되지 못하고 하나의 점에서 만나는 것 처럼 보입니다.(반대의 변환도 가능)

4개의 Point의 Input값과이동할 output Point 가 필요합니다.

변환 행렬을 구하기 위해서는 cv2.getPerspectiveTransform 함수가 필요하며, cv2.warpPerspective 함수에 변환행렬값을 적용하여 최종 결과 이미지를 얻을 수 있습니다.

아래의 예는 원근법이 적용된 효과를 제거하는 예제입니다.

#-*- coding:utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('images/perspective.jpg')
# [x,y] 좌표점을 4x2의 행렬로 작성
# 좌표점은 좌상->좌하->우상->우하
pts1 = np.float32([[504,1003],[243,1525],[1000,1000],[1280,1685]])

# 좌표의 이동점
pts2 = np.float32([[10,10],[10,1000],[1000,10],[1000,1000]])

# pts1의 좌표에 표시. perspective 변환 후 이동 점 확인.
cv2.circle(img, (504,1003), 20, (255,0,0),-1)
cv2.circle(img, (243,1524), 20, (0,255,0),-1)
cv2.circle(img, (1000,1000), 20, (0,0,255),-1)
cv2.circle(img, (1280,1685), 20, (0,0,0),-1)

M = cv2.getPerspectiveTransform(pts1, pts2)

dst = cv2.warpPerspective(img, M, (1100,1100))

plt.subplot(121),plt.imshow(img),plt.title('image')
plt.subplot(122),plt.imshow(dst),plt.title('Perspective')
plt.show()

OpenCV_-_Perspective_Transformation.jpg

원근변환 후 비디오 녹화 샘플

#-*- coding:utf-8 -*-

import cv2
import sys
from numpy import array, float32


def main(input_file: str, output_file: str, headless=True):
    cap = cv2.VideoCapture(input_file)
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    input_size = width, height

    print("Input: ", input_file)
    print("Input fps: ", fps)
    print("Input size: ", input_size)
    print("Input frames: ", frames)

    resize_size = 1920, 1080
    print("Resize size: ", resize_size)

    left_top = 600, 37
    left_bottom = 479, 906
    right_top = 1068, 37
    right_bottom = 1212, 906
    points = left_top, left_bottom, right_top, right_bottom
    pp_from = array(points, dtype=float32)

    pp_roi = 0, 0, 733, 877
    x1, y1, x2, y2 = pp_roi
    pp_width = abs(x2 - x1)
    pp_height = abs(y2 - y1)
    pp_size = pp_width, pp_height
    pp_to = array(((x1, y1), (x1, y2), (x2, y1), (x2, y2)), dtype=float32)

    m = cv2.getPerspectiveTransform(pp_from, pp_to, cv2.DECOMP_LU)

    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    writer = cv2.VideoWriter(output_file, fourcc, fps, pp_size)
    print("Output: ", output_file)
    print("Output fps: ", fps)
    print("Output size: ", pp_size)

    try:
        i = 0
        while True:
            # print(f"{i}/{frames}")
            i += 1

            ret, image = cap.read()
            if not ret:
                break

            if image.shape[0:2] != resize_size:
                image = cv2.resize(image, dsize=resize_size)

            image = cv2.warpPerspective(image, m, pp_size)

            writer.write(image)

            if not headless:
                cv2.imshow("Preview", image)
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break
    finally:
        cap.release()
        writer.release()
        if not headless:
            cv2.destroyAllWindows()

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2], True)

See also

Favorite site