opencv筆記(一)
阿新 • • 發佈:2022-12-05
opencv筆記(一)
目錄環境搭建
- python3環境
- pip install numpy matplotlib opencv-python
基礎用法
常用物件
- 視窗
- 攝像裝置
- 視訊寫入
import cv2 # 建立fourcc物件 fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 建立VideoWriter物件,引數為1.檔案路徑、fourcc、幀率、解析度 vw = cv2.VideoWriter('d.mp4', fourcc, 24, (640, 480)) # 建立視窗物件 cv2.namedWindow('video', cv2.WINDOW_NORMAL) # 建立攝像裝置物件,引數為裝置序列號 cap = cv2.VideoCapture(0) while cap.isOpened(): ok, frame = cap.read() if ok: # 螢幕顯示 cv2.imshow('video', frame) # 儲存 vw.write(frame) key = cv2.waitKey(6) if key & 0xFF == ord('q'): break else: break # 釋放資源 cap.release() vw.release() cv2.destroyAllWindows()
- 滑鼠回撥函式
import cv2 import numpy as np # 定義回撥函式體,引數:1.事件、2.寬、3.高、4.滑鼠鍵或者組合鍵、5.設定滑鼠回撥函式時傳入的userdata def mouse_callback(event, x, y, flag, userdata): print(event, x, y, flag, userdata) # 建立視窗物件 cv2.namedWindow('video', cv2.WINDOW_NORMAL) cv2.resizeWindow('video', 1280, 720) # 設定滑鼠回撥函式,引數:1.視窗名、2.回撥函式、3.userdata值 cv2.setMouseCallback('video', mouse_callback, 'userdata') img = np.zeros((720, 1280, 3), np.uint8) while 1: # 螢幕顯示 cv2.imshow('video', img) key = cv2.waitKey(6) if key & 0xFF == ord('q'): break cv2.destroyAllWindows()
- TrackBar
import cv2
import numpy as np
def callback(userdata):
print(userdata)
cv2.namedWindow('trackbar', cv2.WINDOW_NORMAL)
cv2.resizeWindow('trackbar', 640, 320)
# 建立trackbar
cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
cv2.createTrackbar('G', 'trackbar', 0, 255, callback)
cv2.createTrackbar('B', 'trackbar', 0, 255, callback)
img = np.zeros((320, 640, 3), np.uint8)
while 1:
# 螢幕顯示
r = cv2.getTrackbarPos('R', 'trackbar')
g = cv2.getTrackbarPos('G', 'trackbar')
b = cv2.getTrackbarPos('B', 'trackbar')
img[:] = [b, g, r]
cv2.imshow('trackbar', img)
key = cv2.waitKey(6)
if key & 0xFF == ord('q') or cv2.getWindowProperty('trackbar', cv2.WND_PROP_VISIBLE) < 1.0:
break
cv2.destroyAllWindows()
色彩空間
- BGR
- RGB
- HSV:色相+飽和度+明度
- HSL:色相+飽和度+亮度
- YUV
import cv2
def callback(userdata):
print(userdata)
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
img = cv2.imread('1.png')
color_spaces = [cv2.COLOR_BGR2BGRA, cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV_FULL, cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2YUV]
cv2.createTrackbar('trans', 'color', 0, len(color_spaces)-1, callback)
while 1:
v = cv2.getTrackbarPos('trans', 'color')
# 色彩空間轉換
new_img = cv2.cvtColor(img, color_spaces[v])
cv2.imshow('color', new_img)
key = cv2.waitKey(6)
if key & 0xFF == ord('q') or cv2.getWindowProperty('color', cv2.WND_PROP_VISIBLE) < 1.0:
break
cv2.destroyAllWindows()
Numpy基礎
建立矩陣
- 通過array:np.array[[1, 2, 3], [4, 5, 6]]
- 通過zeros:np.zeros((320, 640, 3), np.uint8)
- 通過ones:np.ones((320, 640, 3), np.uint8)
- 通過full:np.full((8, 8, 3), 255, np.uint8)
- 通過identity:np.identity(4)
- 通過eye:np.eye(3, 5, k=2)
矩陣取值與賦值
- img[y, x]:[1, 2, 3]
- img[y, x, channel]:1
ROI
- img[y1:y2, x1:x2]
- img[:, :]
import cv2
import numpy as np
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
img = np.full((320, 640, 3), 0, np.uint8)
img[100:200, 100:200] = [0, 0, 255]
img[:, 300] = [255, 0, 0]
cv2.imshow('color', img)
key = cv2.waitKey(0)
if key & 0xFF == ord('q') or cv2.getWindowProperty('color', cv2.WND_PROP_VISIBLE) < 1.0:
cv2.destroyAllWindows()
Mat
結構
- header:dims維度、rows行數、cols列數、depth畫素位深、channels通道數、size矩陣大小、type
- data:矩陣詳細資料
拷貝
當顯式呼叫copy()生成新矩陣時會拷貝header和data,否則只拷貝header。
import cv2
import numpy as np
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
img = np.full((320, 640, 3), 0, np.uint8)
img2 = img[:]
img2[:] = [0, 0, 255]
img3 = img.copy()
img3[100:200, 100:200] = [255, 0, 0]
cv2.imshow('color', img)
cv2.imshow('color2', img2)
cv2.imshow('color3', img3)
key = cv2.waitKey(0)
if key & 0xFF == ord('q') or cv2.getWindowProperty('color', cv2.WND_PROP_VISIBLE) < 1.0:
cv2.destroyAllWindows()
屬性訪問
- img.shape:高、寬、通道數
- img.size:高x寬x通道數
- img.dtype:位深,例如uint8
通道的分離與合併
- split(mat)
- merge((chan1, chan2))
import cv2
import numpy as np
img = np.zeros((320, 640, 3), np.uint8)
b, g, r = cv2.split(img) # split將同時拷貝header與data
b[100:200, 100:200] = 255
g[100:200, 100:200] = 255
r[0:100, 0:100] = 255
img2 = cv2.merge((b, g, r)) # merge將同時拷貝header與data
img2[200:300, 200:300] = [0, 0, 255]
cv2.imshow('color', img)
cv2.imshow('color0', img2)
cv2.imshow('color1', b)
cv2.imshow('color2', g)
cv2.imshow('color3', r)
key = cv2.waitKey(0)
if key & 0xFF == ord('q'):
cv2.destroyAllWindows()
圖形繪製
- 線:line
- 矩形:rectangle
- 圓:circle
- 橢圓:ellipse
- 多邊形:
- 字型:
import cv2
import numpy as np
# 此處座標引數為y, x順序
img = np.zeros((320, 640, 3), np.uint8)
# 此處座標相關引數全部是(x, y)順序,引數:影象、起始點、終止點、顏色、線寬、線形
cv2.line(img, (10, 20), (100, 200), (255, 0, 0), 5)
#矩形
cv2.rectangle(img, (80, 80), (200, 200), (0, 255, 0))
# 圓
cv2.circle(img, (140, 140), 60, (0, 0, 255))
# 橢圓 引數:影象、圓心、x和y半徑、順時針旋轉角度、繪製起始角度、繪製終止角度、顏色、厚
cv2.ellipse(img, (140, 140), (60, 30), 90, 0, 360, (0, 0, 255), -1)
# 多邊形 引數:影象、點、是否閉合、顏色
points = np.array([(300, 5), (132, 109), (480, 109)], np.int32)
cv2.polylines(img, [points], True, (0, 0, 255))
# 填充的多邊形 引數:影象、點、顏色
points_fill = np.array([(300, 10), (150, 100), (450, 100)], np.int32)
cv2.fillPoly(img, [points_fill], (255, 0, 0))
# 文字 引數:影象、文字內容、起始點、字型、字號、顏色
cv2.putText(img, 'test', (200, 300), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 255))
cv2.imshow('line', img)
key = cv2.waitKey(0)
if key & 0xFF == ord('q'):
cv2.destroyAllWindows()
基本影象運算與處理
加法運算
import cv2
import numpy as np
# 加法運算
# 必須確保兩張影象大小通道一致
im1 = cv2.imread('x.png')
# im2 = cv2.imread('y.png')
im2 = np.ones((1080, 1920, 3), np.uint8) * 100
cv2.imshow('add', cv2.add(im1, im2))
cv2.waitKey(0)
減法運算
import cv2
import numpy as np
# 減法運算
# 必須確保兩張影象大小通道一致
# 注意受np.uint8型別約束,加法運算逆運算後可能得到與原圖有偏差的結果
im1 = cv2.imread('x.png')
im2 = np.ones(im1.shape, np.uint8) * 10
cv2.imshow('ori', im1)
cv2.imshow('subtract', cv2.subtract(cv2.add(im1, im2), im2))
cv2.waitKey(0)
乘除運算
import cv2
import numpy as np
# 減法運算
# 必須確保兩張影象大小通道一致
# 注意受np.uint8型別約束,加法運算逆運算後可能得到與原圖有偏差的結果
im1 = cv2.imread('x.png')
im2 = np.ones(im1.shape, np.uint8) * 10
cv2.imshow('ori', im1)
cv2.imshow('multiply', cv2.multiply(im1, im2))
cv2.imshow('divide', cv2.divide(im1, im2))
cv2.waitKey(0)
影象溶合
即帶權重的影象疊加
import cv2
im1 = cv2.imread('x.png')
im2 = cv2.imread('y.png')
# 引數:影象一、影象一權重、影象二、影象二權重、靜態權重
cv2.imshow('addWeighted', cv2.addWeighted(im1, 0.6, im2, 0.4, 0))
cv2.waitKey(0)
影象位運算
-
與
-
或
-
非
-
異或
import cv2
import numpy as np
im1 = np.zeros((200, 200), np.uint8)
im2 = np.zeros((200, 200), np.uint8)
im1[20:120, 20:120] = 255
im2[80:180, 80:180] = 255
cv2.imshow('not', cv2.bitwise_not(im1))
cv2.imshow('and', cv2.bitwise_and(im1, im2))
cv2.imshow('or', cv2.bitwise_or(im1, im2))
cv2.imshow('xor', cv2.bitwise_xor(im1, im2))
cv2.waitKey(0)
影象的變換
影象縮放
import cv2
# 影象縮放
"""
引數:源、縮放後大小、X軸縮放因子、Y軸縮放因子、插值演算法,同時指定大小和縮放因子優先取大小
插值演算法:INTER_NEAREST(臨近插值,速度快,效果差)、INTER_LINEAR(雙線性插值,參考周圍4點)
INTER_CUBIC(三次插值,參考16點)、INTER_AREA(效果最好)
"""
img = cv2.imread('1.png')
res = cv2.resize(img, (1920, 1080))
res2 = cv2.resize(img, None, fx=0.6, fy=0.6)
cv2.imshow('resize1', res)
cv2.imshow('resize2', res2)
cv2.waitKeyEx(0)
影象翻轉
import cv2
# 影象翻轉
# 引數:影象、翻轉標誌(0代表上下翻轉, >0代表左右翻轉, <0代表上下+左右)
img = cv2.imread('1.png')
cv2.imshow('flip', cv2.flip(img, -1))
cv2.waitKeyEx(0)
影象旋轉
import cv2
# 影象旋轉
# 引數:影象、旋轉標誌(ROTATE_90_CLOCKWISE, ROTATE180, ROTATE_90_COUNTERCLOCKWISE)
img = cv2.imread('1.png')
cv2.imshow('rotate', cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE))
cv2.waitKeyEx(0)
仿射變換
即影象旋轉、縮放、平移的總稱
import cv2
import numpy as np
img = cv2.imread('1.png')
# 仿射變換
# 引數:影象、變換矩陣、輸出大小、flag插值演算法、mode邊界外推法標誌、value填充邊界的值
# X軸平移100
M = np.float32([[1, 0, 100], [0, 1, 0]])
h, w, _ = img.shape
cv2.imshow('warpAffine', cv2.warpAffine(img, M, (w, h)))
# 通過API獲取變換矩陣
# 引數:中心點、角度(逆時針)、縮放比例
# 變換不改變影象大小,如果要修改影象大小需要修改dsize
M = cv2.getRotationMatrix2D((100, 100), 30, 1.0)
cv2.imshow('warpAffine2', cv2.warpAffine(img, M, (w, h)))
# 通過API獲取變換矩陣-三點定位
# 引數:原三點、目的三點
ori = np.float32([[100, 200], [300, 200], [100, 400]])
new = np.float32([[150, 300], [200, 400], [50, 350]])
M = cv2.getAffineTransform(ori, new)
cv2.imshow('warpAffine3', cv2.warpAffine(img, M, (w, h)))
cv2.waitKeyEx(0)
透視變換
import cv2
import numpy as np
img = cv2.imread('3.jpg')
# 獲取變換矩陣
# 引數:原四點、目標四點
src = np.float32([[100, 1100], [2100, 1100], [0, 4000], [2500, 3900]])
des = np.float32([[0, 0], [2300, 0], [0, 3000], [2300, 3000]])
M = cv2.getPerspectiveTransform(src, des)
# 透視變換
# 引數:影象、變換矩陣、輸出大小...
warp_perspective = cv2.warpPerspective(img, M, (2300, 3000))
cv2.imshow('warpPerspective', warp_perspective)
cv2.waitKeyEx(0)
影象濾波
一幅影象通過濾波器得到另一幅影象。
卷積
濾波器又稱卷積核,濾波的過程稱為卷積。
-
卷積核的大小:
一般為奇數(原因包括增加padding和確保錨點居中),例如3x3、5x5等,在深度學習中,卷積核越大,感受野越大,資訊越多,提取的特徵越好,同時計算量也越大
-
錨點:卷積核中心點
-
邊界擴充:
當卷積核大於1且不進行邊界擴充,輸出尺寸將相應縮小
當卷積核一標準方式進行邊界擴充,則輸出資料的空間尺寸將與輸入相等
N = (W - F + 2P) / S + 1
N即輸出影象大小,W源大小,F卷積核大小,P擴充尺寸,S步長大小
-
步長
低通濾波:低於某個閾值的值可以通過,可以去除噪音或者平滑影象
高通濾波:高於某個閾值的值可以通過,可以幫助查詢影象邊緣
常用濾波器
低通濾波
濾波器名 | 作用或優點 | 缺點 | 備註 |
---|---|---|---|
*方盒濾波(boxFilter) | / | / | normalize=True時為均值濾波,使用較少 |
均值濾波(blur) | 平滑影象,減少銳化 | 失去紋理 | / |
高斯濾波(GaussianBlur) | 塗抹噪點 | 邊緣模糊 | 越靠近中心,權重越高,錨點權重約0.148 |
中值濾波(medianBlur) | 消除胡椒噪音 | 對其他噪音效果不佳,邊緣模糊 | 取卷積陣列的中值作為卷積結果 |
雙邊濾波(bilateralFilter) | 保留邊緣同時對邊緣內區域進行平滑處理 | 胡椒噪音效果不佳 |
高通濾波
運算元 | 作用或優點 | 缺點 | 備註 |
---|---|---|---|
索貝爾(Sobel) | 抗噪 | 同時求一個以上方向邊緣時效果極差 | 卷積核大小為-1時即沙爾 |
*沙爾(Scharr) | 細小邊緣檢測 | 只能同時求一個方向上的邊緣 | 使用較少 |
拉普拉斯(Laplacian) | 同時求多方向邊緣 | 噪音敏感 | 使用前需要先做降噪處理 |
邊緣檢測-Canny
內部實現步驟
- 使用5x5高斯濾波消除噪聲
- 從四個方向計算影象梯度:0°/45°/90°/135°
- 取區域性極大值
- 閾值計算:高於最大值即是邊緣,低於最小值即不是邊緣,中間值如與以確定邊緣有連續關係則是邊緣,否則不是邊緣
import cv2
import numpy as np
img = cv2.imread('8.png')
# 影象卷積
# 引數:影象、位深,卷積核,錨點,指定偏差,邊界型別
# kernel = np.ones((5, 5), np.float32) / 25
# des = cv2.filter2D(img, -1, kernel)
# 均值濾波,引數:源、卷積核大小...
# blur_des = cv2.blur(img, (5, 5))
# 高斯濾波,引數:源、卷積核(大小)、sigma(值越大越模糊,未指定時參考卷積核大小)
# gauss_des = cv2.GaussianBlur(img, (5, 5), sigmaX=3)
# 中值濾波,引數:源、卷積核大小
# median_des = cv2.medianBlur(img, 5)
# 雙邊濾波,引數:源、filter大小、顏色sigma、sigma空間
# bil_des = cv2.bilateralFilter(img, 6, 20, 50)
# 索貝爾運算元,引數:源、輸出位深、對X求導、對Y求導、核大小...
# sobel_des = cv2.add(cv2.Sobel(img, cv2.CV_64F, 1, 0, 5), cv2.Sobel(img, cv2.CV_64F, 0, 1, 5))
# 拉普拉斯運算元,引數:源、輸出位深、核大小
# lap_des = cv2.Laplacian(img, cv2.CV_64F, ksize=5)
# Canny,引數:源、最小值、最大值
canny_des = cv2.Canny(img, 100, 200)
cv2.imshow('ori', img)
# cv2.imshow('des', des)
# cv2.imshow('blur_des', blur_des)
# cv2.imshow('gauss_des', gauss_des)
# cv2.imshow('median_des', median_des)
# cv2.imshow('bil_des', bil_des)
# cv2.imshow('sobel_des', sobel_des)
# cv2.imshow('lap_des', lap_des)
cv2.imshow('canny_des', canny_des)
cv2.waitKeyEx(0)
形態學
影象二值化
全域性二值化
將影象的每個畫素變成兩種值
import cv2
import numpy as np
ori_img = cv2.imread('8.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
# 全域性二值化,引數:源、閾值、用於替換超過最大值的值、型別
# 型別包含THRESH_BINARY、THRESH_BINARY_INV、THRESH_TRUNC、THRESH_TOZERO、THRESH_TOZERO_INV
_, des = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
# 全域性二值化(自適應閾值),引數:源、用於替換超過最大值的值、自適應方法、型別、自適應區域、從計算出的平均值或者加權平均值中減去的常量
# 自適應方法:ADAPTIVE_THRESH_MEAN_C(計算鄰近區域的平均值)、ADAPTIVE_THRESH_GAUSSIAN_C(高斯視窗加權平均值)
# 型別包含THRESH_BINARY、THRESH_BINARY_INV
auto_des = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 0)
cv2.imshow('ori', ori_img)
cv2.imshow('des', des)
cv2.imshow('auto_des', auto_des)
cv2.waitKeyEx(0)
腐蝕
import cv2
import numpy as np
ori_img = cv2.imread('8.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, des = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
# 手動構建卷積核
# kernel = np.ones((3, 3), np.uint8)
# 獲取卷積核,引數:卷積核型別、卷積核大小
# 卷積核型別:MORPH_RECT(全1)、MORPH_ELLIPSE(橢圓核,四角為0)、MORPH_CROSS(十字核,橫豎為1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 腐蝕,引數:源、卷積核、腐蝕次數
erode_des = cv2.erode(des, kernel)
cv2.imshow('ori', ori_img)
cv2.imshow('erode_des', erode_des)
cv2.waitKeyEx(0)
膨脹
import cv2
import numpy as np
ori_img = cv2.imread('8.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, des = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
# 手動構建卷積核
# kernel = np.ones((3, 3), np.uint8)
# 獲取卷積核,引數:卷積核型別、卷積核大小
# 卷積核型別:MORPH_RECT(全1)、MORPH_ELLIPSE(橢圓核,四角為0)、MORPH_CROSS(十字核,橫豎為1)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 腐蝕,引數:源、卷積核、腐蝕次數
erode_des = cv2.erode(des, kernel)
# 膨脹,引數:源、卷積核、腐蝕次數
dilate_des = cv2.dilate(des, kernel)
cv2.imshow('ori', ori_img)
cv2.imshow('erode_des', erode_des)
cv2.imshow('dilate_des', dilate_des)
cv2.waitKeyEx(0)
開運算
先做腐蝕後做膨脹
用於消除背景中的小圖形,保留大圖形,可以理解為消除主要目標外的背景中的噪點
閉運算
先做膨脹後做腐蝕
用於消除大圖形中的小圖形,可以理解為消除主要目標中的噪點
梯度運算
梯度=原圖-腐蝕後的圖,用於得到目標圖形的邊緣,一定條件下,卷積核越小,得到的邊緣越清晰而細小,卷積核越大,得到的邊緣越模糊
頂帽運算
頂帽=原圖-開運算,用於得到主要目標圖形外的小圖形,可以理解為獲取背景中的噪點
黑帽運算
黑帽=原圖-閉運算,用於得到主要圖形中的小圖形,可以理解為獲取目標圖形中的噪點
import cv2
ori_img = cv2.imread('8.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 開運算,引數:源、巨集型別(MORPH_OPEN)、卷積核
morph_open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# 閉運算,引數:源、巨集型別(MORPH_CLOSE)、卷積核
morph_close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# 梯度運算,引數:源、巨集型別(MORPH_GRADIENT)、卷積核
morph_gr = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
# 頂帽運算,引數:源、巨集型別(MORPH_TOPHAT)、卷積核
morph_top = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
# 黑帽運算,引數:源、巨集型別(MORPH_BLACKHAT)、卷積核
morph_black = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('ori', ori_img)
cv2.imshow('morph_open', morph_open)
cv2.imshow('morph_close', morph_close)
cv2.imshow('morph_gr', morph_gr)
cv2.imshow('morph_top', morph_top)
cv2.imshow('morph_black', morph_black)
cv2.waitKeyEx(0)
運算名 | 步驟(方法) | 作用 |
---|---|---|
開運算 | 先做腐蝕後做膨脹,MORPH_OPEN | 消除背景中的噪點 |
閉運算 | 先做膨脹後做腐蝕,MORPH_CLOSE | 消除主要目標中的噪點 |
梯度運算 | 原圖-腐蝕後的圖,MORPH_GRADIENT | 得到目標圖形的邊緣 |
頂帽運算 | 原圖-開運算,MORPH_TOPHAT | 獲取背景中的噪點 |
黑帽運算 | 原圖-閉運算,MORPH_BLACKHAT | 獲取目標圖形中的噪點 |
輪廓查詢
影象輪廓即具有相同顏色或強度的連續點的曲線。
影象輪廓的作用
- 圖形分析
- 物體的識別與檢測
查詢輪廓注意
- 需要先對影象進行二值化或Canny操作
- 畫輪廓會修改輸入影象(需要拷貝)
- 通常會將背景設定為黑色,目標設定為白色
import cv2
ori_img = cv2.imread('9.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
# 查詢輪廓,引數:源、組織已找到輪廓的模式、邊框點儲存模式,返回值:輪廓結果列表、層級
# 組織已找到輪廓的模式:RETR_EXTERNAL=0(只檢測外輪廓)、RETR_LIST=1(檢測到的輪廓不建立層級關係)、RETR_CCOMP=2(最多兩層)、RETR_TREE=3(樹形組織)
# 邊框點儲存模式:CHAIN_APPROX_NONE(儲存所有輪廓上的點)、CHAIN_APPROX_SIMPLE(只儲存角點)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 繪製輪廓,引數:源、輪廓(點)、需要繪製的輪廓的索引(-1表示所有)、顏色、線寬(-1表示全部填充)
contours_res = cv2.drawContours(ori_img, contours, -1, (0, 255, 0), 1)
cv2.imshow('binary', binary)
cv2.imshow('contours_res', contours_res)
cv2.waitKeyEx(0)
輪廓的面積和周長
import cv2
ori_img = cv2.imread('9.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours_res = cv2.drawContours(ori_img, contours, -1, (0, 255, 0), 1)
# 計算輪廓面積,引數:單一輪廓
area = cv2.contourArea(contours[0])
# 計算輪廓周長,引數:單一輪廓、是否閉合
length = cv2.arcLength(contours[0], True)
cv2.imshow('binary', binary)
cv2.imshow('contours_res', contours_res)
cv2.waitKeyEx(0)
多邊形逼近與凸包
import cv2
def draw(img, points):
for i in range(len(points)):
if i == len(points) -1:
next_one = points[0][0]
else:
next_one = points[i + 1][0]
cv2.line(img, points[i][0], next_one, (0, 0, 255), 3)
i += 1
ori_img = cv2.imread('10.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours_res = cv2.drawContours(ori_img, contours, -1, (0, 255, 0), 1)
# 多邊形逼近,引數:輪廓(點)、精度(越小越貼合)、是否閉合
approx_res = cv2.approxPolyDP(contours[1], 20, True)
draw(ori_img, approx_res)
# 凸包,引數:輪廓(點)、順逆時針
convex_res = cv2.convexHull(contours[2])
draw(ori_img, convex_res)
cv2.imshow('ori_img', ori_img)
# cv2.imshow('contours_res', contours_res)
cv2.waitKeyEx(0)
外接矩形
import cv2
import numpy as np
ori_img = cv2.imread('66.png')
img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
_, binary = cv2.threshold(img, 140, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 最小外接矩形,引數:輪廓(點),返回值:RotatedRect(包含起始點(x,y)、寬高(w,h)、角度(angle))
min_r = cv2.minAreaRect(contours[0])
min_box = np.int0(cv2.boxPoints(min_r))
cv2.drawContours(ori_img, [min_box], 0, (0, 255, 0), 3)
# 最大外界矩形,引數:輪廓(點),返回值:Rect(包含起始點(x,y)、寬高(w,h))
x, y, w, h = cv2.boundingRect(contours[0])
cv2.rectangle(ori_img, (x, y), (x + w, y + h), (0, 0, 255), 3)
cv2.imshow('ori_img', ori_img)
cv2.waitKeyEx(0)