圖像入門
學(xué)習(xí)目標(biāo):
- 圖像的讀取凹嘲、顯示添怔、保存
- 學(xué)習(xí)三個函數(shù):cv2.imread(), cv2.imshow() , cv2.imwrite()
- 使用 Matplotlib 來顯示圖像
# 導(dǎo)入常用包
#%matplotlib notebook
import numpy as np
import cv2
import matplotlib.pyplot as plt
讀取顯示圖像
img = cv2.imread("img.jpg", 0) # 1: 顯示原始圖撒会, 0:灰度圖 -1:加載圖像包括 alpha 通道
cv2.imshow("image", img) # 第一個參數(shù)為顯示窗口的名稱朦肘,第二個參數(shù)是要顯示的圖像
k = cv2.waitKey(0) & 0xFF # cv2.waitKey() 鍵盤綁定函數(shù)链方,等待鍵盤按下,以毫秒為計數(shù)單位修陡,也可以設(shè)定特定按鍵點擊。64 bit 的機(jī)器要 cv2.waitKey(0) & 0xFF
if k == 27: # 等待按下 ESC 鍵退出可霎,
cv2.destroyAllWindows() # 銷毀所有窗口魄鸦,也可以用 cv2.destroyWindow() 銷毀特定的窗口。
elif k == ord('s'): # 指定某個按鍵按下后指定某種操作癣朗,如這里是保存
cv2.imwrite('image_write.png',img)
cv2.destroyAllWindows()
結(jié)果:cv2.namedWindow("image_new", cv2.WINDOW_NORMAL) # 創(chuàng)建一個新的窗口拾因,這個窗口大小可以進(jìn)行調(diào)節(jié)的
cv2.imshow("image_new", img)
cv2.waitKey(0)
cv2.destroyWindow("image_new")
寫圖像(保存圖像)
cv2.imwrite("image_write.png", img) # 保存圖像,可以指定保存圖像的格式
True
使用 matplotlib 顯示圖像
Matplotlib是一個用于Python的繪圖庫旷余,它提供了多種繪圖方法绢记。在這里,將學(xué)習(xí)如何使用 Matplotlib 顯示圖像正卧〈老ǎ可以使用 Matplotlib 放大圖片,保存圖片等炉旷。
img = cv2.imread("img.jpg", 0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') # interpolation 插值
plt.xticks([])
plt.yticks([]) # 隱藏 X签孔、Y 坐標(biāo)的刻度值
plt.show()
OpenCV 加載的彩色圖像為 BGR 模式。但是 Matplotlib 以 RGB 模式顯示窘行。因此饥追,如果使用 OpenCV 讀取圖像,Matplotlib 中的彩色圖像將不能正確顯示罐盔。
以下是解決辦法:對圖像的模式進(jìn)行轉(zhuǎn)換但绕,使之與 Matplotlib 或 OpenCV 匹配
img_cv = cv2.imread("img.jpg") # OpenCV 讀取圖像
b, g, r = cv2.split(img_cv) # OpenCV 中圖像顯示是 BGR 模式,提取
img_matplot = cv2.merge([r, g, b])
plt.subplot(121)
plt.imshow(img_cv) # 預(yù)計圖像會是異常的
plt.subplot(122)
plt.imshow(img_matplot) # 預(yù)計是真實的圖像
plt.show()
cv2.imshow('bgr image',img_cv) # 預(yù)計圖像會是異常的
cv2.imshow('rgb image',img_matplot) # 預(yù)計是真實的圖像
cv2.waitKey(0)
cv2.destroyAllWindows()
更多資料
視頻入門
學(xué)習(xí)目標(biāo):
- 顯示視頻惶看、保存視頻
- 從相機(jī)進(jìn)行捕獲
- cv2.VideoCapture(), cv2.VideoWriter() 函數(shù)使用
從相機(jī)捕獲視頻
筆記本自帶攝像頭
import cv2
# 創(chuàng)建一個 VideoCapture 對象捏顺,參數(shù)是設(shè)備的索引即攝像機(jī)的編號或者 Video 的文件名
# 這里的 0 是指第一臺攝像機(jī),以此類推
cap = cv2.VideoCapture(0)
while (True):
# while cap.isOpened():
# 一幀一幀的捕獲
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 顯示
cv2.imshow("frame", gray) # 窗口名為 frame
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release() # 關(guān)閉視頻文件或設(shè)備
cv2.destroyAllWindows()
cap.read()
返回一個bool (True/False)碳竟。如果幀被正確讀取草丧,它將為真。通過檢查這個返回值來檢查視頻的結(jié)尾莹桅。
有時昌执,cap 可能沒有初始化捕獲。在這種情況下诈泼,這段代碼顯示錯誤懂拾。可以通過方法 cap.isOpened()
檢查它是否初始化铐达。如果為真岖赋,則 ok。否則使用 cap.open()
打開它瓮孙。
可以通過 cap.get(propId)
獲取視頻的一些屬性唐断,propId 值為:0 to 18选脊。每個值代表視頻的一個屬性,詳見 Property Identifier 也可以通過 cap.set(propId, value)
設(shè)置視頻的屬性脸甘。
例如:可以通過 cap.get(3)
和 cap.get(4)
檢查幀的寬和高恳啥,默認(rèn)是 640x480。通過 ret = cap.set(3,320)
和 ret = cap.set(4,240)
將寬和高重新設(shè)定丹诀。
# 創(chuàng)建一個 VideoCapture 對象钝的,參數(shù)是設(shè)備的索引即攝像機(jī)的編號或者 Video 的文件名
# 這里的 0 是指第一臺攝像機(jī),以此類推
cap = cv2.VideoCapture(0)
while (True):
# while cap.isOpened():
# 一幀一幀的捕獲
ret, frame = cap.read()
ret = cap.set(3, 320)
ret = cap.set(4, 240)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow("frame", gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
從文件進(jìn)行播放
cap = cv2.VideoCapture('vtest.avi')
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
如果視頻播放結(jié)束铆遭,還沒按鍵按下硝桩,會出現(xiàn)錯誤。 改進(jìn)如下:
import cv2
cap = cv2.VideoCapture('vtest.avi')
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
if ret == False:
# cap.release() # 釋放掉開啟的視頻
# print("1") # 測試
cv2.waitKey(0) # 暫停在最后一幀
break # 關(guān)閉窗口后退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
改進(jìn)以后枚荣,程序會一直監(jiān)測視頻是否到最后一幀碗脊,若是最后一幀,則 ret 為 False 橄妆,暫停在最后一幀并且在關(guān)閉窗口后退出
保存視頻
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
# cv2.VideoWriter_fourcc('X','V','I','D') 功能一樣
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 創(chuàng)建 VideoWriter 對象望薄,指定輸出文件名 output.avi, FourCC 代碼呼畸,傳遞每秒幀數(shù)和幀大小
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
# 對每一幀進(jìn)行翻轉(zhuǎn)
frame = cv2.flip(frame, 0) # 注釋見下
# write the flipped frame
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
FourCC 是一個 4 字節(jié)的代碼,用于指定視頻編解碼器颁虐,依賴于平臺蛮原,到時看具體平臺進(jìn)行選擇。更多 FourCC 代碼見 官網(wǎng)
cv2.flip(src, flipCode[, dst]) → dst
: flipCode: 0表示繞 x 軸翻轉(zhuǎn)另绩,正值(例如儒陨,1)表示繞 y 軸翻轉(zhuǎn)。負(fù)值(例如 -1)表示在兩個軸上翻轉(zhuǎn)笋籽。
更多資料
OpenCV 繪圖功能
學(xué)習(xí)目標(biāo):
- 使用 OpenCV 繪制不同幾何形狀
- cv2.line(), cv2.circle() , cv2.rectangle(), cv2.ellipse(), cv2.putText()
以下圖像都用 matplotlib 繪制
函數(shù)共有參數(shù)說明
- img: 要操作的圖像
- color:繪制形狀的顏色蹦漠, RGB 傳入元組如(255, 255, 255), 灰度值只需傳入標(biāo)量
- thickness:線或圓等的厚度车海。如果對圓形等閉合圖形傳遞 -1 笛园,則填充形狀。默認(rèn)為 1
- lineType:線的類型
繪制各種形狀
# 需要給定直線的起始和結(jié)束坐標(biāo)
# 創(chuàng)建一個黑色的畫布
img = np.zeros((512, 512, 3), np.uint8)
# 繪制坐標(biāo) (0, 0) -> (510, 128) 直線 藍(lán)色侍芝,厚度為 5px
img = cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5) # OpenCV 為 BGR 模式
# 繪制長方形研铆,起始和終點坐標(biāo),顏色州叠,厚度
img = cv2.rectangle(img, (384, 10), (505, 120), (0, 255, 0), 3)
# 繪制圓形棵红,給定圓心,半徑咧栗,最后 -1 為圖形填充
img = cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
# 繪制橢圓逆甜,橢圓心虱肄,長軸,短軸交煞,角度咏窿,起始結(jié)束角,填充
img = cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)
# 繪制多邊形错敢,給定多邊形的頂點坐標(biāo)
pts = np.array([[50, 50], [40, 40], [60, 40], [60, 100]], np.int32)
pts = pts.reshape((-1, 1, 2))
# 若第三個參數(shù)為 False翰灾,則得到連接所有點的折線,而不是一個閉合的形狀稚茅。該函數(shù)可以用來繪制多條直線
img = cv2.polylines(img, [pts], True, (0, 255, 255))
# 添加文字到圖形中
font = cv2.FONT_HERSHEY_SIMPLEX # 指定字體
cv2.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255),
2, cv2.LINE_AA) # 繪制的圖像纸淮,文字,文字左下角的坐標(biāo),字體亚享,字體顏色咽块,厚度等
cv2.imshow("diff type", img)
k = cv2.waitKey(0) & 0xFF
if k == 27:
cv2.destroyAllWindows()
b, g, r = cv2.split(img)
img = cv2.merge([r, g, b])
plt.subplot(121)
plt.xticks([])
plt.yticks([])
plt.imshow(img)
<matplotlib.image.AxesImage at 0x1d119e3b668>
更多資料
鼠標(biāo)作為畫筆
學(xué)習(xí)目標(biāo):
- 處理鼠標(biāo)事件
- cv2.setMouseCallback()
簡單 Demo
首先,創(chuàng)建一個鼠標(biāo)回調(diào)函數(shù)欺税,該函數(shù)在鼠標(biāo)事件發(fā)生時執(zhí)行侈沪。鼠標(biāo)事件可以是任何與鼠標(biāo)相關(guān)的東西,如左鍵向下晚凿、左鍵向上亭罪、左鍵雙擊等。它為每個鼠標(biāo)事件提供坐標(biāo) (x,y)歼秽。有了這個事件和位置应役,我們可以做任何我們想做的事情。
# 列出鼠標(biāo)處理的事件
events = [i for i in dir(cv2) if 'EVENT' in i]
events
['EVENT_FLAG_ALTKEY',
'EVENT_FLAG_CTRLKEY',
'EVENT_FLAG_LBUTTON',
'EVENT_FLAG_MBUTTON',
'EVENT_FLAG_RBUTTON',
'EVENT_FLAG_SHIFTKEY',
'EVENT_LBUTTONDBLCLK',
'EVENT_LBUTTONDOWN',
'EVENT_LBUTTONUP',
'EVENT_MBUTTONDBLCLK',
'EVENT_MBUTTONDOWN',
'EVENT_MBUTTONUP',
'EVENT_MOUSEHWHEEL',
'EVENT_MOUSEMOVE',
'EVENT_MOUSEWHEEL',
'EVENT_RBUTTONDBLCLK',
'EVENT_RBUTTONDOWN',
'EVENT_RBUTTONUP']
import cv2
import numpy as np
# 功能函數(shù)燥筷,在鼠標(biāo)處左鍵雙擊箩祥,繪制白色填充的圓
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img, (x, y), 100, (255, 255, 255), -1)
# 創(chuàng)建一個黑色畫布
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow("image")
# 創(chuàng)建鼠標(biāo)回調(diào)函數(shù),綁定功能函數(shù)
cv2.setMouseCallback("image", draw_circle)
while(1):
cv2.imshow("image", img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
高級 Demo
現(xiàn)在我們要做更多更好的應(yīng)用肆氓。在這里袍祖,通過拖動鼠標(biāo)來繪制矩形或圓形(這取決于我們選擇的模式),就像在 Paint 應(yīng)用程序中所做的那樣谢揪。我們的鼠標(biāo)回調(diào)函數(shù)有兩部分蕉陋,一部分用來畫矩形,另一部分用來畫圓键耕。這個具體的例子將非常有助于創(chuàng)建和理解一些交互式應(yīng)用程序寺滚,如對象跟蹤,圖像分割等屈雄。
import cv2
import numpy as np
drawing = False # 鼠標(biāo)按下為 True
mode = True # 按鍵 'm' 切換模式
ix, iy = -1, -1
def draw(event, x, y, flags, param):
global ix, iy, drawing, mode
if event == cv2.EVENT_LBUTTONDOWN: # 鼠標(biāo)放下
drawing = True
ix, iy = x, y # 鼠標(biāo)放下時的坐標(biāo)
elif event == cv2.EVENT_MOUSEMOVE: # 鼠標(biāo)移動
if drawing == True:
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
elif event == cv2.EVENT_LBUTTONUP: # 鼠標(biāo)提起村视,結(jié)束繪制
drawing = False
# ------------- 中間這一段要不要?
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else:
cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
# -------------
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow("image")
cv2.setMouseCallback("image", draw) # 功能綁定
while(1):
cv2.imshow("image", img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'): # 按鍵 'm' 切換模式
mode = not mode
elif k == 27:
break
cv2.destroyAllWindows()
軌跡欄作為調(diào)色板
學(xué)習(xí)目標(biāo):
- 將軌跡欄綁定到 OpenCV 窗口
- cv2.getTrackbarPos(), cv2.createTrackbar()
Demo
創(chuàng)建簡單的應(yīng)用程序酒奶,通過滑動軌跡條調(diào)節(jié) BGR 的值從而改變畫布顏色蚁孔,初始顏色為黑色奶赔。
cv2.createTrackbar() 函數(shù),第一個參數(shù)是 trackbar 名稱杠氢,第二個參數(shù)是將用作創(chuàng)建的 trackbar 的父窗口的名稱站刑,第三個參數(shù)是默認(rèn)值,第四個參數(shù)是最大值鼻百,第五個參數(shù)是回調(diào)函數(shù)绞旅,每次 trackbar 值發(fā)生變化時都會執(zhí)行回調(diào)函數(shù)∥峦В回調(diào)函數(shù)總是有一個默認(rèn)參數(shù)因悲,即 trackbar 位置。在我們的例子中勺爱,函數(shù)什么也不做晃琳,所以我們只是傳遞。
trackbar 的另一個重要應(yīng)用是將其用作按鈕或開關(guān)琐鲁。默認(rèn)情況下卫旱,OpenCV 沒有按鈕功能。所以你可以使用 trackbar 來獲得這樣的功能围段。在我們的應(yīng)用程序中顾翼,我們已經(jīng)創(chuàng)建了一個開關(guān),在這個開關(guān)中應(yīng)用程序只在開關(guān)打開時才工作奈泪,否則屏幕總是黑色的暴构。
import cv2
import numpy as np
def nothing(x):
pass
img = np.zeros((300, 512, 3), np.uint8)
cv2.namedWindow("image")
cv2.createTrackbar('R', 'image', 0, 255, nothing)
cv2.createTrackbar('G', 'image', 0, 255, nothing)
cv2.createTrackbar('B', 'image', 0, 255, nothing)
switch = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch, 'image', 0, 1, nothing)
while(1):
cv2.imshow('image', img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
s = cv2.getTrackbarPos(switch, 'image')
if s == 0:
img[:] = 0
else:
img[:] = [b, g, r]
cv2.destroyAllWindows()
練習(xí)
創(chuàng)建一個畫筆顏色和筆刷半徑可調(diào)的滑動軌跡條
import cv2
import numpy as np
def nothing(x):
pass
radius_t = 1
bt, gt, rt = 255, 255, 255
def draw_circle(event, x, y, radius, b=255, g=255, r=255):
global radius_t, bt, gt, rt
radius = radius_t
b, g, r = bt, gt, rt
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.circle(img, (x, y), radius, (b, g, r), -1)
img = np.zeros((1366, 768, 3), np.uint8)
cv2.namedWindow("image")
# --------- 畫筆顏色
cv2.createTrackbar('brush_radius', 'image', 1, 10, nothing)
cv2.createTrackbar('pen_B', 'image', 0, 255, nothing)
cv2.createTrackbar('pen_G', 'image', 0, 255, nothing)
cv2.createTrackbar('pen_R', 'image', 0, 255, nothing)
# 創(chuàng)建鼠標(biāo)回調(diào)函數(shù),綁定功能函數(shù)
cv2.setMouseCallback("image", draw_circle)
while(1):
cv2.imshow('image', img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
brush_radius = cv2.getTrackbarPos('brush_radius', 'image')
pen_B = cv2.getTrackbarPos('pen_B', 'image')
pen_G = cv2.getTrackbarPos('pen_G', 'image')
pen_R = cv2.getTrackbarPos('pen_R', 'image')
# 對鼠標(biāo)函數(shù)參數(shù)進(jìn)行賦值
radius_t = brush_radius
bt, gt, rt = pen_B, pen_G, pen_R
cv2.destroyAllWindows()