#1,個人理解
網上查了很多資料,都說sobel算子是用來檢測邊緣的,分別給了兩個方向上的卷積核,然后說明做法,就說這就是sobel算子。對於我個人來說,還有很多不明白的地方,所以理清下思路。
#2,邊緣、邊界和sobel算子
這個可以自己去google或者百度找定義,邊緣和邊界不一樣,兩者沒有必然聯系也並非毫無聯系。因為現實世界的三維空間映射到圖像顯示的二維空間中會丟失很多信息,也會添進來一部分類似光照、場景等的干擾,所以並不能完全給邊緣和邊界的關系下一個定義。對圖像而言,我們一般是要找出它的邊緣,因為這是圖像處理中使用較多的一個特征。何為邊緣?圖像處理中認為,灰度值變化劇烈的地方就是邊緣。那么如何判斷灰度值變化?如何度量“劇烈”?sobel算子就對這些問題做了自己的規范,而且命名為sobel算子,就是對一副圖像的輸入到輸出邊緣信息的整個處理過程。
sobel算子的思想,Sobel算子認為,鄰域的像素對當前像素產生的影響不是等價的,所以距離不同的像素具有不同的權值,對算子結果產生的影響也不同。一般來說,距離越遠,產生的影響越小。
sobel算子的原理,對傳進來的圖像像素做卷積,卷積的實質是在求梯度值,或者說給了一個加權平均,其中權值就是所謂的卷積核;然后對生成的新像素灰度值做閾值運算,以此來確定邊緣信息。
#3,卷積核及計算方法
若Gx是對原圖x方向上的卷積,Gy是對原圖y方向上的卷積;
原圖中的作用點像素值通過卷積之后為:
可以簡化成:
比如,一下矩陣為原圖中的像素點矩陣,帶入上式中的A,最終得到的G或者|G|是下面(x,y)處的像素值,可以自己去搜索下卷積的含義來理解。
另外,卷積核也可以旋轉,用與查找不與x,y軸平行或垂直的方向上的邊緣。
#4,閾值處理及平滑處理
得到像素點新的像素值之后,給定一個閾值就可以得到sobel算子計算出的圖像邊緣了。
通常,為了消除噪聲對sobel算子的影響,會增加一個預處理的操作,主要是做平滑處理降低噪聲的影響。
#5,matlab代碼實現
Gx=[1.0 2.0 1.0;0.0 0.0 0.0;-1.0 -2.0 -1.0]; Gy=[-1.0 0.0 1.0;-2.0 0.0 2.0;-1.0 0.0 1.0]; img=imread('qiaoba.jpg'); image=rgb2gray(img); subplot(2,2,1); imshow(image); title('原圖'); gradx=conv2(Gx,image,'full'); gradx=abs(gradx); %計算圖像的sobel垂直梯度 subplot(2,2,2); imshow(gradx,[]); title('圖像的sobel垂直梯度'); grady=conv2(Gy,image,'full'); grady=abs(grady); %計算圖像的sobel水平梯度 subplot(2,2,3); imshow(grady,[]); title('圖像的sobel水平梯度'); grad=gradx+grady; %得到圖像的sobel梯度 subplot(2,2,4); imshow(grad,[]); title('圖像的sobel梯度');
處理結果:
#5,c++代碼實現
來源:http://blog.csdn.net/dcrmg/article/details/52280768
#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; }
#6,sobel算子的優缺點
優點:計算簡單,速度很快;
缺點:計算方向單一,對復雜紋理的情況顯得乏力;
直接用閾值來判斷邊緣點欠合理解釋,會造成較多的噪聲點誤判。