OpenCV_003-視頻入門

本文主要內容來自於 OpenCV-Python 教程OpenCV 中的 GUI 功能 部分,這個部分的主要內容如下:

目標

從攝像頭採集視頻

通常,我們必須用攝像頭捕捉實時流。OpenCV 提供了一個非常簡單的接口來做這些。讓我們從攝像頭採集一段視頻(我使用我筆記本電腦上內置的 webcam),把它轉換爲灰度視頻並顯示。只是一個入門的簡單任務。

要捕捉視頻,我們需要創建一個 VideoCapture 對象。它的參數可以是設備索引或視頻文件的文件名。設備索引只是一個用於指定使用那個攝像頭的數字。通常連接了一個攝像頭(就我而言)。因而,我簡單地傳入 0 (或 -1)。你可以通過傳入 1 選擇第二個攝像頭等等。隨後你可以一幀一幀地捕捉圖像。最後,不要忘記釋放 capture。

#!/use/bin/env python
import sys

import numpy as np
import cv2 as cv


def main():
    cap = cv.VideoCapture(0)
    if not cap.isOpened():
        print("Cannot open camera")
        sys.exit()

    while True:
        # Capture frame-by-frame
        ret, frame = cap.read()

        # if frame is read correctly ret is True
        if not ret:
            print("Can't receive frame() (stream end?). Exiting ...")
            break
        # Our operations on the frame come here
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        # Display the resulting frame
        cv.imshow('frame', gray)
        if cv.waitKey(1) == ord('q'):
            break

    cap.release()
    cv.destroyAllWindows()


if __name__ == "__main__":
    main()

cap.read() 返回一個布爾值 (True/False)。如果正確地讀取了幀,它爲 True。因此可以通過檢查這個返回值來確認視頻是否結束。

有時,cap 可能還沒有初始化捕捉。在那種情況下,這段代碼將顯示錯誤。我們可以通過 cap.isOpened() 方法檢查它是否初始化。如果它是 True,則 OK。否則使用 cap.open() 打開它。

我們還可以使用 cap.get(propId) 方法訪問這個視頻的一些功能,其中 propId 是一個從 0 到 68 的數字。每個數字表示視頻的一個屬性(如果它適用於該視頻的話)。完整的描述可以在這裏找到:cv::VideoCapture::get()。這些值中的一些可以使用 cap.set(propId, value) 來修改。value 是想要的新值。

比如,我們可以通過 cap.get(cv.CAP_PROP_FRAME_WIDTH)cap.get(cv.CAP_PROP_FRAME_HEIGHT) 檢查幀的寬度和高度。它默認給出了 640x480。但我們想要把它修改爲 320x240。則使用 ret = cap.set(cv.CAP_PROP_FRAME_WIDTH,320) 和 ret = cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)。如:

    width = cap.get(cv.CAP_PROP_FRAME_WIDTH)
    height = cap.get(cv.CAP_PROP_FRAME_WIDTH)
    fps = cap.get(cv.CAP_PROP_FPS)
    print("FPS:{}, width x height: {} x {}".format(fps, width, height))

可以得到如下輸出:

FPS:30.0, width x height: 640.0 x 640.0

注意:如果遇到了錯誤,則可以使用任何其它的攝像頭應用程序(比如 Linux 下的 Cheese)來確認攝像頭是否工作良好。

播放視頻文件

播放視頻文件與從攝像頭採集類似,只是把攝像頭索引改爲視頻文件的文件名。同樣在顯示視頻幀的時候,傳入適當的時間調用 cv.waitKey()。如果時間值太低,則視頻會非常快,如果它太高,則視頻會非常慢(好吧,這就是我們可以慢動作顯示視頻的方式)。一般情況下 25 毫秒就不錯。

def play_video_file():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
    while cap.isOpened():
        ret, frame = cap.read()
        # if frame is read correctly ret is True
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        cv.imshow('frame', gray)
        if cv.waitKey(25) == ord('q'):
            break
    cap.release()
    cv.destroyAllWindows()

cap.get(propId) 可用的 propId 由一些枚舉值定義,這其中部分適用於攝像頭的 VideoCapture,部分則適用於視頻文件的 VideoCapture。對於視頻文件,我們可以通過給 cap.get(propId) 傳入 cv.CAP_PROP_FRAME_COUNT 獲得視頻文件的視頻幀總數。

注意,請確保安裝了適當版本的 ffmpeg 或 gstreamer。有時使用 video capture 比較頭疼,這大多數是由於 ffmpeg/gstreamer 的錯誤安裝。

保存視頻

我們捕捉了視頻,並能一幀一幀地處理它,但我們還想保存視頻。對於圖像,它很簡單:使用 cv.imwrite() 就好。在這裏,需要做更多的工作。

這次我們創建一個 VideoWriter 對象。我們應該指定輸出文件名(比如:output.avi)。然後我們應該指定 FourCC 碼(下一段會有詳細說明)。應該傳入每秒多少幀 (fps) 以及幀大小。最後一個是 isColor 標記。如果它是 True,則編碼器期望是彩色幀,否則,它使用灰度幀。

FourCC 是一個用於指定視頻編解碼器的 4 字節碼。在其官網 fourcc.org 可以找到可用的編解碼器的列表。它是平臺獨立的。以下編解碼器對我來說很好用。

  • 在 Fedora 中:DIVX,XVID,MJPG,X264,WMV1,WMV2。(XVID 是更優選的。 MJPG 會產生大尺寸的視頻。 X264 提供非常小尺寸的視頻)
  • 在 Windows 上:DIVX (更多有待測試和添加)
  • 在 OSX 上:MJPG (.mp4),DIVX (.avi),X264 (.mkv)。

cv.VideoWriter_fourcc('M','J','P','G')cv.VideoWriter_fourcc(*'MJPG') 的形式爲 MJPG 傳 FourCC
碼。

如下的代碼從攝像頭捕捉圖形,在垂直方向翻轉每一幀,並保存視頻。

def save_video_file():
    cap = cv.VideoCapture(0)
    # Define the codec and create VideoWriter object
    fourcc = cv.VideoWriter_fourcc(*'XVID')
    out = cv.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        frame = cv.flip(frame, 0)
        # write the flipped frame
        out.write(frame)
        cv.imshow('frame', frame)
        if cv.waitKey(1) == ord('q'):
            break
    # Release everything if job is finished
    cap.release()
    out.release()
    cv.destroyAllWindows()

Done.

參考文檔 Getting Started with Videos

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章