Skip to content
Search

Perspective transform

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

OpenCV APIs

A Perspective transform is a transform that preserves only the straightness of lines, not their parallelism. Railroad tracks are parallel to each other, but after a perspective transform their parallelism is not preserved and they appear to meet at a single point. (The reverse transform is also possible.)

You need the Input values of 4 Points and the output Points they move to.

To get the transformation matrix you need the cv2.getPerspectiveTransform function, and you can get the final result image by applying the transformation matrix to the cv2.warpPerspective function.

The example below removes the effect of perspective.

#-*- 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

Sample: recording video after a perspective transform

#-*- 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