濾波
線性濾波可以說是圖像處理最基本的方法,它可以允許我們對圖像進行處理,產生很多不同的效果。
卷積
卷積的概念:
卷積的原理與濾波類似。但是卷積卻有著細小的差別。 卷積操作也是卷積核與圖像對應位置的乘積和。但是卷積操作在做乘積之前,需要先 將卷積核翻轉180度,之后再做乘積。
卷積的數學定義:
一般稱為g為作用在f上的filter或kernel
卷積解決的問題:
卷積負責提取圖像中的局部特征
對于濾波器,也有一定的規則要求:
1)濾波器的大小應該是奇數,這樣它才有一個中心,例如3x3,5x5或者7x7。有中心了,也有 了半徑的稱呼,例如5x5大小的核的半徑就是2。
2)濾波器矩陣所有的元素之和應該要等于1,這是為了保證濾波前后圖像的亮度保持不變。但 這不是硬性要求。
3)如果濾波器矩陣所有元素之和大于1,那么濾波后的圖像就會比原圖像更亮,反之,如果小 于1,那么得到的圖像就會變暗。如果和為0,圖像不會變黑,但也會非常暗。
4)對于濾波后的結構,可能會出現負數或者大于255的數值。對這種情況,我們將他們直接截 斷到0和255之間即可。對于負數,也可以取絕對值。
卷積的應用:
第一種卷積:
一個沒有任何效果的卷積
將原像素中間像素值乘1,其余全部乘0。 顯然像素值不會發生任何變化。
第二種卷積:
平滑均值濾波
取九個值的平均值代替中間像素值 — 起到平滑的效果。
第三種卷積:
高斯平滑
高斯平滑水平和垂直方向呈現高斯分布,更突出了 中心點在像素平滑后的權重,相比于均值濾波而言, 有著更好的平滑效果。
第四種卷積:
圖像銳化
圖像銳化使用的是拉普拉斯變換核函數
第五種卷積:
邊界提取的卷積:
用Gx來卷積下面這張圖的話,就會在黑白邊界獲得比較大的值。
手動計算可以發現Gx對橫向邊界會有很大的像素值,Gy是對縱向邊界有很大的像素值,從而實現邊界提取。
第六種卷積:
Sobel邊緣檢測:
Sobel更強調了和邊緣相鄰的像素點 對邊緣的影響。
(不僅僅考慮橫向和縱向的邊界提取,其他方向的邊界也會得到)
代碼實現:
import cv2
import numpy as npimg = cv2.imread("lenna.png", 0)'''
Sobel函數求完導數后會有負值,還有會大于255的值。
而原圖像是uint8,即8位無符號數(范圍在[0,255]),所以Sobel建立的圖像位數不夠,會有截斷。
因此要使用16位有符號的數據類型,即cv2.CV_16S。
'''
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)'''
在經過處理后,別忘了用convertScaleAbs()函數將其轉回原來的uint8形式。
否則將無法顯示圖像,而只是一副灰色的窗口。
dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
其中可選參數alpha是伸縮系數,beta是加到結果上的一個值。結果返回uint8類型的圖片。
'''absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)'''
由于Sobel算子是在兩個方向計算的,最后還需要用cv2.addWeighted(...)函數將其組合起來
。其函數原型為:
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
其中alpha是第一幅圖片中元素的權重,beta是第二個的權重,
gamma是加到最后結果上的一個值。
'''dst = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)cv2.imshow("absX", absX)
cv2.imshow("absY", absY)cv2.imshow("Result", dst)cv2.waitKey(0)
cv2.destroyAllWindows()
實現結果:
豎向:
橫向:
總和結果:
對比圖中橫向和縱向的女生嘴唇可以明顯看出來,橫向和縱向的提取效果
步長/Stride
如果用(f, f)的過濾器來卷積一張(h, w)大小的圖片,每次移動一個像素的話,那么得出的結果 就是(h-f+1, w-f+1)的輸出結果。f是過濾器大小,h和w分別是圖片的高寬。 如果每次不止移動一個像素,而是s個像素,那么結果就會變為:
這個s就叫做步長。
通俗來講,就是卷積核移動的一步的大小。
存在的問題:
? 只要是f或s的值比1要大的話,那么每次卷積之后結果的長寬,要比卷積前小一些。(比如說[5×5]的矩陣,在經過[3×3]的卷積核后的結果是[3×3],比原先[5×5]的矩陣要小)
? 丟失信息
填充/Pading
填充就是在原矩陣外邊添加一圈或多圈全0的值。
主要用來保證卷積核輸出的格式。比如說:[5×5]的矩陣,在經過[3×3]的卷積核后的結果是[3×3],我們要是像得到還是[5×5]的矩陣,就需要將原[5×5]的矩陣填充為[7×7]的矩陣,這樣卷積后的結果就是[5×5]的矩陣了
Same(相同)填充:
Vaild(有效)填充:
是分數怎么辦?一般的處理是,只取整數部分。
而這種p=0,然后結果取整數部分的處理方式,叫做Valid(有效)填充。
Same(相同)填充和Vaild(有效)填充的區別:
SAME進行填充,,當滑動卷積核之后,若多出一列,“Same”發現余下的窗口不到卷積核大小并不會把多出的一列丟棄,但是只有一列了不夠卷積核大小怎么辦?填充!會在原圖像外圍添加一圈或者多圈全“0”(圖片卷積后可能不會變小。)
VALID不進行填充,當滑動卷積核之后,若多出一列,“Vaild”發現余下的窗口不到卷積核大小,會就把剩下的一列直接去了(圖片卷積后還是會變小。)
其中:W為輸入的size,F為filter的size,S為步長
此處參考了網絡 wuzqchom的博客
TensorFlow中CNN的兩種padding方式“SAME”和“VALID”
卷積的擴展:3通道卷積
卷積核的確定:
CNN厲害的地方在于, 過濾器的特征并不是人為設定的,而是通過大量圖片自己訓練出來的。