python - Pipetear imágenes OpenCV sin procesar a FFmpeg
linux (3)
Hizo un montón de manipulación, pero lo descubrí usando el demuxer de video sin procesar de FFmpeg:
python capture.py | ffmpeg -f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 -i - foo.avi
Como no hay un encabezado en el video sin formato que especifique los parámetros de video asumidos, el usuario debe especificarlos para poder decodificar los datos correctamente:
-
-framerate
Establece la velocidad de cuadro de video de entrada. El valor predeterminado es 25. -
-pixel_format
Establece el formato de píxeles de video de entrada. El valor predeterminado es yuv420p. -
-video_size
Configura el tamaño del video de entrada. No hay un valor predeterminado, por lo que este valor debe especificarse explícitamente.
Y aquí hay algo extra para los usuarios avanzados. Lo mismo pero usando VLC para transmitir la salida en vivo a la web, formato Flash:
python capture.py | cvlc --demux=rawvideo --rawvid-fps=30 --rawvid-width=320 --rawvid-height=240 --rawvid-chroma=RV24 - --sout "#transcode{vcodec=h264,vb=200,fps=30,width=320,height=240}:std{access=http{mime=video/x-flv},mux=ffmpeg{mux=flv},dst=:8081/stream.flv}"
Editar: crea una secuencia de webm usando ffmpeg y ffserver
python capture.py | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 640x480 -framerate 25 -i - http://localhost:8090/feed1.ffm
Aquí hay un ejemplo bastante sencillo de lectura de una cámara web utilizando enlaces de python de OpenCV:
''''''capture.py''''''
import cv, sys
cap = cv.CaptureFromCAM(0) # 0 is for /dev/video0
while True :
if not cv.GrabFrame(cap) : break
frame = cv.RetrieveFrame(cap)
sys.stdout.write( frame.tostring() )
Ahora quiero canalizar la salida a ffmpeg como en:
$ python capture.py | ffmpeg -f image2pipe -pix_fmt bgr8 -i - -s 640x480 foo.avi
Lamentablemente, no puedo obtener el hechizo mágico ffmpeg bastante bien y falla con
libavutil 50.15. 1 / 50.15. 1 libavcodec 52.72. 2 / 52.72. 2 libavformat 52.64. 2 / 52.64. 2 libavdevice 52. 2. 0 / 52. 2. 0 libavfilter 1.19. 0 / 1.19. 0 libswscale 0.11. 0 / 0.11. 0 libpostproc 51. 2. 0 / 51. 2. 0 Output #0, avi, to ''out.avi'': Stream #0.0: Video: flv, yuv420p, 640x480, q=2-31, 19660 kb/s, 90k tbn, 30 tbc [image2pipe @ 0x1508640]max_analyze_duration reached [image2pipe @ 0x1508640]Estimating duration from bitrate, this may be inaccurate Input #0, image2pipe, from ''pipe:'': Duration: N/A, bitrate: N/A Stream #0.0: Video: 0x0000, bgr8, 25 fps, 25 tbr, 25 tbn, 25 tbc swScaler: 0x0 -> 640x480 is invalid scaling dimension
- Los cuadros capturados son definitivamente 640x480.
- Estoy bastante seguro de que el orden de píxeles para el tipo de imagen OpenCV (IplImage) es GBR, un byte por canal. Al menos, eso es lo que parece salir de la cámara.
No soy un gurú de ffmpeg. ¿Alguien ha hecho esto exitosamente?
Me llevó una hora descubrir que, de forma predeterminada, los conductos de Windows no son binarios. Esto ocasiona que algunos bytes (específicamente líneas nuevas) sean modificados / omitidos, y el video resultante se desplaza lentamente porque el tamaño del cuadro no es constante.
Para solucionar esto, el archivo de python modificado:
"""
videoCapture.py
"""
import cv2, sys
import time
if sys.platform == "win32":
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
cap = cv2.VideoCapture(0) # 0 is for /dev/video0
while True :
ret, frm = cap.read()
sys.stdout.write( frm.tostring() )
Para probar si la canalización del video en bruto es exitosa, use ffplay. Asegúrese de especificar una tasa de fotogramas mayor que la que proviene de la tubería, de lo contrario, el video comenzará a lag
python videoCapture.py | ffplay -f rawvideo -pix_fmt bgr24 -s 640x480 -framerate 40 -i -
No estoy seguro de si esto es específico de Mac OS, o específico de python3, pero necesitaba convertir el marco en una cadena para que esto funcione para mí, así:
sys.stdout.write(str(frame.tostring()))