轉載: https://blog.csdn.net/hxg2006/article/details/79626288 http://blog.csdn.net/chaipp0607/article/details/72236892
https://www.zhihu.com/question/22298352
在圖像處理領域,我們經常能聽到濾波,卷積之類的詞,其實他們都可以看做一種圖像的卷積操作,相對應的卷積核,卷積模板,濾波器,濾波模板,掃描窗其實也都是同一個東西。下面我們進一步討論圖像中的卷積操作核卷積的意義。
1、數字信號處理中卷積理解
卷積一詞最開始出現在信號與線性系統中,信號與線性系統中討論的就是信號經過一個線性系統以後發生的變化。由於現實情況中常常是一個信號前一時刻的輸出影響着這一時刻的輸出,所在一般利用系統的單位響應與系統的輸入求卷積,以求得系統的輸出信號(當然要求這個系統是線性時不變的)。
卷積的定義: 卷積是兩個變量在某範圍內相乘後求和的結果。如果卷積的變量是序列x(n)和h(n),則卷積的結果:
鏈接:https://www.zhihu.com/question/22298352/answer/50940942
來源:知乎
對於初學者,我推薦用複利的例子來理解卷積可能更好理解一些:
小明存入100元錢,年利率是5%,按複利計算(即將每一年所獲利息加入本金,以計算下一年的利息),那麼在五年之後他能拿到的錢數是,如下表所示:
將這筆錢存入銀行的一年之後,小明又往銀行中存入了100元錢,年利率仍爲5%,那麼這筆錢按複利計算,到了第五年,將收回的錢數是,我們將這一結果作爲新的一行加入上面的表格中:
以此類推,如果小明每年都往銀行中存入新的100元錢,那麼這個收益表格將是這樣的:
<img src="https://pic1.zhimg.com/50/cfe98b9d33640fae02a21bf369f0459d_hd.jpg" data-rawwidth="1296" data-rawheight="284" class="origin_image zh-lightbox-thumb" width="1296" data-original="https://pic1.zhimg.com/cfe98b9d33640fae02a21bf369f0459d_r.jpg">可見,最終小明拿到的錢將等於他各年存入的錢分別計算複利之後得到的錢數的總和,即:
用求和符號來簡化這個公式,可以得到:
在上式中,爲小明的存錢函數,而爲存入銀行的每一筆錢的複利計算函數。在這裏,小明最終得到的錢就是他的存錢函數和複利計算函數的卷積。
爲了更清晰地看到這一點,我們將這個公式推廣到連續的情況,也就是說,小明在從到的這一段時間內,每時每刻都往銀行裏存錢,他的存錢函數爲,而銀行也對他存入的每一筆錢按複利公式計算收益:,則小明到時間將得到的總錢數爲:
這也就是卷積的表達式了,上式可以記爲。相信通過上面這個例子,大家應該能夠很清晰地記住卷積公式了。下面我們再展開說兩句:
如果我們將小明的存款函數視爲一個信號發生(也就是激勵)的過程,而將複利函數視爲一個系統對信號的響應函數(也就是響應),那麼二者的卷積就可以看做是在時刻對系統進行觀察,得到的觀察結果(也就是輸出)將是過去產生的所有信號經過系統的「處理/響應」後得到的結果的疊加,這也就是卷積的物理意義了。
鏈接:https://www.zhihu.com/question/22298352/answer/91131073
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
看了好多關於卷積的答案,看到這個例子才徹底地理解了這個過程~
關於卷積的一個血腥的講解
比如說你的老闆命令你幹活,你卻到樓下打檯球去了,後來被老闆發現,他非常氣憤,扇了你一巴掌(注意,這就是輸入信號,脈衝),於是你的臉上會漸漸地(賤賤地)鼓起來一個包,你的臉就是一個系統,而鼓起來的包就是你的臉對巴掌的響應,好,這樣就和信號系統建立起來意義對應的聯繫。下面還需要一些假設來保證論證的嚴謹:假定你的臉是線性時不變系統,也就是說,無論什麼時候老闆打你一巴掌,打在你臉的同一位置(這似乎要求你的臉足夠光滑,如果你說你長了很多青春痘,甚至整個臉皮處處連續處處不可導,那難度太大了,我就無話可說了哈哈),你的臉上總是會在相同的時間間隔內鼓起來一個相同高度的包來,並且假定以鼓起來的包的大小作爲系統輸出。好了,那麼,下面可以進入核心內容——卷積了!
鏈接:https://www.zhihu.com/question/22298352/answer/193852554
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
想要形象地理解卷積這個數學概念,那麼思路當然是找它的“實際應用”,最容易想到的例子就是它對動態系統的輸入輸出關係的描述了。許多答主提到了“打臉”的例子,非常形象,就不復述了。
以下略糾結,嫌麻煩可以跳過直接看圖。
之前我對@鏡面狐答案的有部分理解是不準確的;現在看來他對 的定義確實有問題(感謝@高啓峯和@逐光指出)。順便提一下,@鏡面狐的答案引用了Franklin的那本經典教材,但是我越來越感覺它講卷積的那部分並沒有寫得很清楚,比如它和配圖和文字就對不上號,徒增了理解的難度。我儘量梳理一遍吧。
首先是單位脈衝和單位脈衝響應 的定義,大家應該都懂我就不囉嗦了。(注意 的“面積”爲 。)再是定義 和 ,當 時趨近於 和 。(同樣注意 的高度爲 ,面積爲 。)
一個輸入信號可以拆成很多 的和,即 (所以
取極限寫成積分形式即
注意不要忘了 ,因爲我們是要跟單位脈衝比較面積,即 是 的多少倍。
糾結部分完。
有了這個基礎,再去理解卷積的公式就沒那麼intimidating了。放張圖,心血來潮隨手畫的,但願能頂個卵用。
另外,對於實際系統(因果系統),由於未來的打臉( )不會造成現在的臉腫,所以積分上限設爲 就行了;此外我們還一般假設 之前沒人打臉並且臉也不腫,所以積分下限設爲 就行了。因此。
2、數字圖像處理中卷積
數字圖像是一個二維的離散信號,對數字圖像做卷積操作其實就是利用卷積核(卷積模板)在圖像上滑動,將圖像點上的像素灰度值與對應的卷積核上的數值相乘,然後將所有相乘後的值相加作爲卷積核中間像素對應的圖像上像素的灰度值,並最終滑動完所有圖像的過程。
2.1邊界補充問題
上面的圖片說明了圖像的卷積操作,但是他也反映出一個問題,如上圖,原始圖片尺寸爲7*7,卷積核的大小爲3*3,當卷積核沿着圖片滑動後只能滑動出一個5*5的圖片出來,這就造成了卷積後的圖片和卷積前的圖片尺寸不一致,這顯然不是我們想要的結果,所以爲了避免這種情況,需要先對原始圖片做邊界填充處理。在上面的情況中,我們需要先把原始圖像填充爲9*9的尺寸。
常用的區域填充方法包括:
圖是我在word裏面畫的,所以有很多回車鍵哈,有些簡陋,大家湊合看吧,意思還是對的,也是爲了畫圖方便,這裏就不用5*5的尺寸了,用3*3定義原始圖像的尺寸,補充爲9*9的尺寸,圖片上的顏色只爲方便觀看,並沒有任何其他含義。
原始圖像:
2.1.1補零
2.2.2邊界複製
2.2.3鏡像
2.2.4塊複製
以上四種邊界補充方法通過看名字和圖片就能理解了,不在多做解釋。
不同卷積核下卷積意義
我們經常能看到的,平滑,模糊,去燥,銳化,邊緣提取等等工作,其實都可以通過卷積操作來完成,下面我們一一舉例說明一下:
(1)一個沒有任何作用的卷積核:
將原像素中間像素值乘1,其餘全部乘0,顯然像素值不會發生任何變化。
(2)平滑均值濾波:
選擇卷積核:
該卷積核的作用在於取九個值的平均值代替中間像素值,所以起到的平滑的效果:
(3)高斯平滑:
卷積核:
高斯平滑水平和垂直方向呈現高斯分佈,更突出了中心點在像素平滑後的權重,相比於均值濾波而言,有着更好的平滑效果。
(4)圖像銳化:
卷積核:
該卷積利用的其實是圖像中的邊緣信息有着比周圍像素更高的對比度,而經過卷積之後進一步增強了這種對比度,從而使圖像顯得棱角分明、畫面清晰,起到銳化圖像的效果。
除了上述卷積核,邊緣銳化還可以選擇:
(5)梯度Prewitt:
水平梯度:
垂直梯度:
梯度Prewitt卷積核與Soble卷積核的選定是類似的,都是對水平邊緣或垂直邊緣有比較好的檢測效果。
(6)Soble邊緣檢測:
Soble與上述卷積核不同之處在於,Soble更強調了和邊緣相鄰的像素點對邊緣的影響。
水平梯度:
垂直梯度:
以上的水平邊緣與垂直邊緣檢測問題可以參考:Soble算子水平和垂直方向導數問題
(7)梯度Laplacian:
卷積核:
Laplacian也是一種銳化方法,同時也可以做邊緣檢測,而且邊緣檢測的應用中並不侷限於水平方向或垂直方向,這是Laplacian與soble的區別。下面這張圖可以很好的表徵出二者的區別:來源於OpenCV官方文檔
代碼實現
可以利用OpenCV提供的filter2D函數完成對圖像進行卷積操作,其函數接口爲:
- CV_EXPORTS_W void filter2D(
- InputArray src,
- OutputArray dst,
- int ddepth,
- InputArray kernel,
- Point anchor=Point(-1,-1),
- double delta=0,
- int borderType=BORDER_DEFAULT );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
第一個參數: 輸入圖像
第二個參數: 輸出圖像,和輸入圖像具有相同的尺寸和通道數量
第三個參數: 目標圖像深度,輸入值爲-1時,目標圖像和原圖像深度保持一致。
第四個參數: 卷積核,是一個矩陣
第五個參數:內核的基準點(anchor),其默認值爲(-1,-1)說明位於kernel的中心位置。基準點即kernel中與進行處理的像素點重合的點。
第六個參數: 在儲存目標圖像前可選的添加到像素的值,默認值爲0
第七個參數: 像素向外逼近的方法,默認值是BORDER_DEFAULT。
- #include <iostream>
- #include <iostream>
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- using namespace std;
- using namespace cv;
-
- int main()
- {
- Mat srcImage = imread("1.jpg");
- namedWindow("srcImage", WINDOW_AUTOSIZE);
- imshow("原圖", srcImage);
- Mat kernel = (Mat_<double>(3,3) <<
- -1, 0 ,1,
- -2, 0, 2,
- -1, 0, 1);
- Mat dstImage;
- filter2D(srcImage,dstImage,srcImage.depth(),kernel);
- namedWindow("dstImage",WINDOW_AUTOSIZE);
- imshow("卷積圖",dstImage);
- waitKey(0);
- return 0;
- }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
所以代碼的實現就非常簡單了,不同的卷積操作只需要改變卷積核kernel 即可。