Python-OpenCV — 讀取顯示及儲存影像、影片

李謦伊
謦伊的閱讀筆記
10 min readApr 26, 2021

在做深度學習的時候經常會使用到 OpenCV,因此來寫一下筆記做紀錄。OpenCV 是一個跨平台的電腦視覺套件,全名為 Open Source Computer Vision Library。本文將會使用 Python-OpenCV 來進行讀取、顯示、儲存影像和影片。

在使用 OpenCV 前要先安裝相關 library

$ pip install numpy $ pip install matplotlib

$ pip install opencv-python

接著 import OpenCV library

import cv2

讀取圖片

使用以下函數來讀取圖片,其中 flag 是用來控制讀取檔案的類型,目前有13種,可參考官方文件 → 🔍

img = cv2.imread(path, flag)

最常用的 flag 有以下三種:

  • cv2.IMREAD_UNCHANGED: 讀取圖片中的所有 channel,包括透明度
  • cv2.IMREAD_GRAYSCALE: 以灰階格式讀取
  • cv2.IMREAD_COLOR: 以 RGB 格式讀取,為預設值

我的輸入圖片是彩色的,因此維度是三維;若輸入是黑白圖片,維度為二維

# 彩色圖片
img.shape
(800, 582, 3)
# 黑白圖片
img.shape
(800, 582)

顯示圖片

使用以下函數來顯示圖片,其中 ”windows” 是顯示的視窗名稱。

cv2.imshow(“windows”, img)

在將圖片進行顯示時,通常會使用 cv2.waitKey() 來等待使用者按鍵,其中 delay 是等待按鍵觸發的時間,預設值為 0,表示程式會一直等待直到使用者按鍵為止。

cv2.waitKey(delay)

也可以利用回傳值取得按鍵的 ASCII 碼值。

key = cv2.waitKey(delay)# 使用 python 的函數 ord() 來取得字元的 ASCII 碼值
if key == ord(“a”) :
print(“press a”)

顯示完圖片後,要將視窗進行釋放。

# 釋放指定視窗
cv2.destroyWindow(“windows”)
# 釋放所有視窗
cv2.destroyAllWindows()

儲存影像

可透過副檔名儲存不同格式的影像,params 是儲存類型的參數,總共有 17 種,可參考官方文件 → 🔍

cv2.imwrite(“output.jpg”, img, params)# 若要儲存為jpg,可使用 cv2.IMWRITE_JPEG_QUALITY 控制儲存的影像畫質(0~100)
cv2.imwrite(“output.jpg”, img, [cv2.IMWRITE_JPEG_QUALITY, 98])

讀取、顯示、儲存圖片範例

img = cv2.imread(“001.jpg”)cv2.imshow(“windows”, img)key = cv2.waitKey()if key == ord(“q”):
print(“exit”)
cv2.imwrite(“output.jpg”, img)cv2.destroyWindow(“windows”)

但若在 Jupyter NoteBook 直接使用 cv2.imshow() 會導致程式 crash,有兩種解決辦法:

  • 加入 cv2.destroyWindow(“windows”) 或 cv2.destroyAllWindows()
  • 使用 plt.imshow() 代替

首先需要 import matplotlib.pyplot,Matplotlib 是 python 的繪圖庫,pyplot 則是 Matplotlib 中的模塊。

import matplotlib.pyplot as pltplt.imshow(img)plt.show()

由於 opencv 讀取的 channel 順序是 B → G → R,顯示的顏色會與原圖不一樣,因此使用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 轉換為 RGB。之後會再講 cv2.cvtColor() 的使用方式。

讀取影片/攝影機

接下來介紹如何讀取影片或攝影機。首先要進行初始化,其中 filename 為影片名稱或是攝影機 id。

cap = cv2.VideoCapture(filename)

一般情況下,使用 cv2.VideoCapture() 就可以完成初始化,但為了防止初始化發生錯誤,可以用以下函數檢查初始化是否成功。

若初始化成功 retval 會回傳 True,反之則回傳 False。

retval = cv2.VideoCapture.isOpened( )

如果初始化失敗,則可以使用 cv2.VideoCapture.open() 開啟,filename 一樣是影片名稱或攝影機 id。

retval = cv2.VideoCapture.open(filename)

接著要來擷取影片或攝影機的影像,其中 retval 表示影像是否擷取成功、frame 表示擷取的影像。

retval, frame = cv2.VideoCapture.read()

當不需要攝影機鏡頭時,要將其關閉,函數的語法如下

cv2.VideoCapture.release()

若要取得或修改類別物件的屬性可以使用以下函數,其中能使用的屬性值 propId 可由官方文件查看 → 🔍

# 取得類別物件屬性
cv2.VideoCapture.get(propId)
# 修改類別物件屬性
cv2.VideoCapture.set(propId, value)
# ======================================================
ex: 取得目前frame的寬高
cv2.VideoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)
cv2.VideoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)ex: 修改目前frame的寬高為(640, 480)
cv2.VideoCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cv2.VideoCapture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

讀取、顯示鏡頭範例

import cv2# current camera
cap = cv2.VideoCapture(0)
while (cap.isOpened()):
ret, frame = cap.read()
cv2.imshow(‘frame’, frame)
key = cv2.waitKey(1)
# ESC
if key == 27:
break
cap.release()
cv2.destroyAllWindows()

同步一組/多頭攝影機

當需要同步一組或多頭攝影機時,cv2.VideoCapture.read() 就不適用了,因此可以組合使用 cv2.VideoCapture.grab() 和 cv2.VideoCapture.retrieve()

# 用來擷取下一個frame,若成功會回傳 True
retval = cv2.VideoCapture.grab()
# 將擷取的frame進行解碼,,其中retval表示是否解碼成功、frame表示傳回的影像。
retval, image = cv2.VideoCapture.retrieve()
ex:cap0 = cv2.VideoCapture(0)cap1 = cv2.VideoCapture(1)g0 = cap0.grab()g1 = cap1.grab()if g0 and g1:
frame0 = cap0.retrieve()
frame1 = cap1.retrieve()

儲存影片

cv2.VideoWriter 函數可以將圖片、攝影機讀取的影像轉為影片檔案,也可以修改影片的屬性以及對影片類型的轉換。儲存影片的步驟包含建立物件、寫入影片、釋放物件。而在建立物件前,需要先設定好參數。

先來看一下建置函數所需要的參數有哪些:

  • filename 為輸出的影片名稱
  • fourcc 為影片編碼與解碼的格式,使用 cv2.VideoWriter_fourcc() 來指定
  • fps 為影片的播放速度
  • frameSize 為影片的長度與寬度
out = cv2.VideoWriter(filename, fourcc, fps, frameSize)

cv2.VideoWriter_fourcc() 中有四個字元參數,可以寫成 ('x', 'x', 'x', 'x') 或是 (*'xxxx')

# 表示未壓縮的 YUV 顏色編碼格示,副檔名為 .avi
fourcc = cv2.VideoWriter_fourcc('I', '4', '2', '0')
fourcc = cv2.VideoWriter_fourcc(*'I420')
# 表示 MPEG-1 編碼格示,副檔名為 .avi
fourcc = cv2.VideoWriter_fourcc('P', 'I', 'M', 'T')
fourcc = cv2.VideoWriter_fourcc(*'PIMT')
# 表示 MPEG-4 編碼格示,副檔名為 .avi
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 表示 MP4 編碼格示,副檔名為 .mp4
fourcc = cv2.VideoWriter_fourcc('M', 'P', '4', 'V')
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
# 表示 Ogg Vorbis 編碼格示,副檔名為 .ogv
fourcc = cv2.VideoWriter_fourcc('T', 'H', 'E', 'O')
fourcc = cv2.VideoWriter_fourcc(*'THEO')
# 表示 Flash 編碼格示,副檔名為 .flv
fourcc = cv2.VideoWriter_fourcc('F', 'L', 'V', 'I')
fourcc = cv2.VideoWriter_fourcc(*'FLVI')

將讀取的 frame 寫入影片

cv2.VideoWriter.write(frame)

不需要 cv2.VideoWriter 類別物件時,要將其釋放

cv2.VideoWriter.release()

讀取、顯示鏡頭並儲存範例

import cv2

# current camera
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20, (640, 480))
while (cap.isOpened()):
ret, frame = cap.read()
if ret == True:
out.write(frame)
cv2.imshow('frame', frame)

key = cv2.waitKey(1)
# ESC
if key == 27:
break

else:
break

cap.release()
out.release()
cv2.destroyAllWindows()

--

--