it-swarm.com.de

Rohe OpenCV-Bilder an FFmpeg

Hier ein recht einfaches Beispiel für das Ablesen einer Web-Cam mit Python-Bindings von 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() )

Nun möchte ich die Ausgabe an ffmpeg weiterleiten wie in:

$ python capture.py | ffmpeg -f image2pipe -pix_fmt bgr8 -i - -s 640x480 foo.avi

Leider kann ich die magische Zauberformel von ffmpeg nicht ganz richtig hinbekommen, und es schlägt fehl

 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 
 Ausgabe # 0, avi an 'out.avi': 
 Stream # 0.0: Video: flv, yuv420p 640x480, q = 2-31, 19660 kb/s, 90 ktbb, 30 tbc 
 [Image2pipe @ 0x1508640] max_analyze_duration erreicht 
 [Image2pipe @ 0x1508640] Die voraussichtliche Dauer der Bitrate ist ungenau 
 Eingabe # 0, image2pipe, aus 'pipe:': 
 Dauer: N/A, Bitrate: N/A 
 Stream # 0.0: Video: 0x0000, bgr8, 25 fps , 25 tbr, 25 tbn, 25 tbc 
 SwScaler: 0x0 -> 640x480 ist ungültige Skalierungsdimension 
  • Die aufgenommenen Bilder sind definitiv 640x480.
  • Ich bin mir ziemlich sicher, dass die Pixelreihenfolge für den OpenCV-Bildtyp (IplImage) GBR ist, ein Byte pro Kanal. Zumindest scheint das aus der Kamera zu kommen.

Ich bin kein ffmpeg-Guru. Hat jemand das erfolgreich gemacht?

24
BrianTheLion

Habe ein bisschen Fummelchen gemacht, aber ich habe es mit FFmpeg rawvideo demuxer herausgefunden:

python capture.py | ffmpeg -f rawvideo -pixel_format bgr24 -video_size 640x480 -framerate 30 -i - foo.avi

Da es im Rohvideo keinen Header gibt, der die angenommenen Videoparameter angibt, muss der Benutzer diese angeben, um die Daten richtig decodieren zu können:

  • -framerate Eingangsvideo-Bildrate einstellen. Der Standardwert ist 25.
  • -pixel_format Legt das Pixelformat für das Eingabevideo fest. Der Standardwert ist yuv420p.
  • -video_size Legt die Größe des Eingangsvideos fest. Es gibt keinen Standardwert, daher muss dieser Wert explizit angegeben werden.

Und hier ist ein kleines Extra für die Power User. Gleiches, aber die Verwendung der VLC zum Streamen der Live-Ausgabe im Web im Flash-Format:

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}"

Edit: Erstellen Sie einen Webm-Stream mit ffmpeg und ffserver

python capture.py | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 640x480 -framerate 25 -i - http://localhost:8090/feed1.ffm
31
BrianTheLion

Ich bin ein bisschen spät dran, aber meine mächtige VidGear Python Library automatisiert das Pipelining von OpenCV-Frames in FFmpeg auf jeder Plattform . Hier ist ein einfaches python Beispiel:

# import libraries
from vidgear.gears import WriteGear
import cv2

output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg Tweak parameters for writer

stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device

writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4' 

# infinite loop
while True:

    (grabbed, frame) = stream.read()
    # read frames

    # check if frame empty
    if not is grabbed:
        #if True break the infinite loop
        break


    # {do something with frame here}
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # write a modified frame to writer
        writer.write(gray) 

        # Show output window
    cv2.imshow("Output Frame", frame)

    key = cv2.waitKey(1) & 0xFF
    # check for 'q' key-press
    if key == ord("q"):
        #if 'q' key-pressed break out
        break

cv2.destroyAllWindows()
# close output window

stream.release()
# safely close video stream
writer.close()
# safely close writer

Quelle: https://github.com/abhiTronix/vidgear/wiki/Compression-Mode:-FFmpeg#2-writegear-apicompression-mode-with-opencv-directly

Sie können in VidGear Docs nach erweiterten Anwendungen und Funktionen suchen.

Hoffentlich hilft das!

2
AbhiTronix

Ich brauchte eine Stunde, um herauszufinden, dass Windows-Pipes standardmäßig nicht binär sind. Dies bewirkt, dass einige Bytes (insbesondere Newlines) geändert/weggelassen werden, und das resultierende Video wird langsam verschoben, da die Bildgröße nicht konstant ist.

Um dies zu umgehen, die modifizierte Python-Datei:

"""
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() )

Verwenden Sie ffplay, um zu testen, ob das Pipeing des Rohvideos erfolgreich ist. Vergewissern Sie sich, dass Sie eine höhere Bildrate als die von der Pipe kommenden Daten angeben. Andernfalls beginnt das Video zu verzögern

python videoCapture.py | ffplay -f rawvideo -pix_fmt bgr24 -s 640x480 -framerate 40 -i -
1
hgabe

Nicht sicher, ob dies Mac OS-spezifisch oder Python3-spezifisch ist, aber ich musste den Rahmen in eine Zeichenfolge umwandeln, damit dies für mich funktioniert:

sys.stdout.write(str(frame.tostring()))
0
Matt W