標籤:也會 情況下 idt 特殊 純粹 show 編碼 rac 方法
基本I/O指令碼讀/寫影像檔
OpenCV的imread函數和imwrite函數能支援各種靜態影像檔格式。不同系統支援的檔案格式不一樣,但都支援BMP格式,通常還應該支援PNG、JPEG和TIFF格式。
大多數常用的opencv函數都在cv2模組中。可能也會遇到其他基於cv或cv2.cv模組的opencv協助,這些都是傳統版本。Python模組被稱為cv2並不表示該模組是針對OpenCv2.x.x版本的
imread()函數的參數:
1.IMREAD_ANYCOLOR=4
2.IMREAD_ANYDEPTH=2
3.IMREAD_COLOR=1
4.IMREAD_GRAYSCALE=0
5IMREAD_LOAD_GDAL=8
6.IMREAD_UNCHANGED=-1
cv.imshow(‘視窗名’,img)#必須要加上視窗名
且必須加
cv2.waitKey(0)
cv2.destroyAllWindows()否則會一閃跳過
映像與原始位元組之間的轉換
一個opencv映像是.array類型的二維或三維數組。
8位的灰階映像是一個含有位元組值得二維數組。一個24維得RGB映像是一個三維數組,它也包含了位元組值。可使用運算式訪問這些值,例如image[0,0]或image[0,0,0]。第一個值代表像素y座標或行,0表示頂部;第二個值是像素得x座標或列,0表示最左;第三個值(如果可用得話)表示色彩通道。
若一副映像得每個通道為8位,則可將其顯示轉換為標準得一維Python bytearray格式:
byteArray=bytearray(image)
反之,bytearray含有恰當順序的位元組,可以通過顯式轉換和重構,得到numpy.array形式得映像:
grayImage=numpy.array(grayByteArray).reshape(height,width)
bgrImage=numpy.array(bgrByteArray).reshape(height,width,3)
視頻檔案得讀/寫
opencv提供VideoCapture類和videoWriter類來支援各種格式得視頻檔案。支援的格式類型會因系統的不同而變化,但應該都支援AVI格式。在到達視頻檔案末尾之前,VideoCapture類可通過read()函數來擷取新的幀,每幀是一副基於BGR格式的映像
可將一幅映像傳遞給VideoWriter類的write()函數,該函數會將這幅映像加到VideoWriter類所指向的檔案中。
特別注意:必須要為VideoWriter類的建構函式指定視頻檔案名稱,這個檔案名稱對應的檔案若存在,會被覆蓋。也必須指定視頻轉碼器。轉碼器的可用性根據系統不同而不同。下面是常用選項:
cv2.VideoWriter_fourcc(‘I’,’4’,’2’,’0’):該選項是一個未壓縮的 YUV顏色編碼,是4:2:0色度子採樣。這種編碼有很好的相容性,但會產生較大檔案,副檔名為.avi
cv2.VideoWriter_fourcc(‘P’,’I’,’M’,’1’):該選項是MPEG-1編碼類別型,副檔名為.avi
cv2.VideoWriter_fourcc(‘X’,’V’,’I’,’D’):該選項是MPEG-4編碼類別型,如果希望得到的視頻大小為 平均值,推薦使用此選項,副檔名為.avi
cv2.VideoWriter_fourcc(‘F’,’L’,’V’,’1’):該選項是一個Flash視頻,副檔名為.flv。
捕獲網路攝影機的幀
VideoCapture類可以獲得網路攝影機的幀流。但對網路攝影機而言,通常不是用視頻的檔案名稱來構造VideoCapture類,而是需要傳遞網路攝影機的裝置索引(device index)
然而與前面不一樣,VideoCapture類的get()方法不能返回網路攝影機畫面播放速率(fps)的準確值,它總是返回0
import cv2import numpy as npcameraCapture=cv2.VideoCapture(0)#調用網路攝影機fps=30size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))videoWriter=cv2.VideoWriter(‘4.avi‘,cv2.VideoWriter_fourcc(‘X‘,‘V‘,‘I‘,‘D‘),fps,size)success,frame=cameraCapture.read()numFramesRemaining=10*fps-1#倒計時while success and numFramesRemaining>0: videoWriter.write(frame) success,frame=cameraCapture.read() numFramesRemaining-=1cameraCapture.release()
網路攝影機的數量和順序由系統決定。但opencv沒有提供任何查詢網路攝影機數量和屬性的方法。如果使用無效索引構造了VideoCapture類,就不會得到幀,VideoCapture的read()函數會返回(false,None)。為了不讓read()函數從沒有正確開啟的VideoCapture類中擷取資料,可在執行該函數之後使用VideoCapture.isOpened方法做一個判斷,該方法返回一個boolean值。
當需要同布一組網路攝影機或一個多頭網路攝影機時,read()方法就不再適合,可用grab()和retrive()方法代替它。對於一組網路攝影機,可以使用以下代碼
success0=cameraCapture0.grab()success1=cameraCapture1.grab()if success0 and success1: frame0=cameraCapture0.retrieve() frame1=cameraCapture1.retrieve()
在視窗顯示映像
cv.imshow(‘視窗名’,img)#必須要加上視窗名
且必須加
cv2.waitKey(0)
cv2.destroyAllWindows()否則會一閃跳過
在視窗顯示網路攝影機幀
OpenCV的namedWindow()、imshow()和DestroyWindow()函數允許指定視窗來建立,顯示和銷毀(destroy)視窗。此外,任意視窗下都可以通過waitKey()函數來擷取鍵盤輸入,通過setMouseCallback()函數來擷取滑鼠輸入。
import cv2clicked=Falsedef onMouse(event,x,y,flags,param): global clicked if event==cv2.EVENT_LBUTTONUP: clicked=TrueCameraCapture=cv2.VideoCapture(0)cv2.namedWindow(‘MyWindow‘)cv2.setMouseCallback(‘MyWindow‘,onMouse)print(‘Showing camera feed. Click window or press any key to stop‘)success,frame=CameraCapture.read()while success and cv2.waitKey(1)==-1 and not clicked:#要麼鍵盤輸入要麼滑鼠輸入,要麼網路攝影機擷取幀不成功,否則會繼續 cv2.imshow(‘Mywindow‘,frame) success,frame=CameraCapture.read()cv2.destroyWindow(‘MyWindow‘)CameraCapture.release()
OpenCV的視窗函數和waitKey()函數相互依賴。OpenCV的視窗只有在調用waitKey()函數時才會更新,waitKey()函數只有在OpenCV視窗成為使用中視窗時,才能捕獲輸入資訊。
滑鼠回呼函數setMouseCallback()有5個參數,如前面的範例程式碼所示。param為選擇性參數,它是setMouseCallback()函數的第三個參數,預設情況下,該參數為0.回調事件參數可以取如下的值,他們分別對應不同的滑鼠事件。
cv2.EVENT_MOUSEMOVE:該事件對應滑鼠移動
cv2.EVENT_LBUTTONDOWN:該事件對應滑鼠左鍵按下
cv2.EVENT_RBUTTONDOWN:該事件對應滑鼠右鍵按下
cv2.EVENT_MBUTTONDOWN:該事件對應滑鼠中間鍵按下
cv2.EVENT_LBUTTONUP:該事件對應滑鼠左鍵鬆開
cv2.EVENT_RBUTTONUP:該事件對應滑鼠右鍵鬆開
cv2.EVENT_MBUTTONUP:該事件對應滑鼠中間鍵鬆開
cv2.EVENT_LBUTTONDBLCLK:該事件對應雙擊滑鼠左鍵
cv2.EVENT_RBUTTONDBLCLK:該事件對應雙擊滑鼠右鍵
cv2.EVENT_MBUTTONDBLCLK:該事件對應雙擊滑鼠中鍵
滑鼠回調的標誌參數可能以下事件的按位組合:
cv2.EVENT_FLAG_LBUTTON:該事件對應按下滑鼠左鍵
cv2.EVENT_FLAG_RBUTTON:該事件對應按下滑鼠右鍵
cv2.EVENT_FLAG_MBUTTON:該事件對應按下滑鼠中鍵
cv2.EVENT_FLAG_CTRLKEY:該事件對應按下Ctrl鍵
cv2.EVENT_FLAG_SHIFTKEY:該事件對應按下Shift鍵
cv2.EVENT_FLAG_ALTKEY:該事件對應按下Alt鍵
然而OpenCV不提供任何處理視窗事件的方法。例如當單擊視窗的關閉按鈕時不能關閉應用程式。由於Opencv有限的事件處理能力和GUI處理能力。
Cameo——物件導向的設計
Python的應用程式可用純粹的面向過程語言來實現,像前面討論的小應用程式(如基本I/O的指令碼)通常會這樣做。不過為了提高模組化水平和擴充性,下面將採用物件導向的方式實現。
通過前面介紹的OpenCV I/O功能可以知道,所有映像其實都是相似的,儘管映像的來源或去向不同。無論是從哪裡獲得的映像流,或者要將其輸出到哪裡,都可以將相同邏輯應用程式到映像流中的每個幀中。在應用中,將I/O代碼與應用程式代碼分離會變得特別方便,例如Cameo會使用多個I/O流
可建立CaptureManager類和WindowManager類作為進階的I/O流介面。在應用程式的代碼中可以使用CaptureManager來讀取新的幀,並能將幀指派到一個或多個輸出中,這些輸出包括靜止的影像檔、視頻檔案以及視窗(可以通過WindowManager類來實現)。WindowManager類使應用程式代碼能以物件導向的形式處理視窗和事件。
CaptureManager和WindowManager都具有可擴充性,因此,實現時可以不依賴OpenCV的I/O.
使用managers.CaptureManager提取視頻流
無論該映像流來自視頻檔案還是網路攝影機,openCV都可以擷取、顯示和記錄映像流,但是每種情況都有一些需要特殊考慮的地方。CaptureManager類對一些差異進行了抽象,並提供了更進階的介面從擷取流中分配映像,再將映像分到一個或多個輸出中(像檔案、視頻檔案或視窗)。
在VideoCapture類中初始化CaptureManager類,在應用程式主迴圈的每一次迭代通常應調用CaptureManager類的enterFrame()和exitFrame()函數。在調用enterFrame()和exitFrame()函數之間,應用程式可能會設定通道屬性並擷取幀屬性。通道屬性的初始值是0,只有在多頭網路攝影機的情況下,通道屬性的初始值非0.幀屬性是當調用enterFrame()函數時與當前通道狀態對應的映像。
可能會經常調用CaptureManager類的writeImage()、startWritingVideo()和stopWritingVideo()函數。在調用existFrame()函數之前,會延遲寫入檔案。並且,在調用existFrame()函數的過程中,幀屬性可能會在視窗中顯示,這取決於應用程式代碼是將WindowManager類作為CaptureManager的建構函式參數,還是設定previewWindowManager屬性。
如果應用程式代碼處理了幀屬性,那麼在記錄檔案和視窗中會有所體現。CaptureManager類中有一個稱為shouldMirrorPreview的建構函式參數和屬性,如果想要幀在視窗中鏡像(水平翻轉),但不記錄在檔案中,可將shouldMirrorPreview設定為True.通常,當面對網路攝影機的時候,使用者喜歡網路攝影機返回鏡像映像。
前面介紹過VideoWriter類需要畫面播放速率,但OpenCV不能為網路攝影機提供準確的畫面播放速率,解決這個問題的方法是通過幀計數器和Python標準的time.time()函數估計畫面播放速率,但這些方法都有問題。由於畫面播放速率不穩定以及time.time()函數需要依賴系統實現,有些時候,估計精度可能會很差。但是,如果在未知的硬體平台上運行應用程式,這樣估計得畫面播放速率會比隨意假定一個網路攝影機的畫面播放速率效果要好。
cameo.Cameo的強大實現
Cameo類提供兩種方法啟動應用程式:run()和onkeypress()。在初始化時,Cameo類會把onKeypress()作為回呼函數建立WindowManager類,而CaptureManager類會使用網路攝影機和WindowManager類。當調用run()函數時,應用程式會執行主迴圈處理幀和事件,應用程式會調用onkeypress()函數處理事件。按空格鍵可擷取資訊,按tab鍵可啟動/停止截屏(一個視頻記錄),按Esc鍵可以推出應用程式。
opencv3電腦視覺+Python(一)