Чтобы найти оптический поток как ndarray, используйте cv2.calcOpticalFlowPyrLK () - PullRequest
0 голосов
/ 05 апреля 2020

Мне нужно найти оптический поток между каждыми 2 смежными кадрами видео, используя оптический поток Лукаса Канаде. Я использую python и openCV для проекта.

Насколько я понимаю, Лукас Канаде - это редкий метод поиска оптического потока. Есть ли плотная реализация этого? Если да, то как его использовать в python?

Используя cv2.calcOpticalFlowFarneback (), который является плотным методом, мы получаем в качестве вывода ndarray («поток» в примере ниже), который содержит оптический поток.

cv2.calcOpticalFlowFarneback(prev, next, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags[, flow]) → flow

Есть ли способ получить аналогичный вывод с помощью cv2.calcOpticalFlowPyrLK ()?

cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts[, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]]]) → nextPts, status, err

При использовании cv2.calcOpticalFlowPyrLK () (выше) полученный вывод содержит nextPts, который содержит следующие точки для отслеживания, но это не так непосредственно дать оптический поток из 2 кадров. Если я вычитаю prevPts из nextPts, получится ли оптический поток между двумя кадрами? Я нашел 'prev (y, x) ~ next (y + flow (y, x) [1], x + flow (y, x) [0]) "в разделе, объясняющем calcOpticalFlowFarneback () по этой ссылке: https://docs.opencv.org/2.4/modules/video/doc/motion_analysis_and_object_tracking.html Отсюда и вопрос. (Синтаксис для cv2.calcOpticalFlowPyrLK () и cv2.calcOpticalFlowFarneback также взят из этой ссылки) Ниже приведена моя реализация того же.

import cv2
import numpy as np
import os
import subprocess as sp

yuv_filename = 'can_0.yuv'
flow=[]

width, height = 320, 240

file_size = os.path.getsize(yuv_filename)
n_frames = file_size // (width*height*3 // 2)
f = open(yuv_filename, 'rb')


old_yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))


# Convert YUV420 to Grayscale
old_gray = cv2.cvtColor(old_yuv, cv2.COLOR_YUV2GRAY_I420)


# params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7,
                       blockSize = 7 )

# Parameters for lucas kanade optical flow
lk_params = dict( winSize  = (15,15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))


p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)


for i in range(1,n_frames):
    # Read Y, U and V color channels and reshape to height*1.5 x width numpy array
    yuv = np.frombuffer(f.read(width*height*3//2), dtype=np.uint8).reshape((height*3//2, width))

    # Convert YUV420 to Grayscale
    gray = cv2.cvtColor(yuv, cv2.COLOR_YUV2GRAY_I420)

    # calculate optical flow
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, gray, p0, None, **lk_params)


    flow.append(np.subtract(p1,p0))
    good_old = p0[st==1]
    good_new = p1[st==1]


    # Now update the previous frame and previous points
    old_gray = gray.copy()
    p0 = good_new.reshape(-1,1,2)


f.close()

Поток представляет собой список ndarrays, содержащий оптический поток между соседними кадрами входного видео?

Это вывод, который я получил для потока [7] (выбран случайным образом), но я не уверен, что это значения оптического потока.

[[[6.7138672e-03 4.5318604e- 03]]

[[- 1.6220093e-02 1.9645691e-03]]

[[- 8.5296631e-03 1.8482208e-03]]

[[- 5.8441162e-03 1.5701294e-02]]

[[7.5836182e-03 2.3475647e-02]]

[[- 1.4129639e-02 1.6357422e-02]]

[[4.4555664e-03 4.1809082e-03]]

[[5.6457520e-04 -9.5863342e-03]]

[[2.8991699e-04 -3.0517578e- 05]]

[[- 2.3452759e-02 -1.5502930e-02]]

[[- 6.8283081e-03 3.3264160e-03]]

[[ -8.4381104e-03 7.7590942e-03]]

[[5.7144165e-03 1.1177063e-02]]

[[- 1.4160156e-02 2.1179199e-02]]

[[- 1.0498047e-02 8.0099106e-03]]

[[- 1.8310547e-04 2.8953552e-03]]

[[4.4937134e-03 -2.0904541 e-03]]

[[- 4.7698975e-02 3.7708282e-02]]

[[6.3323975e-03 1.3298035e-02]]

[[ -3,323364 3e-02 -1.7229080e-02]]

[[7.5683594e-03 2.4566650e-03]]

[[- 3.0364990e-03 3.4656525e-03]]

[[- 1.0345459e-02 -7.4539185e-03]]

[[1.3168335e-02 2.1423340e-02]]

[[- 6.3476562e-03 -1.0681152 e-02]]

[[1.5869141e-03 1.0375977e-03]]

[[2.1820068e-03 6.7329407e-03]]

[[- 9.6130371e-03 2.9449463e-03]]

[[- 2.1362305e-03 8.5525513e-03]]

[[- 1.7547607e-04 2.1362305e-04]]

[[2.9144287e-03 1.4343262e-03]]

[[2.9602051e-03 -7.1868896e-03]]

[[- 1.2878418e-02 5.0182343e -03]]

[[- 3.1585693e-03 -5.0544739e-05]]

[[1.0070801e-03 1.3740540e-02]]

[[ 6.7138672e-04 1.7852783e-03]]

[[- 2.0568848e-02 -1.2943268e-02]]

[[- 2.1057129e-03 4.5013428e-03]]]

Также существует ли способ получить оптический поток, используя метод Лукаса Канаде, чтобы он имел тот же размер или размеры, что и входные кадры? Если так, то как?

1 Ответ

0 голосов
/ 16 апреля 2020

Вы можете оценить плотное поле потока с помощью чисто пирамидального метода Лукаса Канаде, рассчитав для каждого пикселя соответствующие пары точек. Для этого:

  • игнорировать cv2.goodFeaturesToTrack
  • инициализировать список точек p0, содержащий все пиксельные местоположения изображения

    grid_y, grid_x = np.mgrid[0:prevImg.shape[0]:1, 0:prevImg.shape[1]:1]
    p0 = np.stack((grid_x.flatten(),grid_y.flatten()),axis=1).astype(np.float32)
    
  • выполнить расчет запасного потока

    p1, status, err = cv2.calcOpticalFlowPyrLK(prevImg, currImg, p0, None)
    
  • собрать плотное поле потока путем вычисления и изменения формы векторов движения (p1 - p0), поток будет иметь форму (hxwx 2) и prevImg ( hxwx 1)

    flow = np.reshape(p1 - p0, (prevImg.shape[0], prevImg.shape[1], 2))
    

Однако это не самый эффективный способ вычисления плотного поля оптического потока. В OpenCV вы можете взглянуть на другие методы DenseOpticalFlow (например, DIS, Farneback, RLOFDense, Dual-TVL1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...