【cv筆記】卷積 + 數學形態學(膨脹腐蝕、開閉運算等)
一 卷積
1 卷積定義
卷積是兩個變數在某範圍內相乘後求和的結果。如果卷積的變數是序列x(n)和h(n),則卷積的結果
一維卷積
【例】
X = [10, 1, 2, 3, 0, 3]
H= [0.4, 1, 0.5, 2] (卷積核Kernel
)
Y=X * H
。。。。。。
。。。。
import numpy as np
from scipy import signal
X = np.array([10, 1, 2, 3, 0 , 3])
H = np.array([2, 0.5, 1, 0.4])
S = signal.convolve(X, H)
print(S)
output:
[ 20. 7. 14.5 12. 3.9 9.8 2.7 3. 1.2]
二維卷積
【例】
import numpy as np
from scipy import signal
F = np.array([
[1, 2, 0 , 7, 0, 3],
[8, 7, 3, 4, 1, 0],
[0, 3, 5, 3, 0, 1],
[1, 2, 1, 7, 1, 0],
[0, 0, 0, 0, 0, 1]])
H = np.array([
[-2, 1, 3],
[-2, 0, 2],
[1, 0, -1]])
S = signal.convolve2d(F, H, boundary='wrap',mode='valid')
print(S)
output:
[[ 2 19 22 11]
[-12 -10 16 22]
[ 5 -10 -5 10]]
H、X的順序是不影響結果的,S = H * X = X * H
2 影象的卷積運算
可看做是加權求和的過程,使用到的影象區域中每個畫素分別與卷積核(權矩陣)的每個元素相乘,所有乘積只和作為區域中心畫素的新值
濾波器(卷積核)的一般要求
- 2D卷積需要四個迴圈巢狀,比較耗時,所以我們一般採用較小的卷積核,如3*3、5*5
- 濾波器的大小應該為奇數,如5*5 、7*7 ,這樣才會有中心,7*7的核半徑為3
- 濾波器矩陣所有的元素之和等於1,濾波前後影象的亮度保持不變。大於1,影象變亮,小於1,影象變暗
- 對於濾波後的結構,可能會出現0~255以外的數值。對這種情況,直接截斷到0和255之間即可
邊界處理
當處理影象邊界畫素時,卷積核與影象區域不能匹配,卷積核中心與邊界元素點對應,卷積運算出現問題,此時有以下幾種處理方式:
1)想象I是無限長的影象的一部分,除了我們給定值的部分,其他部分的畫素值都是0。
2)第二種方法也是想象I是無限影象的一部分。但沒有指定的部分是用影象邊界的值進行拓展。
3)第三種情況就是認為影象是週期性的。也就是I不斷的重複。週期就是I的長度。在我們這裡,I(0)和I(8)的值就是一樣的,I(9)的值和I(1)的值也是一樣的。
4)忽略邊界畫素(處理後的影象丟掉這些畫素)
3 卷積在影象處理中的應用
- 均值模糊 高斯模糊
- 高通濾波 低通濾波
- 影象銳化 浮雕
- 邊緣檢測
- 。。。
例項0
下面這個濾波器,只有中心點的值是1,鄰域點的權值都是0。
相當於未對圖片進行變化
例項1 均值模糊
import cv2
import numpy as np
img =cv2.imread("pp1.jpg")
fil = np.array([[ 1/9,1/9, 1/9],
[ 1/9, 1/9, 1/9],
[ 1/9, 1/9, 1/9]])
res = cv2.filter2D(img,-1,fil)
cv2.imshow('win',res)
key_pressed=cv2.waitKey(0)
例項2 影象銳化
import cv2
import numpy as np
img =cv2.imread("pp1.jpg")
fil = np.array([[ -1,-1, -1],
[ -1, 9, -1],
[ -1, 1, -1]])
res = cv2.filter2D(img,-1,fil)
cv2.imshow('win',res)
key_pressed=cv2.waitKey(0)
例項3 邊緣檢測
其他效果
二 數學形態學(Mathematical morphology)
是一門建立在格論和拓撲學基礎之上的影象分析學科,是數學形態學影象處理的基本理論。其基本的運算包括:二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形態學梯度、Top-hat變換、顆粒分析、流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形態學梯度等。
1 腐蝕 (erode)
先確定一個核kernel
例如確定好核的尺寸為3*3 .
在opencv中核又被稱之為結構元素。
用結構元素與其覆蓋的二值影象做與 (and)操作 ,如果都為1,結果影象的該畫素為1。否則為0。
也就是說, 如果一個點周邊所有點與其本身, 只要這裡面有一個0, 它就會被視作為0.
核取的越大, 腐蝕效果越強.
kernel = np.ones((5,5), np.uint8) #新建一個核
erorsion_img = cv2.erode(img, kernel, iterations=1) #將核傳入erode函式
iterations
為迭代次數
下圖分別為 原圖 、 1次迭代 、 2次迭代
import cv2
import numpy as np
img = cv2.imread("d1.png", flags=cv2.IMREAD_GRAYSCALE)# 讀入灰度圖
#print(img)
kernel = np.ones((5,5), np.uint8)
erorsion_img = cv2.erode(img, kernel, iterations=1)
cv2.imshow('win',erorsion_img )
key_pressed=cv2.waitKey(0)
2 膨脹 (dilate)
假如使用的是3*3 的核(結構元素).
用核與其覆蓋的二值影象做或or
操作
如果周邊與其自身任意一個點為1,結果影象的該畫素為1, 否則為0
kernel = np.ones((5,5), np.uint8) #新建一個核
dilation_img = cv2.dilate(img, kernel, iterations=1) #將核傳入dilate函式
下圖分別為 原圖 、 1次迭代 、 2次迭代
3 開運算 (opening )
開運算(opening) 等於對影象先進行腐蝕(erode) 然後進行膨脹(dilate).
通常用於去除小粒噪聲
opening_img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
import cv2
import numpy as np
img = cv2.imread("dd.png", flags=cv2.IMREAD_GRAYSCALE)# 讀入灰度圖
kernel = np.ones((5,5), np.uint8)
opening_img = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel,iterations=1)
cv2.imshow('win',opening_img )
key_pressed=cv2.waitKey(0)
4 閉運算 (closing )
閉運算(opening) 等於對影象先進行膨脹(dilate)然後進行腐蝕(erode) .
通常用於消除內部細小空洞的部分
closing_img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel,iterations=1)
import cv2
import numpy as np
img = cv2.imread("p.png", flags=cv2.IMREAD_GRAYSCALE)# 讀入灰度圖
kernel = np.ones((5,5), np.uint8)
closing_img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel,iterations=1)
cv2.imshow('win',closing_img)
key_pressed=cv2.waitKey(0)
5 數學形態學梯度 (gradient)
數學形態學梯度 = 影象膨脹 - 影象腐蝕
獲取到影象的邊緣.
gradient_img = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
用二進位制邏輯運算也可以得到 gradient :
erode = cv2.erode(img, kernel)
dilate = cv2.dilate(img,kernel)
gradient = cv2.bitwise_xor(dilate, erode)
6 頂帽運算(Top Hat)
頂帽運算為原影象與它的開運算值之差,
因為開運算帶來的結果是放大了裂縫或者區域性低亮度的區域,因此得到的圖突出了比原圖輪廓周圍的區域更明亮的區域,且這一操作和選擇的核的大小相關。
頂帽運算往往用來分離比鄰近點亮一些的斑塊。
7 黑帽運算(black-tophat)
黑帽運算為原影象與它的閉運算值之差,
黑帽運算後的效果圖突出了比原圖輪廓周圍的區域更暗的區域,且這一操作和選擇的核的大小相關。
黑帽運算用來分離比鄰近點暗一些的斑塊。