1.Sobel算子
- 卷積的作用除了實現圖像模糊或者去噪,還可以尋找一張圖像上所有梯度信息,這些梯度信息是圖像的最原始特征數據,進一步處理之后就可以生成一些比較高級的特征用來表示一張圖像實現基於圖像特征的匹配,圖像分類等應用。
- Sobel算子是一種很經典的圖像梯度提取算子,其本質是基於圖像空間域卷積,背后的思想是圖像一階導數算子的理論支持。
- sobel算子主要用於獲得數字圖像的一階梯度,常見的應用和物理意義是邊緣檢測。(Laplacian邊緣檢測並不局限於水平方向或垂直方向,這是Laplacian與soble的區別)
2.Sobel算子的實現
Sobel本質是基於圖像空間域卷積,先來理解下卷積的基礎知識。
2.1卷積
- 待處理的數字圖像可以看做是一個大矩陣,圖像的每個像素對應着矩陣的每個元素,假設我們的圖像分辨率為1024x768,那么對應大矩陣的的行數則為1024,列數為768.
- 用於濾波(卷積核不止用於濾波)的小矩陣(也叫卷積核),一般是一個方陣,也就是行數和列數相同,比如常見的邊緣檢測Sobel算子為3x3的矩陣。
- 濾波就是對於大矩陣中的每個像素,計算它周圍和濾波器矩陣對應位置元素的乘積,最后把乘積結果相加到一起,最終得到的值就作為該像素的新值。這樣就對一個像素完成了一次濾波
卷積示意圖:
注:對圖像大矩陣和濾波小矩陣的對應位置元素進行相乘再求和的操作就叫做卷積。(Convolution)或協相關(Correlation).
協相關(Correlation)和卷積(Convolution)很類似, 兩者唯一的差別就是卷積在計算前需要翻轉卷積核, 協相關則不需要翻轉
2.2Sobel算子
該算子包含兩組3x3的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。其公式如下:

其中:
- I代表原始圖像,
- Gx及Gy分別代表經橫向及縱向邊緣檢測的圖像灰度值
- G表示圖像的每一個像素的橫向及縱向灰度值 有兩種計算方式
- Scharr,比Sobel算子的值更大,因此對於灰度變化更為敏感,會得到較強的邊緣強度,但是也會損失一些細節
3.實戰
3.1 api解釋
OpenCV實現了基於Sobel算子提取圖像梯度的API,表示與解釋如下
1 void Sobel( 2 InputArray src, 3 OutputArray dst, int ddepth, 4 int dx, 5 int dy, 6 int ksize = 3, 7 double scale = 1, double delta = 0, 8 int borderType = BORDER_DEFAULT ); 9 10 @param src 為輸入圖像,填Mat類型即可。 11 @param dst 即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。 12 @param ddepth 輸出圖像的深度。 13 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F 14 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F 15 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F 16 若src.depth() = CV_64F, 取ddepth = -1/CV_64F 17 @param dx x 方向上的差分階數。 18 @param dy y方向上的差分階數。 19 @param ksize 有默認值3,表示Sobel核的大小;必須取1,3,5或7。 20 @param scale 計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。 21 @param delta 表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。 22 @param borderType 邊界模式,默認值為BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息
3.2代碼
1 #include <opencv2/opencv.hpp> 2 #include <iostream> 3 4 using namespace cv; 5 using namespace std; 6 7 int main(int artc, char** argv) { 8 Mat src = imread("src_sobel.jpg"); 9 if (src.empty()) { 10 printf("could not load image...\n"); 11 return -1; 12 } 13 namedWindow("input", CV_WINDOW_AUTOSIZE); 14 imshow("input", src); 15 Mat grad_x, grad_y; 16 Mat dst; 17 Sobel(src, grad_x, CV_32F, 1, 0, 3, 1, 0, BORDER_DEFAULT); 18 Sobel(src, grad_y, CV_32F, 0, 1, 3, 1, 0, BORDER_DEFAULT); 19 20 convertScaleAbs(grad_x, grad_x); 21 convertScaleAbs(grad_y, grad_y); 22 23 add(grad_x, grad_y, dst, Mat(), CV_16S); 24 convertScaleAbs(dst, dst); 25 26 imshow("grad_x", grad_x); 27 imshow("grad_y", grad_y); 28 imshow("gradient", dst); 29 30 waitKey(0); 31 32 return 0; 33 }
原圖:
x方向sobel:檢測水平梯度邊緣,已經將豎直方向上的邊緣梯度剔除
y方向sobel:檢測豎直梯度邊緣,已經將水平方向上的邊緣梯度剔除
梯度綜合圖像(兩者像素相加即可得到合並后的圖像)
參考:
卷積及常用卷積核的類型:https://www.cnblogs.com/xiaojianliu/p/9075872.html
sobel:https://www.cnblogs.com/freeblues/p/5738987.html
https://blog.csdn.net/linqianbi/article/details/78673903
https://blog.csdn.net/qq_30460949/article/details/90046408
https://wx.zsxq.com/dweb2/index/group/551551828124?from=mweb&type=detail
