콘텐츠로 이동
Search

Perspective transform

lastmod 2023-10-26created 2023-01-058 edits

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

author Zer0 sitemap