Захват потокового видео в реальном времени OpenCV идет медленно. Как отбрасывать кадры или синхронизироваться с реальным временем? - PullRequest
3 голосов
/ 08 октября 2019

Цель и проблема

Я бы хотел настроить систему opencv для обработки потоков HLS или потоков RMTP, однако я столкнулся со странной проблемой, связанной с уменьшением частоты кадров и накоплением задержки,Как будто видео становится все дальше и дальше от того места, где оно должно быть в потоке.

Я ищу способ быть в курсе событий с живым источником, даже если это означает удаление кадров.

Текущий подход

import cv2

cap = cv2.VideoCapture()
cap.open('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8')

while (True):
    _, frame = cap.read()
    cv2.imshow("camCapture", frame)
    cv2.waitKey(1)

Я проверил качество потока на VLC, и, похоже, там он работает нормально.

cv2 speed

.

реалистичная / ожидаемая скорость

Вопросы:

  • Что я здесь не так делаю?
  • Почему это так медленно?
  • Как мне синхронизировать его со скоростью в реальном времени?

Ответы [ 2 ]

1 голос
/ 15 октября 2019

image

Моя гипотеза состоит в том, что джиттер наиболее вероятен из-за сетевых ограничений и возникает при отбрасывании пакета кадра. Когда кадр отбрасывается, это приводит к тому, что программа отображает последний «хороший» кадр, что приводит к зависанию дисплея. Вероятно, это проблема с аппаратным обеспечением или пропускной способностью, но некоторые из них можно решить с помощью программного обеспечения. Вот некоторые возможные изменения:

1. Установить максимальный размер буфера

Мы установили для объекта cv2.videoCapture() ограниченный размер буфера с параметром cv2.CAP_PROP_BUFFERSIZE. Идея состоит в том, что, ограничивая буфер, мы всегда будем иметь самый последний кадр. Это также может помочь решить проблему случайного скачка кадров вперед.

2. Установить задержку извлечения кадра

В настоящее время я считаю, что read() читает слишком быстро, даже если он находится в своем собственном выделенном потоке. Это может быть одной из причин, по которой все кадры появляются и объединяются в следующем кадре. Например, скажем, в течение одного секунды, он может произвести 15 новых кадров, но в течение следующего интервала в одну секунду возвращаются только 3 кадра. Это может быть связано с потерей кадров сетевого пакета, поэтому для обеспечения получения постоянной частоты кадров мы просто добавляем задержку в поток поиска кадров. Задержка для получения примерно ~30 FPS делает хорошую работу для «нормализации» частоты кадров и сглаживания перехода между кадрами в случае потери пакетов.

Примечание: Мы должны попытаться сопоставить частоту кадров потока, но я не уверен, что такое FPS веб-камеры, поэтому я только предположил 30 FPS. Кроме того, обычно вместо прямого промежуточного веб-сервера используется прямая ссылка на поток, что может значительно повысить производительность.


Если вы попытаетесь использовать сохраненный .mp4 видеофайл, вы заметите, что тамнет дрожанияЭто подтверждает мое подозрение, что проблема, скорее всего, связана с задержкой в ​​сети.

from threading import Thread
import cv2, time

class ThreadedCamera(object):
    def __init__(self, src=0):
        self.capture = cv2.VideoCapture(src)
        self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)

        # FPS = 1/X
        # X = desired FPS
        self.FPS = 1/30
        self.FPS_MS = int(self.FPS * 1000)

        # Start frame retrieval thread
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()
            time.sleep(self.FPS)

    def show_frame(self):
        cv2.imshow('frame', self.frame)
        cv2.waitKey(self.FPS_MS)

if __name__ == '__main__':
    src = 'https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8'
    threaded_camera = ThreadedCamera(src)
    while True:
        try:
            threaded_camera.show_frame()
        except AttributeError:
            pass
0 голосов
/ 09 октября 2019

Попытка поточить

Я попытался это решение из nathancy с небольшим успехом.

Включает:

  • создание отдельного потока для захвата изображения из источника
  • с использованием основного потока исключительно для отображения.

Код:

import cv2
from threading import Thread

class ThreadedCamera(object):
    def __init__(self, source = 0):

        self.capture = cv2.VideoCapture(source)

        self.thread = Thread(target = self.update, args = ())
        self.thread.daemon = True
        self.thread.start()

        self.status = False
        self.frame  = None

    def update(self):
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()

    def grab_frame(self):
        if self.status:
            return self.frame
        return None  
if __name__ == '__main__':
    stream_link = "https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8"
    streamer = ThreadedCamera(stream_link)

    while True:
        frame = streamer.grab_frame()
        if frame is not None:
            cv2.imshow("Context", frame)
        cv2.waitKey(1) 

Беспорядочные, но в режиме реального времени результаты

.

Потоковая работа. Он поддерживает в режиме реального времени. Однако создается впечатление, что все кадры объединяются и внезапно врываются в видео. Я хотел бы, чтобы кто-нибудь объяснил это.

Пространство для улучшения

Поток в реальном времени можно найти здесь.

https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet

Этот сайт очищен для m3u8 с использованием потокового скребка Python streamlink.


import streamlink

streams = streamlink.streams("https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet")
print(streams)

, что приводит к:

OrderedDict([

('720p',<HLSStream('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w202109066.m3u8')>),

('live', <RTMPStream({'rtmp': 'rtmp://videos3.earthcam.com/fecnetwork/', 'playpath': '9974.flv', 'pageUrl': 'https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet','swfUrl': 'http://static.earthcam.com/swf/streaming/stream_viewer_v3.swf', 'live': 'true'}, redirect=False>),

('worst', <HLSStream('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w202109066.m3u8')>),

('best', <RTMPStream({'rtmp': 'rtmp://videos3.earthcam.com/fecnetwork/', 'playpath': '9974.flv', 'pageUrl': 'https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet', 'swfUrl': 'http://static.earthcam.com/swf/streaming/stream_viewer_v3.swf', 'live': 'true'}, redirect=False>)

])


Возможность неправильного чтения потоков.

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