Saltar al contenido

La captura de video en tiempo real de OpenCV es lenta. ¿Cómo eliminar fotogramas o sincronizarlo con tiempo real?

Este escrito ha sido analizado por especialistas así aseguramos la veracidad de nuestro contenido.

Solución:

Mi hipótesis es que lo más probable es que la fluctuación se deba a limitaciones de la red y se produzca cuando se descarta un paquete de tramas. Cuando se descarta un fotograma, esto hace que el programa muestre el último fotograma “bueno”, lo que provoca que la pantalla se congele. Probablemente se trate de un problema de hardware o de ancho de banda, pero podemos solucionarlo con software. A continuación, se muestran algunos posibles cambios:

1. Establecer el tamaño máximo del búfer

Establecemos el cv2.videoCapture() objeto para tener un tamaño de búfer limitado con el cv2.CAP_PROP_BUFFERSIZE parámetro. La idea es que al limitar el búfer siempre tendremos el último fotograma. Esto también puede ayudar a aliviar el problema de los fotogramas que se adelantan aleatoriamente.

2. Establecer el retardo de recuperación de tramas

Actualmente, creo que read() está leyendo demasiado rápido a pesar de que está en su propio hilo dedicado. Esta puede ser una de las razones por las que todos los fotogramas parecen agruparse y estallar repentinamente en el siguiente fotograma. Por ejemplo, digamos en un intervalo de tiempo de un segundo, puede producir 15 nuevos fotogramas, pero en el siguiente intervalo de un segundo, solo se devuelven 3 fotogramas. Esto puede deberse a la pérdida de fotogramas del paquete de red, por lo que para asegurarnos de obtener velocidades de fotogramas constantes, simplemente agregamos un retraso en el hilo de recuperación de fotogramas. Un retraso para obtener aproximadamente ~30 FPS hace un buen trabajo para “normalizar” la velocidad de cuadros y suavizar la transición entre cuadros en caso de pérdida de paquetes.

Nota: Deberíamos intentar igualar la velocidad de fotogramas de la transmisión, pero no estoy seguro de cuál es el FPS de la cámara web, así que lo adiviné. 30 FPS. Además, suele haber un enlace de transmisión “directo” en lugar de pasar por un servidor web intermedio que puede mejorar considerablemente el rendimiento.


Si intenta utilizar un .mp4 archivo de video, notará que no hay jitter. Esto confirma mi sospecha de que el problema probablemente se deba a la latencia de la red.

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

Intento de enhebrar

Intenté esta solución desde nathancy con poco éxito.

Implica:

  • creando un hilo separado para la captura de imágenes desde la fuente
  • utilizando el hilo principal exclusivamente para la visualización.

Código:

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) 

Nervioso, pero resultados en tiempo real

.

La transmisión funciona. Mantiene el tiempo real. Sin embargo, es como si todos los fotogramas se juntaran y repentinamente estallaran en el video. Me gustaría que alguien me explicara eso.

Margen de mejora

La transmisión en tiempo real se puede encontrar aquí.

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

Este sitio se raspa para el m3u8 usando python streamlink raspador de corriente.


import streamlink

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

que yeilds:

OrderedDict([

('720p',),

('live', ),

('worst', ),

('best', )

])


La posibilidad de que las transmisiones se lean incorrectamente.

Agradecemos que quieras auxiliar nuestra investigación dejando un comentario y dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *