web-dev-qa-db-ja.com

生のOpenCV画像をFFmpegにパイプする

以下は、OpenCVのpython bindingsを使用してWebカメラを読み取る簡単な例です。

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

次のように出力をffmpegにパイプしたいと思います。

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

悲しいことに、ffmpegの魔法の呪文を正しく理解できず、失敗します

 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達する
 [image2pipe @ 0x1508640]ビットレートから継続時間を推定しています。これは不正確な場合があります
入力#0、image2pipe、from 'pipe:':
期間:N/A、ビットレート:N/A 
ストリーム#0.0:ビデオ:0x0000、bgr8、25 fps 、25 tbr、25 tbn、25 tbc 
 swScaler:0x0-> 640x480は無効なスケーリングディメンション
  • キャプチャされたフレームは間違いなく640x480です。
  • OpenCV画像タイプ(IplImage)のピクセル順序は、チャネルごとに1バイトのGBRであると確信しています。少なくとも、それはカメラから外れているようです。

私はffmpegの第一人者ではありません。誰かがこれを成功させましたか?

25
BrianTheLion

いじくり回しましたが、FFmpeg rawvideo demuxer

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

想定されるビデオパラメータを指定する生のビデオにはヘッダーがないため、ユーザーはデータを正しくデコードできるようにヘッダーを指定する必要があります。

  • -framerate入力ビデオのフレームレートを設定します。デフォルト値は25です。
  • -pixel_format入力ビデオのピクセル形式を設定します。デフォルト値はyuv420pです。
  • -video_size入力ビデオのサイズを設定します。デフォルトはないため、この値は明示的に指定する必要があります。

そして、パワーユーザーのために少し余分なものがあります。同じことですが、VLCを使用してライブ出力をWeb、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}"

編集:ffmpegとffserverを使用してwebmストリームを作成します

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

私は最近は親切ですが、私の強力な VidGear Python =ライブラリは、任意のプラットフォームでOpenCVフレームをFFmpegにパイプライン処理するプロセスを自動化します。基本的なpythonの例:

# 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

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

より高度なアプリケーションと機能については、 VidGear Docs をチェックしてください。

お役に立てば幸いです。

2
abhiTronix

デフォルトでは、Windowsパイプはバイナリではないことを理解するのに1時間かかりました。これにより、一部のバイト(特に改行)が変更または省略され、フレームサイズが一定ではないため、結果のビデオはゆっくりとシフトします。

これを回避するために、変更されたpythonファイル:

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

生のビデオのパイプ処理が成功したかどうかをテストするには、ffplayを使用します。パイプからのフレームレートよりも高いフレームレートを指定してください。そうしないと、ビデオが遅れ始めます。

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

これがMac OS固有かpython3固有かはわかりませんが、これを機能させるには、次のようにフレームを文字列にキャストする必要がありました。

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