番外2. OpenCV 中攝像頭捕獲與視頻處理與常見問題解決方案
本系列專欄寫作方式
本系列專欄寫作將采用首創的問答式寫作形式,快速讓你學習到 OpenCV 的初級、中級、高級知識。
2. OpenCV 中攝像頭捕獲與視頻處理
OpenCV 除了應用在圖像處理領域外,還會應用到視頻處理領域,接下來我們就將學習到,如何通過Python OpenCV 對攝像頭捕獲或者視頻文件進行處理。
視頻文件將從三個方向入手,分別是讀取文件,顯示視頻,保存視頻。
本文將為你核心解決以下2個函數:cv2.VideoCapture 與 cv2.VideoWrite,基于這2個函數,會衍生出其它相關函數,具體參照下文。
在 OpenCV 中操作攝像頭相關注意事項和解決方案
攝像頭相較于視頻,差異在一個是實時圖像,一個是既定內容。如果想要捕獲到視頻,用到的是cv2.VideoCapture 函數,該函數的第一個參數是設備的索引號,如果你使用的是筆記本電腦,默認一般是0,表示的內置攝像頭,如果鏈接了外置,可以修改該數字即可。
最簡單的測試代碼如下:
import cv2 import numpy as np cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() # 轉變成灰度圖 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow("frame", gray) if cv2.waitKey() & 0xFF == ord("x"): break # 關閉攝像 cap.release() cv2.destroyAllWindows()
該代碼在運行時,如果你電腦未安裝攝像頭或者驅動異常,都會導致報錯,例如下述BUG
error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'
該問題雖然報錯出現在 cv2.cvtColor函數,但是原因是 frame 為空,即cap.read()讀取失敗導致的。
這里在實際編碼過程中,需要增加一個判斷,cap.read() 函數會返回一個狀態布爾值,如果讀取到數據,返回真,否則返回假,測試如下代碼(下述代碼的停止,需要按鍵盤上的CTRL+C ):
import cv2 import numpy as np cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() print(ret) # 關閉攝像 cap.release() cv2.destroyAllWindows()
測試完畢之后,我們修改本文一開始的代碼,讓其更加健壯。
while True: ret, frame = cap.read() if ret: # 轉變成灰度圖 gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow("frame", gray) # pass ...
這里存在一個常見,但是及容易被忽視的問題,就是很多時候,我們并不知道電腦上有沒有攝像頭,或者攝像頭的設備號,該如何進行操作。
你可以按照下述代碼進行檢測:
import cv2 import numpy as np for cn_num in range(0, 5): cap = cv2.VideoCapture(cn_num) if cap.isOpened(): break
以上代碼運行的原理是,按照順序依次打開設備 0~5,當發現攝像頭被成功打開,返回跳出。
上述代碼還提及了一個新的函數 cap.isOpened,該函數用來檢測攝像頭是否初始化(能被打開),初始化成功返回 True。
在 OpenCV 中操作視頻文件相關注意事項和解決方案
其實操作視頻文件與操作攝像頭操作基本一致,唯一修改的就是cv2.VideoCapture 函數設備號即可。
這里將設備號修改為視頻文件路徑。
接下來,我們先看一段代碼,認識基本用法。
import numpy as np import cv2 cap = cv2.VideoCapture('test.mp4') while cap.isOpened(): ret, frame = cap.read() # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) cv2.imshow('frame', frame) if cv2.waitKey(25) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
其中最需要注意的一個地方,不是 cv2.VideoCapture(‘test.mp4’) 函數讀取文件,而是 cv2.waitKey(25),這個地方需要設置好對應的視頻,如果數值特別小,例如 1,視頻就會快速播放,設置太高播放又會變慢,一般建議設置為 25。
當然,上述代碼注釋的部分,如果取消,就會變成一個灰度視頻。
甚至可以直接將視頻進行翻轉,用到函數為:cv2.flip(frame, 0),
import numpy as np import cv2 cap = cv2.VideoCapture('test.mp4') while cap.isOpened(): ret, frame = cap.read() if ret == True: frame = cv2.flip(frame, 0) cv2.imshow('frame', frame) if cv2.waitKey(25) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
上述代碼運行如下:
接下來我們用視頻來學習一下一些操作屬性的方法。
cv2.VideoCapture.get(propId) 可以訪問視頻的某些功能,其中 propId 是一個從0到18的數字,每個數字表示視頻的屬性。
取值清單如下(該清單只作為查詢參考使用):
0 - cv2.CAP_PROP_POS_MSEC: 視頻文件的當前位置(ms);
1 - cv2.CAP_PROP_POS_FRAMES:從0開始索引幀,幀位置;
2 - cv2.CAP_PROP_POS_AVI_RATIO:視頻文件的相對位置(0表示開始,1表示結束);
3 - cv2.CAP_PROP_FRAME_WIDTH:視頻流的幀寬度;
4 - cv2.CAP_PROP_FRAME_HEIGHT: 視頻流的幀高度;
5 - cv2.CAP_PROP_FPS:幀率;
6 - cv2.CAP_PROP_FOURCC : 編解碼器四字符代碼;
7 - cv2.CAP_PROP_FRAME_COUNT :視頻文件的幀數;
8 - cv2.CAP_PROP_FORMAT:retrieve()返回的Mat對象的格式;
9 - cv2.CAP_PROP_MODE :后端專用的值,指示當前捕獲模式;
10 - cv2.CAP_PROP_BRIGHTNESS :圖像的亮度,僅適用于支持的相機;
11 - cv2.CAP_PROP_CONTRAST :圖像對比度,僅適用于相機;
12 - cv2.CAP_PROP_SATURATION:圖像飽和度,僅適用于相機;
13 - cv2.CAP_PROP_HUE:圖像色調,僅適用于相機;
14 - cv2.CAP_PROP_GAIN:圖像增益,僅適用于支持的相機;
15 - cv2.CAP_PROP_EXPOSURE:曝光,僅適用于支持的相機;
16 - cv2.CAP_PROP_CONVERT_RGB:布爾標志,指示是否應將圖像轉換為RGB;
17 - cv2.CAP_PROP_WHITE_BALANCE:目前不支持;
18 - cv2.CAP_PROP_RECTIFICATION:立體攝像機的整流標志。
有了上述清單,可以獲取視頻較多的屬性值了,例如獲取寬度與高度。
cap = cv.VideoCapture('test.mp4') print("寬度:%s,高度:%s" % (cap.get(3), cap.get(4)))
有 get 方法,對應的就存在 set 函數,函數原型如下:
cap.set(propId,value) # 進行修改,value 是修改后的值
但這個地方要注意下,上面 set 函數只對采集攝像頭有用,如果讀取的是視頻文件,上述內容就不在起作用了。
如果你還是希望實現修改視頻文件的窗口大小,那可以使用下述方案。
cv2.namedWindow("frame", 0) cv2.resizeWindow("frame", 800,300)
如果想希望查看視頻播放的當前位置、幀率、幀數,可以直接使用下述代碼。
time = cap.get(cv2.CAP_PROP_POS_MSEC) fps = cap.get(cv2.CAP_PROP_FPS) total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
當然,使用屬性值也可以。
time = cap.get(0) fps = cap.get(5) total_frames = cap.get(7)
在 OpenCV 中捕獲視頻并保存
圖片的保存使用函數 cv2.imwrite即可實現,但視頻保存,需要與cv2.VideoCapture對應著,創建一個 VideoWriter對象,而且還需要確定文件的名稱,視頻 FourCC 編碼,頻率,幀大小,isColor標簽,該標簽如果為 True 則保存彩色圖,否則是灰度圖。
首先對 FourCC 進行一下說明,該編碼是一個4字節碼,表示的是視頻編碼格式。
例如對于 MJPG,它有兩種寫法。
注意這是 OpenCV 3 寫法,網上現在大多數博客都是 OpenCV 2 寫法。
cv2.VideoWriter_fourcc('M', 'J', 'P', 'G') cv2.VideoWriter_fourcc(*'MJPG')
常見編碼說明:
MJPG編碼器編碼的視頻非常大;
X264 編碼器編碼的視頻很小;
XVID編碼器優先選擇,質量較高且體積較小。
cv2.VideoWriter函數原型如下:
cv2.VideoWriter( filename, fourcc, fps, frameSize[, isColor] )
相關參數:
filename:視頻保存文件名稱;
fourcc:視頻編解碼器的4字節代碼;
fps:幀率;
frameSize:幀大小;
isColor:如果為True,則視頻為彩色,否則為灰度視頻,默認為True。
測試代碼如下,代碼之后跟相關問題的說明。
import numpy as np import cv2 cap = cv2.VideoCapture("test.mp4") width = int(cap.get(3)) height = int(cap.get(4)) fps = cap.get(5) # FourCC 編碼是 XVID fourcc = cv2.VideoWriter_fourcc(*'XVID') out = cv2.VideoWriter("test1.avi", fourcc, fps, (width, height)) while 1: ret, frame = cap.read() if frame is None: break else: # 對每一幀都進行處理 # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) out.write(frame) cv2.imshow("video", frame) k = cv2.waitKey(25) & 0xFF if k == 27: break cap.release() out.release() cv2.destroyAllWindows()
在調用函數 cv2.VideoWriter("test1.avi", fourcc, fps, (width, height)) 的時候,注意需要 (width, height) 必須是整數,需要強制轉換一下。
其中 20 是 fps ,如果想保存成灰度視頻,按照下述代碼修改即可。
out = cv2.VideoWriter("test1.avi", fourcc, fps, (width, height),False) # ...... # 注意在讀取每一幀的時候,都要轉換成灰度圖 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # ......
如果在編碼時出現如下錯誤,注意是 frameSize 參數設置的問題
VideoWriter() missing required argument 'frameSize' (pos 5)
對應的代碼位置按照如下修改即可
out = cv2.VideoWriter("test1.avi", fourcc, fps, (int(width), int(height)))
下一個常見的問題是,如果不是讀取視頻文件,直接采集的攝像頭數據,使用 fps = cap.get(5) 是無法獲取到具體的 fps 值的,此時只能進行手動設定。
該值的設定需要依據自己電腦的配置,一般設置為10~20即可。
OpenCV 視頻
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。