Jak wykonać korekcję perspektywy wykorzystując bibliotekę OpenCV? W tym poście pokażę Ci jak przekształcić widok z kamery aby uzyskać widok z góry.
Kod źródłowy do tego posta znajdziesz na Githubie: https://github.com/karolmajek/TrafficAnalysis/blob/master/TrafficCamera_Unwarp_Image.ipynb
Do pracy wykorzystamy język Python. W pierwszym kroku zaimportujemy niezbędne biblioteki: Matplotlib, Numpy i OpenCV.
import matplotlib.pyplot as plt import numpy as np import cv2
Następnie ściągniemy flim z Youtube’a przy pomocy youtube-dl, który możesz pobrać tutaj http://rg3.github.io/youtube-dl/. W linii poleceń wpisz:
youtube-dl -f 313 MNn9qKG2UFI
Powyższe polecenie pobierze film w rozdzilczości 4K. A teraz wrócimy do pythona. Wyświelimy pierwszą klatkę:
cap = cv2.VideoCapture("4K Traffic camera video - free download now!-MNn9qKG2UFI.webm") while(True): ret, frame = cap.read() if not ret: break frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB) break plt.figure(figsize=(16,9)) plt.imshow(frame) plt.show()

4k Traffic Camera Frame
Potrafimy już wczytać klatkę z filmu. Teraz aby wyprostować film musimy znaleźć trapez tworzący perspektywę. W tym przypadku zrobimy to ręcznie podając wierzchołki roi_corners:
roi_corners=[[0.0 *frame.shape[1],1.0*frame.shape[0]], # left, down [0.38*frame.shape[1],0.0*frame.shape[0]], # left, up [0.62*frame.shape[1],0.0*frame.shape[0]], # right, up [1.0 *frame.shape[1],1.0*frame.shape[0]]] # right, down show_roi=True if show_roi: #change the format of points list and draw it on image src = np.float32(roi_corners) pts = np.array(src, np.int32) pts = pts.reshape((-1,1,2)) cv2.polylines(frame,[pts],True,(255,0,0),10) # Red in RGB; width: 10 plt.figure(figsize=(16,9)) plt.imshow(frame) plt.show()

4k Traffic Camera Trapezoid
Korekcja perspektywy
A teraz zdefiniujemy funkcję która znajdzie przekształcenie perspektywy pomiędzy czterema parami wierchołków. Do tego wykorzystamy funkcję getPerspectiveTransform z biblioteki OpenCV. Następnie przekształcimy obraz za pomocą funckji warpPerspective.
def unwarp(img, roi_corners): ''' Unwarp image using 4 points and getPerspectiveTransform ''' src = np.float32(roi_corners) warped_size=(img.shape[1], img.shape[0]) offset=int(warped_size[0]/3.0) dst = np.float32([[offset , warped_size[1] ], # [offset , 0 ], [warped_size[0]-offset, 0 ], [warped_size[0]-offset, warped_size[1]]]) Mpersp = cv2.getPerspectiveTransform(src, dst) warped = cv2.warpPerspective(img, Mpersp, dsize=warped_size) return warped
Zobaczmy jak powyższa funkcja zadziała dla naszego obarazu, wykonamy korekcję perspektywy:
# Unwarp the frame!
unwarped = unwarp(frame,roi_corners)
# Let's see the result
plt.figure(figsize=(16,9))
plt.imshow(unwarped)
plt.show()

Korekcja perspektywy w OpenCV
Udało się! Teraz możemy spróbować przetworzyć wszystkie klatki filmu. W tym celu złożymy cały kod w jednym miejscu:
import matplotlib.pyplot as plt import numpy as np import cv2 cap = cv2.VideoCapture("4K Traffic camera video - free download now!-MNn9qKG2UFI.webm") counter = 0 while(True): ret, frame = cap.read() if not ret: break # We are working in BGR which is native for OpenCV show_roi=True if show_roi: src = np.float32(roi_corners) pts = np.array(src, np.int32) pts = pts.reshape((-1,1,2)) cv2.polylines(frame,[pts],True,(0,0,255),10) # Red in BGR # unwarp unwarped = unwarp(frame,roi_corners) #Picture in picture - show the original frame unwarped[-541:-1,0:960,:] = frame[::4,::4,:] #write the result to file! cv2.imwrite("/tmp/img%08d.jpg"%counter, unwarped) counter = counter + 1
Uzyskaliśmy wyniki dla każdej z klatek filmu. Chcielibyśmy je złożyć z powrotem w film, w tym może nam pomóc ffmpeg:
ffmpeg -pattern_type glob -i '/tmp/img*.jpg' -c:v libx265 result.mp4
A tutaj cały film z korekcją perspektywy: