2024年2月20日 星期二

Python 學習筆記 : OpenCV (三) 視訊讀寫與顯示

今天繼續測試 OpenCV 功能, 本系列之前的文章參考 :


OpenCV 官方教學文件 (Python) 參考 :



一. 從檔案讀取視訊 : 

本篇要來測試 OpenCV 的視訊讀寫功能, 這要用到其 VideoCapture 類別, 它可以從檔案 (例如 mp4 檔) 或攝影機讀取視訊, 呼叫其建構式 VideoCapture() 會傳回一個 VideoCapture 物件, 其參數介面如下 : 

vcap=VideoCapture(file [, flag])             # 從檔案 file (含路徑) 讀取視訊


此處用來測試的影片是從 YT 下載, 網友改編自周星馳電影 "唐伯虎點秋香", 用來提醒明天要補班的片段 :





可以用線上 YT 轉 MP4 工具下載 : 


將下載的 mp4 檔案放在工作目錄下, 然後將檔名傳給 cv2.VideoCapture() 即可, 它會傳回一個包含兩元素的 tuple

>>> import cv2   
>>> vcap=cv2.VideoCapture('唐伯虎點秋香-記得明天要上班.mp4')   
>>> type(vcap)   
<class 'cv2.VideoCapture'>   

用 dir() 檢視 VideoCapture 物件的內容 :

>>> dir(vcap)  
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'get', 'getBackendName', 'getExceptionMode', 'grab', 'isOpened', 'open', 'read', 'release', 'retrieve', 'set', 'setExceptionMode', 'waitAny']

VideoCapture 物件提供一些方法可用來讀取視訊框, 常用者如下表 : 


 VideoCapture 物件方法 說明
 isOpened() 檢查影片檔是否正常開啟, 傳回 True/False
 read() 向下讀取一幀 (frame) 訊框, 傳回 (ret, frame), ret=True 表示讀取成功
 release() 釋放儲存視訊框的記憶體


顯示所讀取之視訊要用一個 while 無窮迴圈呼叫 VideoCapture 物件的 read() 方法依序讀取物件中的視訊框, 然後用 cv2.imshow() 顯示此訊框 (圖片), 並利用傳入 cv2.waitKey() 之延遲毫秒參數控制影片播放速度, 直到讀不到訊框 (ret=False) 跳出無窮迴圈為止. 

例如 :
# opencv_read_mp4_1.py
import cv2

vcap=cv2.VideoCapture('唐伯虎點秋香-記得明天要上班.mp4')  # 讀取 mp4 檔案
if not vcap.isOpened():   # 檢查檔案是否開啟成功
    print('無法開啟影片檔')
    exit()    # 跳出程式
while True:   
    ret, frame=vcap.read()   # 讀取下一個訊框
    if not ret:    # 檢查訊框是否已讀完
        print('未收到訊框')
        break      # 跳出迴圈
    cv2.imshow('videocapture', frame)    # 顯示此訊框
    if cv2.waitKey(50) == ord('q'):    # 延遲 50ms 期間若按下 'q' 跳出迴圈
        break
vcap.release()
cv2.destroyAllWindows()

截圖如下如下 :





此例中 cv2.waitKey() 參數值調小會讓動作變快, 調大則會變慢. 適當的值可參考影片檔的總幀數 與影片時間長度來決定, 只要將時長除以總幀數即可得到每幀要停留多久時間. 如果影片檔較小, 可以用下列網站來取得總幀數與時長 :


將影片檔上傳, 播完後即可得到總 frame 數與時長 :




可見此影片總框數為 776 框, 影片總長為 12.933 秒, 故每幀時間為 12.933/776=16.7 ms, 但 cv2.waitKey() 只能傳入整數, 故取 17 ms, 但播放起來還是覺得有點快動作, 改成 50 就比較自然了. 


二. 從攝影機讀取視訊 :  

如果是筆電或有外接攝影機的電腦, 只要將攝影機編號 (第一台編號 0, 第二台編號 1, ...) 傳給 VideoCapture() 建構式即可即時從攝影機擷取視訊, 將其分解為一幀幀的圖片 :

vcap=VideoCapture(camera [, flag])     # 從攝影機 camera (0, 1, 2 ...) 讀取視訊

用法與上面讀取影片檔類似, 只是將第一參數從檔案名稱字串改成攝影機編號而已, 例如 : 

import cv2

vcap=cv2.VideoCapture(0)   # 讀取編號 0 攝影機
if not vcap.isOpened():
    print('無法開啟攝影機')
    exit()
while True:
    ret, frame=vcap.read()
    if not ret:
        print('未收到訊框')
        break
    cv2.imshow('videocapture', frame)
    if cv2.waitKey(1) == ord('q'):      # 延遲時間用 1 影像較即時
        break
vcap.release()
cv2.destroyAllWindows()

注意, 此例 cv2.waitKey() 參數改為 1ms 才能喪影像反應更即時. 截圖如下 :




沒有留言 :