Korekcja perspektywy w OpenCV

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
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
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
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:

Linki:

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *