2023/4/24

opencv perspective transform

ref:
(550,807), (943,807),(1749,945),(8,945)
(0,0), (600,0), (600,800),(0,800)
車道線選上面四點。
自己決定 mapping 到 600x800 的矩形。
然後用:

pts1 = np.float32([[550,807],[943,807],[1749,945],[8,945]])
pts2 = np.float32([[  0,  0],[600,  0],[ 600,800],[0,800]])

matrix = cv2.getPerspectiveTransform(pts1,pts2)
得到 perspective matrix

然後用 warpPerspective( ) 把 source image , 轉換..
result = cv2.warpPerspective(frame,matrix,(600,900))
因為我們選四個點的時候,沒有選到照片的最底端。
所以 warpPerspective( ) 最後一個 destinate image size,長度要比 mapping 的 800 還多一些...才能把沒被包進去的下面部份也納入。


完整的程式就是:
import cv2
import numpy as np

frame = cv2.imread('p1.png')

pts1 = np.float32([[550,807],[943,807],[1749,945],[8,945]])
pts2 = np.float32([[  0,  0],[600,  0],[ 600,800],[0,800]])

matrix = cv2.getPerspectiveTransform(pts1,pts2)
result = cv2.warpPerspective(frame,matrix,(600,900))

cv2.imshow('result',result)

cv2.waitKey(0)

另外,如果要把整個 video 都做 mapping 的話:
import cv2
import numpy as np
import sys
import os

input_file = sys.argv[1]
print(input_file)
path, filename = os.path.split(input_file)
filename, ext = os.path.splitext(filename)
output_file = filename + '_ipm' + ext
print(output_file)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_file,fourcc,30.0,(600,900))

pts1 = np.float32([[550,807],[943,807],[1749,945],[8,945]])
pts2 = np.float32([[  0,  0],[600,  0],[ 600,800],[0,800]])
matrix = cv2.getPerspectiveTransform(pts1,pts2)

cap = cv2.VideoCapture(input_file)
while(cap.isOpened()):
        ret, frame = cap.read()
        if not ret:
                break

        result = cv2.warpPerspective(frame,matrix,(600,900))
        out.write(result)

cap.release()
cv2.destroyAllWindows()

另外,得到 perspective transform matrix 後,如果要知道 某一點 transform 後的位置。
相乘完,還要 scale
import numpy as np

with open('matrix.npy','rb') as f:
    matrix = np.load(f)
    
Point = np.float32([100,60,1]) 
PPoint = matrix.dot(Point)
PPoint /= PPoint[2]    // Scalse 

TransformPoint = PPoint[:2]

沒有留言:

張貼留言