算子是一個函數空間到函數空間上的映射O:X→X。廣義上的算子能夠推廣到任何空間,如內積空間等。html
在圖像處理中,一般會使用一些不一樣的算子來對圖像進行處理。下面介紹一下圖像處理中經常使用的一些算子。ios
相關算子的表達方法是git
\[{\rm{g}} = f \otimes h\]github
其具體公式爲數組
\[g(i,j) = \sum\limits_{k,l} {f(i + k,j + l)h(k,l)} \]網絡
運算步驟爲:ide
1)滑動核,使其中心位於輸入圖像g的(i,j)像素上函數
2)利用上式求和,獲得輸出圖像的(i,j)像素值post
3)充分上面操縱,直到求出輸出圖像的全部像素值學習
例:
假設
\[{\rm{a}} = \left( {\begin{array}{*{20}{c}}
{17}&{24}&1&{\begin{array}{*{20}{c}}
8&{15}
\end{array}}\\
{23}&5&7&{\begin{array}{*{20}{c}}
{14}&{16}
\end{array}}\\
4&6&{13}&{\begin{array}{*{20}{c}}
{20}&{22}
\end{array}}\\
{\begin{array}{*{20}{c}}
{10}\\
{11}
\end{array}}&{\begin{array}{*{20}{c}}
{12}\\
{18}
\end{array}}&{\begin{array}{*{20}{c}}
{19}\\
{25}
\end{array}}&{\begin{array}{*{20}{c}}
{\begin{array}{*{20}{c}}
{21}\\
2
\end{array}}&{\begin{array}{*{20}{c}}
3\\
9
\end{array}}
\end{array}}
\end{array}} \right)h = \left( {\begin{array}{*{20}{c}}
8&1&6\\
3&5&7\\
4&9&2
\end{array}} \right)\]
Matlab 函數:imfilter(A,h)
卷積算子的表達方法是
\[g = f*h\]
其具體公式爲
\[g(i,j) = \sum\limits_{k,l} {f(i - k,j - l)h(k,l) = } \sum\limits_{k,l} {f(k,l)h(i - k,j - l)} \]
運算步驟爲:
1)將核圍繞中心旋轉180度
2)滑動核,使其中心位於輸入圖像g的(i,j)像素上
3)利用上式求和,獲得輸出圖像的(i,j)像素值
4)充分上面操縱,直到求出輸出圖像的全部像素值
將上例中的數據作卷積算子運算爲:
Matlab 函數:Matlab 函數:imfilter(A,h,'conv')% imfilter默認是相關算子,所以當進行卷積計算時須要傳入參數'conv'
當對圖像邊緣的進行濾波時,核的一部分會位於圖像邊緣外面。
經常使用的策略包括:
1)使用常數填充:imfilter默認用0填充,這會形成處理後的圖像邊緣是黑色的。
2)複製邊緣像素:I3 = imfilter(I,h,'replicate');
fspecial函數能夠生成幾種定義好的濾波器的相關算子的核。
例:unsharp masking 濾波
1
2
3
4
5
|
I = imread(
'moon.tif'
);
h = fspecial(
'unsharp'
);
I2 = imfilter(I,h);
imshow(I), title(
'Original Image'
)
figure, imshow(I2), title(
'Filtered Image'
)
|
這裏的藍色矩陣就是輸入的圖像,粉色矩陣就是卷積層的神經元,這裏表示了有兩個神經元(w0,w1)。綠色矩陣就是通過卷積運算後的輸出矩陣,這裏的步長設置爲2。
藍色的矩陣(輸入圖像)對粉色的矩陣(filter)進行矩陣內積計算並將三個內積運算的結果與偏置值b相加(好比上面圖的計算:2+(-2+1-2)+(1-2-2) + 1= 2 - 3 - 3 + 1 = -3),計算後的值就是綠框矩陣的一個元素。
下面的動態圖形象地展現了卷積層的計算過程:
瞭解了卷積在圖像處理中的應用形式核方法後,下面是一些在圖像處理中經常使用到的模板(卷積核)
邊緣檢測經常藉助於空域微分算子進行,經過將其模板與圖像卷積完成.主要有一次微分(Sobel算子、Robert算子)、二次微分(Laplacian算子)等。在梯度法的基礎上,Sobel提出了一種強方向差分運算與局部平均相結合的方法,即Sobel算子.
sobel算子的思想,Sobel算子認爲,鄰域的像素對當前像素產生的影響不是等價的,因此距離不一樣的像素具備不一樣的權值,對算子結果產生的影響也不一樣。通常來講,距離越遠,產生的影響越小。其基本思想是,以待加強圖像的任意像素(i,j)爲中心,截取一個3*3像素的窗口,以下式所示:
\[\begin{array}{*{20}{c}}
{{\rm{f}}(i - 1,j - 1)}&{{\rm{f}}(i - 1,j)}&{{\rm{f}}(i - 1,j + 1)}\\
{{\rm{f}}(i,j - 1)}&{{\rm{f}}(i,j)}&{{\rm{f}}(i,j + 1)}\\
{{\rm{f}}(i + 1,j + 1)}&{{\rm{f}}(i + 1,j)}&{{\rm{f}}(i + 1,j + 1)}
\end{array}\]
分別計算中心像素在x,y方向上的梯度
sobel算子的原理,對傳進來的圖像像素作卷積,卷積的實質是在求梯度值,或者說給了一個加權平均,其中權值就是所謂的卷積核;而後對生成的新像素灰度值作閾值運算,以此來肯定邊緣信息。
Gx是對原圖x方向上的卷積,Gy是對原圖y方向上的卷積;
原圖中的做用點像素值經過卷積以後爲:
能夠簡化成:
好比,一下矩陣爲原圖中的像素點矩陣,帶入上式中的A,最終獲得的G或者|G|是下面(x,y)處的像素值,能夠本身去搜索下卷積的含義來理解。
另外,卷積核也能夠旋轉,用與查找不與x,y軸平行或垂直的方向上的邊緣。
獲得像素點新的像素值以後,給定一個閾值就能夠獲得sobel算子計算出的圖像邊緣了。
一般,爲了消除噪聲對sobel算子的影響,會增長一個預處理的操做,主要是作平滑處理下降噪聲的影響。
下面是其MATLAB的實現及效果圖
f=imread('1.jpg'); f=rgb2gray(f);%轉化成灰度圖 f=im2double(f);%函數im2double 將其值歸一化到0~1之間 %使用垂直Sobcl箅子.自動選擇閾值 [VSFAT Threshold]=edge(f, 'sobel','vertical'); %邊緣探測 figure,imshow(f),title(' 原始圖像,');%顯示原始圖像 figure,imshow(VSFAT),title( '垂直圖像邊緣檢測'); %顯示邊緣探測圖像 %使用水平和垂直Sobel算子,自動選擇閾值 SFST=edge(f,'sobel',Threshold); figure,imshow(SFST),title('水平和垂直圖像邊緣檢測'); %顯示邊緣探測圖像 %使用指定45度角Sobel算子濾波器,指定閡值 s45=[-2 -1 0;-1 0 1;0 1 2]; SFST45=imfilter(f,s45,'replicate');%功能:對任意類型數組或多維圖像進行濾波。 SFST45=SFST45>=Threshold; figure,imshow(SFST45),title('45度角圖像邊緣檢測') ; %顯示邊緣探測圖像
相關的C++代碼實現爲:
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" #include "iostream" using namespace std; using namespace cv; int main(int argc, char *argv[]) { Mat image = imread("qiaoba.jpg", 0); Mat imageX = Mat::zeros(image.size(), CV_16SC1); Mat imageY = Mat::zeros(image.size(), CV_16SC1); Mat imageXY = Mat::zeros(image.size(), CV_16SC1); Mat imageX8UC; Mat imageY8UC; Mat imageXY8UC; if (!image.data) { return -1; } GaussianBlur(image, image, Size(3, 3), 0); //高斯濾波消除噪點 uchar *P = image.data; uchar *PX = imageX.data; uchar *PY = imageY.data; int step = image.step; int stepXY = imageX.step; for (int i = 1; i<image.rows - 1; i++) { for (int j = 1; j<image.cols - 1; j++) { //經過指針遍歷圖像上每個像素 PX[i*imageX.step + j*(stepXY / step)] = abs(P[(i - 1)*step + j + 1] + P[i*step + j + 1] * 2 + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[i*step + j - 1] * 2 - P[(i + 1)*step + j - 1]); PY[i*imageX.step + j*(stepXY / step)] = abs(P[(i + 1)*step + j - 1] + P[(i + 1)*step + j] * 2 + P[(i + 1)*step + j + 1] - P[(i - 1)*step + j - 1] - P[(i - 1)*step + j] * 2 - P[(i - 1)*step + j + 1]); } } addWeighted(imageX, 0.5, imageY, 0.5, 0, imageXY);//融合X、Y方向 convertScaleAbs(imageX, imageX8UC); convertScaleAbs(imageY, imageY8UC); convertScaleAbs(imageXY, imageXY8UC); //轉換爲8bit圖像 Mat imageSobel; Sobel(image, imageSobel, CV_8UC1, 1, 1); //Opencv的Sobel函數 imshow("Source Image", image); imshow("X Direction", imageX8UC); imshow("Y Direction", imageY8UC); imshow("XY Direction", imageXY8UC); imshow("Opencv Soble", imageSobel); waitKey(); return 0; }
sobel的優缺點也比較明確。
優勢:計算簡單,速度很快;
缺點:計算方向單一,對複雜紋理的狀況顯得乏力;
直接用閾值來判斷邊緣點欠合理解釋,會形成較多的噪聲點誤判。
前面講解了卷積的原理,及卷積在圖像中的基礎應用,可是在實際應用中,根據需求和硬件條件的不一樣,卷積的應用方法和名稱也不一樣。這裏有必要將一些經常使用的卷積拿出來單獨講一下。不過在介紹前須要瞭解一些在深度學習中卷積的基本結構的定義:
卷積核大小(Kernel Size):定義了卷積操做的感覺野。在二維卷積中,一般設置爲3,即卷積核大小爲3×3。
步幅(Stride):定義了卷積核遍歷圖像時的步幅大小。其默認值一般設置爲1,也可將步幅設置爲2後對圖像進行下采樣,這種方式與最大池化相似。
邊界擴充(Padding):定義了網絡層處理樣本邊界的方式。當卷積核大於1且不進行邊界擴充,輸出尺寸將相應縮小;當卷積核以標準方式進行邊界擴充,則輸出數據的空間尺寸將與輸入相等。
輸入與輸出通道(Channels):構建卷積層時需定義輸入通道I,並由此肯定輸出通道O。這樣,可算出每一個網絡層的參數量爲I×O×K,其中K爲卷積核的參數個數。例,某個網絡層有64個大小爲3×3的卷積核,則對應K值爲 3×3 =9。
在可分離卷積(separable convolution)中,一般將卷積操做拆分紅多個步驟。而在神經網絡中一般使用的就是深度可分離卷積(depthwise separable convolution)。
假設有一個3×3大小的卷積層,其輸入通道爲1六、輸出通道爲32。那麼通常的操做就是用32個3×3的卷積核來分別同輸入數據卷積,這樣每一個卷積核須要3×3×16個參數,獲得的輸出是隻有一個通道的數據。之因此會獲得一通道的數據,是由於剛開始3×3×16的卷積核的每一個通道會在輸入數據的每一個對應通道上作卷積,而後疊加每個通道對應位置的值,使之變成了單通道,那麼32個卷積核一共須要(3×3×16)×32 =4068個參數。
用一張來解釋深度可分離卷積,以下:
能夠看到每個通道用一個filter卷積以後獲得對應一個通道的輸出,而後再進行信息的融合。而以往標準的卷積過程能夠用下面的圖來表示:
而應用深度可分離卷積的過程是①用16個3×3大小的卷積核(1通道)分別與輸入的16通道的數據作卷積(這裏使用了16個1通道的卷積核,輸入數據的每一個通道用1個3×3的卷積核卷積),獲得了16個通道的特徵圖,咱們說該步操做是depthwise(逐層)的,在疊加16個特徵圖以前,②接着用32個1×1大小的卷積核(16通道)在這16個特徵圖進行卷積運算,將16個通道的信息進行融合(用1×1的卷積進行不一樣通道間的信息融合),咱們說該步操做是pointwise(逐像素)的。這樣咱們能夠算出整個過程使用了3×3×16+(1×1×16)×32 =656個參數。能夠看出運用深度可分離卷積比普通卷積減小了所須要的參數。重要的是深度可分離卷積將以往普通卷積操做同時考慮通道和區域改變成,卷積先只考慮區域,而後再考慮通道。實現了通道和區域的分離。
Group convolution 分組卷積,最先在AlexNet中出現,因爲當時的硬件資源有限,訓練AlexNet時卷積操做不能所有放在同一個GPU處理,所以做者把feature maps分給多個GPU分別進行處理,最後把多個GPU的結果進行融合。
在說明分組卷積以前咱們用一張圖來體會一下通常的卷積操做。
從上圖能夠看出,通常的卷積會對輸入數據的總體一塊兒作卷積操做,即輸入數據:H1×W1×C1;而卷積核大小爲h1×w1,一共有C2個,而後卷積獲得的輸出數據就是H2×W2×C2。這裏咱們假設輸出和輸出的分辨率是不變的。主要看這個過程是一鼓作氣的,這對於存儲器的容量提出了更高的要求。
可是分組卷積明顯就沒有那麼多的參數。先用圖片直觀地感覺一下分組卷積的過程。對於上面所說的一樣的一個問題,分組卷積就以下圖所示。
能夠看到,圖中將輸入數據分紅了2組(組數爲g),須要注意的是,這種分組只是在深度上進行劃分,即某幾個通道編爲一組,這個具體的數量由(C1/g)決定。由於輸出數據的改變,相應的,卷積核也須要作出一樣的改變。即每組中卷積核的深度也就變成了(C1/g),而卷積核的大小是不須要改變的,此時每組的卷積核的個數就變成了(C2/g)個,而不是原來的C2了。而後用每組的卷積核同它們對應組內的輸入數據卷積,獲得了輸出數據之後,再用concatenate的方式組合起來,最終的輸出數據的通道仍舊是C2。也就是說,分組數g決定之後,那麼咱們將並行的運算g個相同的卷積過程,每一個過程裏(每組),輸入數據爲H1×W1×C1/g,卷積核大小爲h1×w1×C1/g,一共有C2/g個,輸出數據爲H2×W2×C2/g。
從一個具體的例子來看,Group conv自己就極大地減小了參數。好比當輸入通道爲256,輸出通道也爲256,kernel size爲3×3,不作Group conv參數爲256×3×3×256。實施分組卷積時,若group爲8,每一個group的input channel和output channel均爲32,參數爲8×32×3×3×32,是原來的八分之一。而Group conv最後每一組輸出的feature maps應該是以concatenate的方式組合。
Alex認爲group conv的方式可以增長 filter之間的對角相關性,並且可以減小訓練參數,不容易過擬合,這相似於正則的效果。
空洞卷積(dilated convolution)是針對圖像語義分割問題中下采樣會下降圖像分辨率、丟失信息而提出的一種卷積思路。利用添加空洞擴大感覺野,讓本來3
x3的卷積核,在相同參數量和計算量下擁有5x5(dilated rate =2)或者更大的感覺野,從而無需下采樣。擴張卷積(dilated convolutions)又名空洞卷積(atrous convolutions),向卷積層引入了一個稱爲 「擴張率(dilation rate)」的新參數,該參數定義了卷積核處理數據時各值的間距。換句話說,相比原來的標準卷積,擴張卷積(dilated convolution) 多了一個hyper-parameter(超參數)稱之爲dilation rate(擴張率),指的是kernel各點以前的間隔數量,【正常的convolution 的 dilatation rate爲 1】。
(a)圖對應3x3的1-dilated conv,和普通的卷積操做同樣。(b)圖對應3x3的2-dilated conv,實際的卷積kernel size仍是3x3,可是空洞爲1,須要注意的是空洞的位置全填進去0,填入0以後再卷積便可。【此變化見下圖】(c)圖是4-dilated conv操做。
在上圖中擴張卷積的感覺野能夠由如下公式計算獲得;其中i+1表示dilated rate。
好比上圖中(a),dilated=1,F(dilated) = 3×3;圖(b)中,dilated=2,F(dilated)=7×7;圖(c)中,dilated=4, F(dilated)=15×15。
dilated=2時具體的操做,即按照下圖在空洞位置填入0以後,而後直接卷積就能夠了。
在二維圖像上直觀地感覺一下擴張卷積的過程:
上圖是一個擴張率爲2的3×3卷積核,感覺野與5×5的卷積核相同,並且僅須要9個參數。你能夠把它想象成一個5×5的卷積核,每隔一行或一列刪除一行或一列。
在相同的計算條件下,空洞卷積提供了更大的感覺野。空洞卷積常常用在實時圖像分割中。當網絡層須要較大的感覺野,但計算資源有限而沒法提升卷積核數量或大小時,能夠考慮空洞卷積。
對於標準卷積核狀況,好比用3×3卷積核連續卷積2次,在第3層中獲得1個Feature點,那麼第3層這個Feature點換算回第1層覆蓋了多少個Feature點呢?
第3層:
第2層:
第1層:
第一層的一個5×5大小的區域通過2次3×3的標準卷積以後,變成了一個點。也就是說從size上來說,2層3*3卷積轉換至關於1層5*5卷積。題外話,從以上圖的演化也能夠看出,一個5×5的卷積核是能夠由2次連續的3×3的卷積代替。
但對於dilated=2,3*3的擴張卷積核呢?
第3層的一個點:
第2層:
能夠看到第一層13×13的區域,通過2次3×3的擴張卷積以後,變成了一個點。即從size上來說,連續2層的3×3空洞卷積轉換至關於1層13×13卷積。
那什麼是反捲積?從字面上理解就是卷積的逆過程。值得注意的反捲積雖然存在,可是在深度學習中並不經常使用。而轉置卷積雖然又名反捲積,卻不是真正意義上的反捲積。由於根據反捲積的數學含義,經過反捲積能夠將經過卷積的輸出信號,徹底還原輸入信號。而事實是,轉置卷積只能還原shape大小,而不能還原value。你能夠理解成,至少在數值方面上,轉置卷積不能實現卷積操做的逆過程。因此說轉置卷積與真正的反捲積有點類似,由於二者產生了相同的空間分辨率。可是又名反捲積(deconvolutions)的這種叫法是不合適的,由於它不符合反捲積的概念。
△卷積核爲3×三、步幅爲2和無邊界擴充的二維轉置卷積
須要注意的是,轉置先後padding,stride仍然是卷積過程指定的數值,不會改變。
因爲上面只是理論的說明了轉置卷積的目的,而並無說明如何由卷積以後的輸出重建輸入。下面咱們經過一個例子來講明感覺下。
好比有輸入數據:3×3,Reshape以後,爲A :1×9,B(能夠理解爲濾波器):9×4(Toeplitz matrix) 那麼A*B=C:1×4;Reshape C=2×2。因此,經過B 卷積,咱們從輸入數據由shape=3×3變成了shape=2×2。反過來。當咱們把卷積的結果拿來作輸入,此時A:2×2,reshape以後爲1×4,B的轉置爲4×9,那麼A*B=C=1×9,注意此時求得的C,咱們就認爲它是卷積以前的輸入了,雖然存在誤差。而後reshape爲3×3。因此,經過B的轉置 - 「反捲積」,咱們從卷積結果shape=2×2獲得了shape=3×3,重建了分辨率。
也就是輸入feature map A=[3,3]通過了卷積B=[2,2] 輸出爲 [2,2] ,其中padding=0,stride=1,反捲積(轉置卷積)則是輸入feature map A=[2,2],通過了反捲積濾波B=[2,2].輸出爲[3,3]。其中padding=0,stride=1不變。那麼[2,2]的卷積核(濾波器)是怎麼轉化爲[4,9]或者[9,4]的呢?經過Toeplitz matrix。
至於這其中Toeplitz matrix是個什麼東西,此處限於篇幅就再也不介紹了。但即便不知道這個矩陣,轉置卷積的具體工做也應該可以明白的。