【OpenCV快速入門系列02】進階操作

1 形態學操作

import numpy as np
import cv2
import matplotlib.pyplot as plt

def show(image):
    plt.imshow(image)
    plt.axis('off')
    plt.show()
# 結構元素
kernel1=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) # 矩形
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) # 橢圓
kernel3 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5,5)) # 十字形
img=cv2.imread('C:/Users/15151/Pictures/embedded.jpg')
show(img)

在這裏插入圖片描述

img_erosion=cv2.erode(img,kernel1) # 腐蝕,取局部最小值
show(img_erosion)

在這裏插入圖片描述

img_dilation=cv2.dilate(img,kernel1) # 膨脹,取局部最大值
show(img_dilation)

在這裏插入圖片描述

img_open=cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel1) # 開運算,先腐蝕後膨脹,消除小白點
show(img_open)

在這裏插入圖片描述

img_close=cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel1) # 閉運算,先膨脹後腐蝕,消除小黑點
show(img_close)

在這裏插入圖片描述

img_gradient=cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel1) # 形態學梯度,膨脹圖減去腐蝕圖,得到輪廓
show(img_gradient)

在這裏插入圖片描述

2 圖像模糊

# 卷積核大小
kernel_sizes=[(3,3),(9,9),(15,15)]
for i,kernel in enumerate(kernel_sizes):
    img_blur=cv2.blur(img,kernel) # 平均平滑,卷積核內所有像素的均值
    print(kernel)
    show(img_blur)

(3, 3)
在這裏插入圖片描述
(9, 9)
在這裏插入圖片描述
(15, 15)
在這裏插入圖片描述

# 卷積核大小
kernel_sizes=[(3,3),(9,9),(15,15)]
for i,kernel in enumerate(kernel_sizes):
    img_gaussianblur=cv2.GaussianBlur(img,kernel,0) # 高斯平滑,卷積核內所有像素的加權均值
    print(kernel)
    show(img_gaussianblur)

(3, 3)
在這裏插入圖片描述
(9, 9)
在這裏插入圖片描述
(15, 15)
在這裏插入圖片描述

for i,kernel in enumerate((3,9,15)):
    img_medianblur=cv2.medianBlur(img,kernel) # 中值平滑,卷積核內所有像素的中值作爲中心像素值
    print(kernel)
    show(img_medianblur)

3
在這裏插入圖片描述
9
在這裏插入圖片描述
15
在這裏插入圖片描述

# 參數集:鄰域直徑,灰度值相似性高斯函數標準差,空間高斯函數標準差
params = [(11,21,7),(11,41,21),(15,75,75)]
for i,(diameter,sigmaColor,sigmaSpace) in enumerate(params):
    img_bilateralblur = cv2.bilateralFilter(img, diameter,sigmaColor,sigmaSpace) # 雙邊平滑,保持邊界清晰的去噪
    show(img_bilateralblur)

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

3 色彩空間

# R,G,B三個顏色通道每種色各分爲256階亮度,在0時“燈”最弱,而在255時“燈”最亮。三色灰度都爲0時,是最暗的黑色調;三色灰度都爲255時,是最亮的白色調。
(R, G, B) = cv2.split(img) # RGB通道分割
zeros = np.zeros(img.shape[:2],dtype='uint8')
show(cv2.merge([R,zeros,zeros]))
show(cv2.merge([zeros,G,zeros]))
show(cv2.merge([zeros,zeros,B]))

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

# HSV顏色空可以更好的數字化處理顏色;
# 色調(H, Hue):取值範圍爲0°~360°,紅色爲0°,綠色爲120°,藍色爲240°
# 飽和度(S,Saturation):顏色接近光譜色的程度,取值範圍爲0%~100%,值越大,顏色越飽和
# 明度(V, Value):顏色明亮的程度,取值範圍爲0%(黑)到100%(白)
img_hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
(H, S, V) = cv2.split(img_hsv) # HSV通道分割
zeros = np.zeros(img.shape[:2],dtype='uint8')
show(cv2.merge([H,zeros,zeros]))
show(cv2.merge([zeros,S,zeros]))
show(cv2.merge([zeros,zeros,V]))

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

# Lab顏色空間用於計算機色調調整和彩色校正
# L* 表示顏色的明度
# a* 正值表示紅色,負值表示綠色
# b* 正值表示黃色,負值表示藍色
img_lab = cv2.cvtColor(img, cv2.COLOR_RGB2LAB)
(L, A, B) = cv2.split(img_lab) # LAB通道分割
zeros = np.zeros(img.shape[:2],dtype='uint8')
show(cv2.merge([L,zeros,zeros]))
show(cv2.merge([zeros,A,zeros]))
show(cv2.merge([zeros,zeros,B]))

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

# 灰階圖像就是黑白圖片
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img_gray,'gray')
plt.axis('off')
plt.show()

在這裏插入圖片描述

4 二值化

# 二值化
ret1,thresh1 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY) # 二值閾值化
ret2,thresh2 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV) # 反向二值閾值化
ret3,thresh3 = cv2.threshold(img_gray,127,255,cv2.THRESH_TRUNC) # 截斷閾值化
ret4,thresh4 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO) # 超過閾值置0
ret5,thresh5 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO_INV) # 低於閾值置0
# 可視化
titles = ['original','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
imgs = [img_gray, thresh1, thresh2, thresh3, thresh4, thresh5]
plt.figure(figsize=(15,5))
for i in range(6):
    plt.subplot(2,3,i+1)
    plt.imshow(imgs[i],'gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

在這裏插入圖片描述

# OTSU自動選擇閾值二值化
ret1,thresh1 = cv2.threshold(img_gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)
ret2,thresh2 = cv2.threshold(img_gray,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) # 反向
# 可視化
titles = ['original','BINARY','BINARY_INV']
imgs = [img_gray, thresh1, thresh2]
plt.figure(figsize=(10,5))
for i in range(3):
    plt.subplot(1,3,i+1)
    plt.imshow(imgs[i],'gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

在這裏插入圖片描述

# 自適應閾值二值化:根據圖像上的每一個小區域計算與其對應的閾值,而非全局閾值
# cv2.ADPTIVE_THRESH_MEAN_C:閾值取自相鄰區域的平均值 
# cv2.ADPTIVE_THRESH_GAUSSIAN_C:閾值取值相鄰區域的加權和,權重爲一個高斯窗口。
# Block Size - 鄰域大小(用來計算閾值的區域大小)
# C - 一個常數,閾值就等於平均值或者加權平均值減去這個常數
th1 = cv2.adaptiveThreshold(img_gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3) # 平均值閾值
th2 = cv2.adaptiveThreshold(img_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3) # 高斯閾值
# 可視化
titles = ['original', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
imgs = [img_gray, th1, th2]
plt.figure(figsize=(10,5))
for i in range(3):
    plt.subplot(1,3,i+1)
    plt.imshow(imgs[i],'gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

在這裏插入圖片描述

5 圖像梯度

# 圖像梯度:Sobel, Scharr 其實就是求一階或二階導數。 
# Scharr 是對 Sobel的優化。Laplacian 是求二階導數。
# 梯度的方向一般總是與邊界垂直。梯度方向被歸爲四類:垂直,水平,和兩個對角線。
laplacian = cv2.Laplacian(img_gray, cv2.CV_64F) # cv2.CV_64F輸出圖像的深度,因爲梯度可能是正也可能是負
sobelx = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3) # 1, 0表示在x方向求一階導數,最大可以求2階導數
sobely = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3) # 0, 1表示在y方向求一階導數,最大可以求2階導數
# 可視化
titles = ['Original', 'Laplacian', 'SobelX', 'SobelY']
images = [img_gray,laplacian,sobelx,sobely]
plt.figure(figsize=(10,5))
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.axis('off')
plt.show()

在這裏插入圖片描述

6 Canny邊緣檢測

# Canny 邊緣檢測
# 1.噪聲去除:5x5 的高斯濾波器
# 2.計算圖像梯度:Sobel 算子計算水平方向和豎直方向的一階導數,找到邊界的梯度和方向
# 3.非極大值抑制:對整幅圖像做一個掃描,去除那些非邊界上的點
# 4.滯後閾值:當圖像的灰度梯度高於 maxVal 時被認爲是真的邊界,那些低於 minVal 的邊界會被拋棄
edges = cv2.Canny(img_gray,100,200)
plt.imshow(edges,'gray')
plt.axis('off')
plt.show()

在這裏插入圖片描述

7 視頻操作

# 攝像頭讀取
cap = cv2.VideoCapture(0) 
while(True):
    # ret 讀取成功True或失敗False
    # frame讀取到的圖像的內容
    # 讀取一幀數據
    ret,frame = cap.read()
    # 變爲灰度圖
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    cv2.imshow('frame',gray)
    # waitKey功能是不斷刷新圖像,單位ms,返回值是當前鍵盤按鍵值
    # ord返回對應的ASCII數值
    if cv2.waitKey(1) & 0xff == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
# 讀取視頻文件
cap = cv2.VideoCapture('G:/data/AccidentDetection20190725/test_video/2.mp4')
# 視頻每秒傳輸幀數
fps = cap.get(cv2.CAP_PROP_FPS)
# 視頻圖像的寬度
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 視頻圖像的長度
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
while(True):
    # ret 讀取成功True或失敗False
    # frame讀取到的圖像的內容
    # 讀取一幀數據
    ret,frame = cap.read()
    if ret!=True:
        break
    cv2.imshow('frame',frame)
    # waitKey功能是不斷刷新圖像,單位ms,返回值是當前鍵盤按鍵值
    # ord返回對應的ASCII數值
    if cv2.waitKey(25) & 0xff == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
# 視頻寫入
fourcc = cv2.VideoWriter_fourcc(*'XVID') # 編碼格式
out = cv2.VideoWriter('G:/data/AccidentDetection20190725/test_video/output.avi',fourcc,fps,(frame_width,frame_height))

while(True):
    ret, frame = cap.read()
    if ret==True:
        # 水平翻轉
        frame = cv2.flip(frame,1)
        out.write(frame)
        cv2.imshow('frame',frame)
        if cv2.waitKey(25) & 0xff == ord('q'):
            break
    else:
        break
out.release()
cap.release()
cv2.destroyAllWindows()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章