Estoy desarrollando un módulo de Python, con OpenCV, que se conecta a una transmisión RTSP para realizar un preprocesamiento en el video (principalmente, reducir los fps y la resolución), y luego almacenarlo en el sistema de archivos.
Pero, incluso después de probar varios códecs, buscando desarrollos similares... siempre termino con un video vacío. He visto este otro hilo ( cv::VideoWriter produce un video ilegible ), que puede ser similar, pero fue desarrollado en C++.
¿Alguien ha trabajado en esto? Normalmente utilizo un flujo RTSP de muestra como referencia, como rtsp://freja.hiof.no:1935/rtplive/ definst /hessdalen03.stream, y puedo recibir e incluso ver el flujo desde VLC correctamente.
He visto bastantes hilos discutiendo cómo capturar video de una transmisión RTSP, o cómo trabajar con clases de VideoWriters y VideoReaders y archivos de video, pero casi nada combinando los dos.
Cualquier ayuda sería muy apreciada:) ¡Gracias!
Edición 1: código de muestra utilizado para almacenar los marcos.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy
# Test frame.
width, height = 400, 300
width_2, height_2 = int(width / 2), int(height / 2)
frame = numpy.zeros((height, width, 3), numpy.uint8)
cv2.rectangle(frame, (0, 0), (width_2, height_2), (255, 0, 0), cv2.FILLED)
cv2.rectangle(frame, (width_2, height_2), (width, height), (0, 255, 0), cv2.FILLED)
frames = [frame for _ in range(100)]
fps = 25
# Define the codec.
#fourcc = cv2.VideoWriter_fourcc(*'X264')
#fourcc = cv2.VideoWriter_fourcc(*'XVID')
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
# Create VideoWriter object
out = cv2.VideoWriter(filename='video.avi',
fourcc=fourcc,
apiPreference=cv2.CAP_FFMPEG,
fps=float(fps),
frameSize=(width, height),
isColor=True)
result = 0
for frame in frames:
result += 0 if out.write(frame) is None else 1
print(result)
out.release()
Edición 2: Solución
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy
# Test frame.
width, height = 400, 300
width_2, height_2 = int(width / 2), int(height / 2)
frame1 = numpy.zeros((height, width, 3), numpy.uint8)
cv2.rectangle(frame1, (0, 0), (width_2, height_2), (255, 0, 0), cv2.FILLED)
cv2.rectangle(frame1, (width_2, height_2), (width, height), (0, 255, 0), cv2.FILLED)
cv2.imwrite('frame1.jpg', frame1)
frame2 = numpy.zeros((height, width, 3), numpy.uint8)
cv2.rectangle(frame2, (width_2, 0), (width, height_2), (255, 0, 0), cv2.FILLED)
cv2.rectangle(frame2, (0, height_2), (width_2, height), (0, 255, 0), cv2.FILLED)
cv2.imwrite('frame2.jpg', frame2)
range1 = [frame1 for _ in range(10)]
range2 = [frame2 for _ in range(10)]
frames = range1 + range2 + range1 + range2 + range1
fps = 2
# Define the codec.
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
# Create VideoWriter object
out = cv2.VideoWriter('video.avi', fourcc, float(fps), (width, height))
for frame in frames:
out.write(frame)
out.release()
Solución del problema
Aquí hay un widget de flujo de RTSP a video. Recomendaría crear otro hilo para obtener los marcos como cv2.VideoCapture.read()
está bloqueando. Esto puede ser costoso y causar latencia ya que el subproceso principal tiene que esperar hasta que haya obtenido un marco. Al colocar esta operación en un subproceso separado que solo se enfoca en capturar fotogramas y procesar/guardar los fotogramas en el subproceso principal, mejora drásticamente el rendimiento. También puede experimentar con otros códecs, pero su uso MJPG
debería ser seguro ya que está integrado en OpenCV. Usé la transmisión de mi cámara IP y guardé los marcos en output.avi
. Asegúrese de cambiar rtsp_stream_link
a su propio enlace de transmisión RTSP.:)
from threading import Thread
import cv2
class RTSPVideoWriterObject(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
# Default resolutions of the frame are obtained (system dependent)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
self.output_video = cv2.VideoWriter('output.avi', self.codec, 30, (self.frame_width, self.frame_height))
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def show_frame(self):
# Display frames in main program
if self.status:
cv2.imshow('frame', self.frame)
# Press Q on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
self.output_video.release()
cv2.destroyAllWindows()
exit(1)
def save_frame(self):
# Save obtained frame into video output file
self.output_video.write(self.frame)
if __name__ == '__main__':
rtsp_stream_link = 'your stream link!'
video_stream_widget = RTSPVideoWriterObject(rtsp_stream_link)
while True:
try:
video_stream_widget.show_frame()
video_stream_widget.save_frame()
except AttributeError:
pass
No hay comentarios:
Publicar un comentario