Sobel邊緣檢測演算法及OpenCV函式實現
轉自https://www.cnblogs.com/herenzhiming/articles/6526741.html https://blog.csdn.net/qaz_wz/article/details/79052246
- 演算法原理
索貝爾運算元(Sobel operator)主要用作邊緣檢測,在技術上,它是一離散性差分運算元,用來運算影象亮度函式的灰度之近似值。在影象的任何一點使用此運算元,將會產生對應的灰度向量或是其法向量
Sobel卷積因子為:
該運算元包含兩組3x3的矩陣,分別為橫向及縱向,將之與影象作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以A代表原始影象,Gx及Gy分別代表經橫向及縱向邊緣檢測的影象灰度值,其公式如下:
具體計算如下:
Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1)
+(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y)
+(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1)
= [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)]
Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1)
+0*f(x-1,y) 0*f(x,y) + 0*f(x+1,y)
+(-1)*f(x-1,y+1) + (-2)*f(x,y+1) + (-1)*f(x+1, y+1)
= [f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]
其中f(a,b), 表示影象(a,b)點的灰度值;
影象的每一個畫素的橫向及縱向灰度值通過以下公式結合,來計算該點灰度的大小:
通常,為了提高效率 使用不開平方的近似值:
如果梯度G大於某一閥值則認為該點(x,y)為邊緣點。
然後可用以下公式計算梯度方向:
Sobel運算元根據畫素點上下、左右鄰點灰度加權差,在邊緣處達到極值這一現象檢測邊緣。對噪聲具有平滑作用,提供較為精確的邊緣方向資訊,邊緣定位精度不夠高。當對精度要求不是很高時,是一種較為常用的邊緣檢測方法。
附帶知識:
普利維特運算元(Prewitt operate):
除sobel邊緣檢測外 還有Prewitt運算元, 它的卷積因子如下:
其他計算 和sobel差不多;
Prewitt運算元利用畫素點上下、左右鄰點灰度差,在邊緣處達到極值檢測邊緣。對噪聲具有平滑作用,定位精度不夠高。
羅伯茨交叉邊緣檢測(Roberts Cross operator)
卷積因子如下:
灰度公式為:
近似公式為:
具體計算如下:
G(x,y)=abs(f(x,y)-f(x+1,y+1))+abs(f(x,y+1)-f(x+1,y))
灰度方向 計算公式為:
Roberts運算元採用對角線方向相鄰兩畫素之差近似梯度幅值檢測邊緣。檢測水平和垂直邊緣的效果好於斜向邊緣,定位精度高,對噪聲敏感
其他邊緣檢測技術:
參考文章:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/featops.htm
http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm
- OpenCV實現
Sobel函式使用擴充套件的 Sobel 運算元,來計算一階、二階、三階或混合影象差分。
void Sobel (
InputArray src,//輸入圖
OutputArray dst,//輸出圖
int ddepth,//輸出影象的深度
int dx,
int dy,
int ksize=3,
double scale=1,
double delta=0,
int borderType=BORDER_DEFAULT );
列表內容
第一個引數,InputArray 型別的src,為輸入影象,填Mat型別即可。
第二個引數,OutputArray型別的dst,即目標影象,函式的輸出引數,需要和源圖片有一樣的尺寸和型別。
第三個引數,int型別的ddepth,輸出影象的深度,支援如下src.depth()和ddepth的組合:
若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_64F, 取ddepth = -1/CV_64F
第四個引數,int型別dx,x 方向上的差分階數。
第五個引數,int型別dy,y方向上的差分階數。
第六個引數,int型別ksize,有預設值3,表示Sobel核的大小;必須取1,3,5或7。
第七個引數,double型別的scale,計算導數值時可選的縮放因子,預設值是1,表示預設情況下是沒有應用縮放的。我們可以在文件中查閱getDerivKernels的相關介紹,來得到這個引數的更多資訊。
第八個引數,double型別的delta,表示在結果存入目標圖(第二個引數dst)之前可選的delta值,有預設值0。
第九個引數, int型別的borderType,我們的老朋友了(萬年是最後一個引數),邊界模式,預設值為BORDER_DEFAULT。這個引數可以在官方文件中borderInterpolate處得到更詳細的資訊。
呼叫Sobel函式
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
const char* path = "C:/Users/Administrator/Desktop/opencv/1.jpg";
const char* load_win = "load image";
const char* gray_win = "gray imgae";
int main(int argc, char** argv)
{
Mat src, dst;
src = imread(path);
if (src.empty())
{
cout << "could not load..." << endl;
return -1;
}
imshow(load_win, src);
GaussianBlur(src, dst, Size(3, 3), 0, 0);
Mat src_gray;
cvtColor(dst, src_gray, CV_BGR2GRAY);
imshow(gray_win, src_gray);
Mat x_grad, y_grad;
Sobel(src_gray, x_grad, CV_16S, 1, 0, 3);
Sobel(src_gray, y_grad, CV_16S, 0, 1, 3);
convertScaleAbs(x_grad, x_grad);
convertScaleAbs(y_grad, y_grad);
imshow("x_grad", x_grad);
imshow("y_grad", y_grad);
waitKey(0);
return 0;
}