簡體   English   中英

使用 python opencv 編寫 mp4 視頻

[英]Writing an mp4 video using python opencv

我想從網絡攝像頭捕獲視頻並使用 opencv 將其保存到 mp4 文件。 我在stackoverflow(下)上找到了很好的示例代碼。 唯一的問題是我試圖將其保存為 mp4,而不是 avi。 我不明白的部分是傳遞給 FOURCC 編寫器的“XVID”參數應該是,我認為,一個 mp4 編解碼器(來自這個鏈接)。 如果我將文件名更改為“output.mp4”,它會告訴我標簽無效,所以我必須相信 XVID 編解碼器實際上是在制作 avi 文件。 這是一個愚蠢的問題嗎? 如何寫入 mp4?

我找到了顯示如何將 avi 轉換為 mp4 的鏈接,但這似乎效率低下。 似乎我應該能夠在初始寫入期間做到這一點。

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.cv.CV_FOURCC(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

這對我有用。

self._name = name + '.mp4'
self._cap = VideoCapture(0)
self._fourcc = VideoWriter_fourcc(*'MP4V')
self._out = VideoWriter(self._name, self._fourcc, 20.0, (640,480))

對我有用的是確保輸入的“幀”大小等於輸出視頻的大小(在本例中為 (680, 480) )。

http://answers.opencv.org/question/27902/how-to-record-video-using-opencv-and-python/

這是我的工作代碼(Mac OSX Sierra 10.12.6):

cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)

fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 20.0, (640,480))

while(True):
    ret, frame = cap.read()
    out.write(frame)
    cv2.imshow('frame', frame)
    c = cv2.waitKey(1)
    if c & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

注意:我按照@10SecTom 的建議安裝了 openh264,但我不確定這是否與問題有關。

以防萬一:

brew install openh264

您的代碼中有一些需要更改的地方:

  1. 將輸出名稱更改為“output.mp4”(更改為 .mp4)
  2. 我遇到了人們在評論中遇到的同樣問題,所以我將fourcc更改為0x7634706dout = cv2.VideoWriter('output.mp4',0x7634706d , 20.0, (640,480))

這是保存相機拍攝的視頻的默認代碼

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

大約兩分鍾的剪輯捕捉到了FULL HD

使用

cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
cap.set(3,1920)
cap.set(4,1080)
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (1920,1080))

保存的文件超過150MB

然后不得不使用ffmpeg來減小保存的文件大小,根據需要更改的視頻質量在30MB60MB之間使用crf降低 crf 更好的視頻質量並生成更大的文件大小。 您還可以更改格式avimp4mkv

然后我找到了ffmpeg-python

這是使用ffmpeg-python將每幀的numpy array保存為視頻的代碼

import numpy as np
import cv2
import ffmpeg

def save_video(cap,saving_file_name,fps=33.0):

    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            i_width,i_height = frame.shape[1],frame.shape[0]
            break

    process = (
    ffmpeg
        .input('pipe:',format='rawvideo', pix_fmt='rgb24',s='{}x{}'.format(i_width,i_height))
        .output(saved_video_file_name,pix_fmt='yuv420p',vcodec='libx264',r=fps,crf=37)
        .overwrite_output()
        .run_async(pipe_stdin=True)
    )

    return process

if __name__=='__main__':

    cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
    cap.set(3,1920)
    cap.set(4,1080)
    saved_video_file_name = 'output.avi'
    process = save_video(cap,saved_video_file_name)

    while(cap.isOpened()):
        ret, frame = cap.read()
        if ret==True:
            frame = cv2.flip(frame,0)
            process.stdin.write(
                cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    .astype(np.uint8)
                    .tobytes()
                    )

            cv2.imshow('frame',frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                process.stdin.close()
                process.wait()
                cap.release()
                cv2.destroyAllWindows()
                break
        else:
            process.stdin.close()
            process.wait()
            cap.release()
            cv2.destroyAllWindows()
            break

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

'mp4v' 不返回錯誤,這與在fourcc 中定義的'MP4V' 不同

對於錯誤:

“OpenCV:FFMPEG:標簽 0x5634504d/'MP4V' 不支持編解碼器 id 13 和格式'mp4 / MP4(MPEG-4 第 14 部分)' OpenCV:FFMPEG:回退使用標簽 0x00000020/'???'”

這對我有用,我添加了 images.sort() 以保持序列順序:

import cv2
import numpy as np
import os

image_folder = 'data-set-race-01'
video_file = 'race-01.mp4'
image_size = (160, 120)
fps = 24

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
images.sort()

out = cv2.VideoWriter(video_file, cv2.VideoWriter_fourcc(*'MP4V'), fps, image_size)

img_array = []
for filename in images:
    img = cv2.imread(os.path.join(image_folder, filename))
    img_array.append(img)
    out.write(img)

out.release()

對於仍在為問題苦苦掙扎的人。 根據這篇文章,我使用了這個示例,它對我有用:

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'X264')
out = cv2.VideoWriter('output.mp4',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

所以我不得不使用cv2.VideoWriter_fourcc(*'X264')編解碼器。 使用從源代碼編譯的 OpenCV 3.4.3 進行測試。

任何正在尋找使用 OpenCV 或 FFmpeg 編寫 MP4 文件的最方便和最強大的方法的人,都可以查看我最先進的VidGear視頻處理 Python 庫的WriteGear API ,它可與OpenCV 后端FFmpeg 后端一起使用,甚至支持 GPU 編碼器. 這是一個在帶有 FFmpeg 后端的 WriteGear 中使用 H264 編碼器進行編碼的示例:

# import required libraries
from vidgear.gears import WriteGear
import cv2

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

# Open suitable video stream, such as webcam on first index(i.e. 0)
stream = cv2.VideoCapture(0) 

# Define writer with defined parameters and suitable output filename for e.g. `Output.mp4`
writer = WriteGear(output_filename = 'Output.mp4', logging = True, **output_params)

# loop over
while True:

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

    # check for frame if not grabbed
    if not grabbed:
      break

    # {do something with the frame here}
    # lets convert frame to gray for this example
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

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

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

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

# close output window
cv2.destroyAllWindows()

# safely close video stream
stream.release()

# safely close writer
writer.close() 
  • 來源: https ://github.com/abhiTronix/vidgear
  • 文檔: https ://abhitronix.github.io/vidgear/
  • 更多 FFmpeg 后端示例: https ://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/
  • OpenCV 后端示例: https ://abhitronix.github.io/vidgear/gears/writegear/non_compression/usage/

諸如OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 13 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x00000020/' ???' 也許您的輸出視頻大小與原始視頻不同。 您可以先查看視頻的幀大小。

您需要將編解碼器設置為'mp4v'小寫)。 如果設置為大寫,則會拋出一個錯誤,說不支持,建議改用小寫: OpenCV: FFMPEG :fallback to use tag 0x7634706d/'mp4v' 您可能還想查看VideoWriter的文檔以及此處給出的示例。 另外,請確保您的輸出視頻的大小等於您的輸入frame大小(下面使用VideoCapture對象的尺寸來處理這個問題)。

cap = cv2.VideoCapture(0)
w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS) 
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, fps, (int(w),int(h)))

您可以通過設置fourcc=-1來獲取可用於mp4等的編解碼器的完整列表。 例如:

out = cv2.VideoWriter('output.mp4', -1, fps, (int(w),int(h)))

關於 VideoWriter,OpenCV 文檔不是很豐富,但是我設法通過以下方式使其工作(通過查看堆棧跟蹤):

import cv2

HEIGHT = 480
WIDTH = 640
FPS = 30.0

cap = cv2.VideoCapture(0, cv2.CAP_ANY)

cap.set(cv2.CAP_PROP_FPS, FPS)
cap.set(cv2.CAP_PROP_CONVERT_RGB , 1)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 100)


cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# output parameters such as fps and size can be changed
output = cv2.VideoWriter("output.mp4", fourcc, FPS, (WIDTH, HEIGHT))

while True:
    if cap.isOpened():
        (ret, frame) = cap.read()
        if ret:
            output.write(frame)
        cv2.imshow("frame", frame)

    if cv2.waitKey(10) == ord('q'):
        break

output.release()
cap.release()
cv2.destroyAllWindows()

堆棧跟蹤錯誤是:

OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 12 and 
format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x7634706d/'mp4v'

不幸的是,很難找到 OpenCV 使用的官方編解碼器列表,或者至少我找不到它們。 無論如何,您似乎必須輸入以小寫形式編寫的編解碼器“mp4v”。

https://docs.opencv.org/3.4/dd/d01/group__videoio__c.html#gac005718f121379beffdbdbfb44f2646a

我注意到的一件重要的事情是幀和輸出視頻的縱橫比必須相同,這就是為什么我使用兩個變量來表示高度和寬度。 如果這兩個不同,則創建文件,但不保存幀(您總是得到一個 1KB 的 mp4 文件)。 為避免任何問題,您可以對 FPS 執行相同操作。

只需將編解碼器更改為"DIVX" 此編解碼器適用於所有格式。

fourcc = cv2.VideoWriter_fourcc(*'DIVX')

我希望這對你有用!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM