視頻
視頻是非常重要的視覺信息來源,它是視覺處理過程中經(jīng)常要處理的一類信號(hào)。實(shí)際上,視頻是由一系列圖像構(gòu)成,這一系列的圖像被稱為幀,幀是以固定時(shí)間間隔從視頻中獲取的。獲取幀的速度稱為幀速率,其單位通常使用“幀率/每秒”表示,代表在1秒內(nèi)所出現(xiàn)的幀數(shù),也就是游戲迷稱為的FPS。
如果我們從視頻中提取出獨(dú)立的幀,就可以使用圖像處理的方法對(duì)其進(jìn)行處理,達(dá)到處理視頻的目的。
VideoCapture類
在OpenCV中,它給我們提供了cv2.VideoCapture類來處理視頻。
通常我們使用 VideoCapture類有以下幾個(gè)步驟:
初始化
VideoCapture類提供了構(gòu)造函數(shù):cv2.VideoCapture(),用于打開攝像頭并完成攝像頭的初始化操作。其構(gòu)造函數(shù)定義如下:
cv2.VideoCapture(攝像頭ID號(hào))
攝像頭ID號(hào)默認(rèn)值為-1,表示隨機(jī)選取一個(gè)攝像頭。如果你運(yùn)行該程序的設(shè)備有多個(gè)攝像頭,則用0表示設(shè)備的第一個(gè)攝像頭,1表示設(shè)備的第二個(gè)攝像頭,依次類推。當(dāng)然,一般臺(tái)式機(jī)只有一個(gè)攝像頭,用0或者-1都可以。比如,下面代碼都行:
video=cv2.VideoCapture(0)
video=cv2.VideoCapture(-1)
檢查攝像頭是否初始化成功
為了程序的健壯性,我們一般在獲取攝像頭初始化之后,檢驗(yàn)攝像頭是否初始化成功。
檢查攝像頭是否初始化成功的函數(shù)為cv2.VideoCapture.isOpened(),其完整定義如下:
result=cv2.VideoCapture.isOpened()
如果成功,result返回True,如果失敗,result返回False。當(dāng)我們初始化攝像頭失敗后,我們還可以使用函數(shù)cv2.VideoCapture.open()打開攝像頭。具體代碼如下:
video=cv2.VideoCapture(0)
result=cv2.VideoCapture.isOpened()
if result is False:
result=cv2.VideoCapture.open(0)
其中,open參數(shù)也是攝像頭的ID號(hào),與前面構(gòu)造函數(shù)一樣。同時(shí),使用open()函數(shù)打開攝像頭后,也返回成功True或失敗False。
不過,cv2.VideoCapture.open()函數(shù)還可以直接打開視頻文件。比如:
result=cv2.VideoCapture.open(filename)
捕獲幀
攝像頭初始化完成之后,我們就可以從攝像頭中捕獲幀信息了。
在OpenCV中,它給我們提供的捕獲幀函數(shù)為cv2.VideoCapture.read()。其完整定義如下:
retval,image=cv2.VideoCapture.read()
其中,retval表示是否捕獲成功,返回布爾類型。image返回捕獲的幀信息(也就是圖像)。如果沒有捕獲幀信息,該值為空。
釋放
在我們捕獲幀,或者使用玩攝像頭資源之后,我們需要釋放該資源,也就是關(guān)閉攝像頭。
在OpenCV中,它提供函數(shù)cv2.VideoCapture.release()關(guān)閉攝像頭,其使用方式如下:
cv2.VideoCapture.release()
以上,就是OpenCV使用攝像頭捕獲信息的基本步驟。
屬性設(shè)置
有時(shí),我們需要獲取cv2.VideoCapture攝像頭的一些屬性,比如其分辨率,像素什么的。就需要通過OpenCV提供給我們的cv2.VideoCapture.get()函數(shù)。其完整定義如下:
cameraInfo=cv2.VideoCapture.get(propId)
這里參數(shù)propId對(duì)應(yīng)著就是cv2.VideoCapture類對(duì)象的屬性。比如,我們獲取攝像頭圖像的寬度,代碼如下:
cap=cv2.VideoCapture(0)
print(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
既然能獲取寬度,肯定也能獲取攝像頭圖像的高度,亮度等信息,包括飽和度,對(duì)比度都能夠獲取到。想了解更多的讀者,可以查詢開發(fā)文檔,這里就不在贅述。
grab()與retrieve()
一般情況下,我們都只使用一個(gè)攝像頭,上面這些步驟與函數(shù)完全能夠應(yīng)付。但是,如果需要同步一組或一個(gè)多頭攝像頭,上面的函數(shù)就無法勝任了。
這個(gè)時(shí)候,我們就需要使用cv2.VideoCapture.grab()與cv2.VideoCapture.retrieve()函數(shù)。你可以把函數(shù)cv2.VideoCapture.read()理解為這兩個(gè)函數(shù)的組合。
函數(shù)cv2.VideoCapture.grab()用于指向下一幀,函數(shù)cv2.VideoCapture.retrieve()用來解碼并返回一幀。所以,對(duì)于一組攝像頭我們可以這樣操作:
cap0=cv2.VideoCapture(0)
cap1=cv2.VideoCapture(0)
isCamera0=cap0.grab()
isCamera1=cap1.grab()
if isCamera0 and isCamera1:
frame0=cap0.retrieve()
frame1=cap1.retrieve()
當(dāng)然,這兩個(gè)函數(shù)也可以讀取視頻文件。
捕獲攝像頭視頻
既然,我們已經(jīng)了解了VideoCapture類。下面,我們來捕獲電腦攝像頭的視頻。其完整代碼如下:
import cv2
cap=cv2.VideoCapture(0)
while(cap.isOpened()):
ret,frame=cap.read()
cv2.imshow('video',frame)
c=cv2.waitKey(1)
if c==27:
break
cap.release()
cv2.destroyAllWindows()
代碼很簡單,首先獲取電腦的攝像頭,然后無線循環(huán)判斷是否打開。在循環(huán)體中,我們讀取每幀,并顯示到界面上,當(dāng)按下ESC鍵時(shí),退出。
運(yùn)行之后,效果如下:

捕獲文件視頻
之前,我們都講解過,如果需要播放視頻文件的話,只需要將攝像頭換成文件名即可。
下面,我們來實(shí)現(xiàn)播放視頻文件,代碼如下:
import cv2
cap=cv2.VideoCapture("38.mp4")
print(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
while(cap.isOpened()):
ret,frame=cap.read()
cv2.imshow('video',frame)
c=cv2.waitKey(1)
if c==27:
break
cap.release()
cv2.destroyAllWindows()
這里,就不運(yùn)行了,感興趣的可以將“38.MP4”視頻替換成自己的。
實(shí)現(xiàn)灰度攝像頭
通過上面兩個(gè)示例,我們知道了如何使用攝像頭。但是,一般我們使用手機(jī)時(shí),都有各種特效,比如美顏,黑白等效果。那么我們?nèi)绾螌?shí)現(xiàn)這些效果呢?
下面,我們以灰度圖像為例,將攝像頭錄像視頻采集為灰度圖像。具體代碼如下:
import cv2
cap=cv2.VideoCapture(0)
print(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
while(cap.isOpened()):
ret,frame=cap.read()
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.imshow('video',frame)
c=cv2.waitKey(1)
if c==27:
break
cap.release()
cv2.destroyAllWindows()
運(yùn)行之后,我們攝像頭顯示的視頻是灰色的。從這里我們也可以看出來,處理視頻信號(hào)時(shí),我們只需要獲取其每一幀的圖像Frame,然后對(duì)frame進(jìn)行處理即可。
2.png
