Python - буфер видеопотока Performant - PullRequest
0 голосов
/ 07 марта 2020

Как мне создать эффективный буфер видеопотока, с которым я могу выполнять numpy операции с массивами?

Это моя реализация в настоящее время - я просто сдвигаю предыдущий массив вперед на 1 кадр и назначаю последний элемент текущему кадру.

import numpy as np
import cv2
import time
cap = cv2.VideoCapture(0)
status, frame = cap.read()
buffer = np.empty([100, frame.shape[0], frame.shape[1], frame.shape[2]])
i=0
total = 100
while i < total:
    if not i: 
        start = time.time()
    status, frame = cap.read()
    t = time.time()
    if i < total/2:
        buffer[i] = frame
    else:
        buffer[:-1] = buffer[1:]
        buffer[-1] = frame
    if i == total/2: 
        middle = t
    i += 1
    # Calculations on the buffer ommitted for brevity but include mean, std, etc.

stop = time.time()
print((middle-start)/(total/2))
print((stop-middle)/(total/2))

Сдвиг массива занимает примерно в 350 раз больше, чем просто присваивание значений кадра элементу массива. Я знаю, что это потому, что я перемещаю все указатели в массиве, что является ненужным и дорогим. Поддерживать порядок в кадре приятно, но не обязательно.

Ответы [ 2 ]

0 голосов
/ 14 марта 2020

Переформатирование списка в массив numpy стоит очень мало. Список deque / related не был действительно более эффективным с 100 кадрами в буфере.

import numpy as np
import cv2
import time
import collections

cap = cv2.VideoCapture(0)
i=0
buff_len = 100

# buffer = []                           #Standard list
# buffer = collections.deque()          #linked list 
status, frame = cap.read()              #numpy array - replaces the first frame once it reaches the last frame
buffer = np.empty([buff_len, frame.shape[0], frame.shape[1], frame.shape[2]])

times_through = 3
start = time.time()

while i < times_through*buff_len:
    t = time.time()
    status, frame = cap.read()
    # buffer.append(frame)              #list and linked list 
    buffer[i%(buff_len)] = frame        #numpy array 
    # if i >= buff_len:                 #list and linked list 
        # buffer.pop(0)                 #list  
        # buffer.popleft()              #linked list 
    if i == buff_len:
        full = t
    i += 1
    print(i, np.mean(buffer, dtype=np.int), int((time.time()-t)*100)/100.)
stop = time.time()
print((full-start)/(buff_len))
print((stop-full)/(buff_len*(times_through-1)))
print(len(buffer))

Результаты в секундах / кадр:

# list
# 0.19624330043792726
# 0.3691681241989136

# linked list
# 0.19301403045654297
# 0.3468885350227356

# numpy Array 
# 0.316677029132843
# 0.30973124504089355
0 голосов
/ 11 марта 2020

Один удивительно простой способ внести незначительное улучшение в это - использовать список Python для фактического сдвига / добавления, а затем повторно создать экземпляр буфера как новый массив NumPy, например:

import numpy as np
import cv2
import itertools
import time
cap = cv2.VideoCapture(0)
status, frame = cap.read()
buffer = np.empty([100, frame.shape[0], frame.shape[1], frame.shape[2]])
i=0
total = 100
middle = 0
while i < total:
    if not i: 
        start = time.time()
    status, frame = cap.read()
    t = time.time()
    if i < total/2:
        buffer[i] = frame
    else:
        list_buffer = [item for item in buffer[1:]]
        list_buffer.append(frame)
        buffer = np.asanyarray(list_buffer)
    if i == total/2: 
        middle = t
    i += 1
    # Calculations on the buffer ommitted for brevity but include mean, std, etc.

stop = time.time()
print((middle-start)/(total/2))
print((stop-middle)/(total/2))

На моей машине это занимает второе время с 1,7 секунды до 1,36 секунды. Не значительное улучшение, но и не незначительное (ускорение ~ 20%).

Однако, если мы вместо этого используем list_buffer во всем l oop, чтобы отслеживать содержимое буфера и просто делать оба наш срез и добавление к , что :

import numpy as np
import cv2
import itertools
import time
cap = cv2.VideoCapture(0)
status, frame = cap.read()
buffer = np.empty([100, frame.shape[0], frame.shape[1], frame.shape[2]])
i=0
total = 100
middle = 0
list_buffer = []
while i < total:
    if not i: 
        start = time.time()
    status, frame = cap.read()
    t = time.time()
    if i < total/2:
        buffer[i] = frame
        list_buffer.append(frame)
    else:
        list_buffer = list_buffer[1:]
        list_buffer.append(frame)
        buffer = np.asanyarray(list_buffer)
    if i == total/2: 
        middle = t
    i += 1
    # Calculations on the buffer ommitted for brevity but include mean, std, etc.

stop = time.time()
print((middle-start)/(total/2))
print((stop-middle)/(total/2))

, внезапно наш вывод будет выглядеть так:

>>> 0.08505516052246094
>>> 0.08459827899932862

Надеюсь, что поможет!

...