Sobel算子:[-1 0 1函數
-2 0 2測試
-1 0 1]spa
用此算子與原圖像作卷積,能夠檢測出垂直方向的邊緣。算子做用在圖像的第二列,結果是:200,200,200;做用在第三列,結果是:3d
200,200,200;code
對當前列左右兩側的元素進行差分,因爲邊緣的值明顯小於(或大於)周邊像素,因此邊緣的差分結果會明顯不一樣,這樣就提取出了垂直邊緣。同理,把上面那個矩陣轉置一下,就是提取水平邊緣。這種差分操做就稱爲圖像的梯度計算。orm
概念: 把圖片想象成連續函數,由於邊緣部分的像素值是與旁邊像素明顯有區別的,因此對圖片局部求極值,就能夠獲得整幅圖片的邊緣信息了。不過圖片是二維的離散函數,導數就變成了差分,這個差分就稱爲圖像的梯度。對象
理解:求一階差分應該是指對圖像相鄰像素求取差分。blog
邊緣 – 是像素值發生躍遷的地方(變化率最大處,導數最大處),是圖像的顯著特徵之一,在圖像特徵提取、對象檢測、模式識別等方面都有重要的做用。圖片
Sobel算子和Scharr算子it
(1)Sobel算子:是離散微分算子(discrete differentiation operator),用來計算圖像灰度的近似梯度,梯度越大越有多是邊緣。
Soble算子的功能集合了高斯平滑和微分求導,又被稱爲一階微分算子,求導算子,在水平和垂直兩個方向上求導,獲得的是圖像在X方法與Y方向梯度圖像。
缺點:比較敏感,容易受影響,要經過高斯模糊(平滑)來降噪。
算子是經過權重不一樣來擴大差別。
梯度計算:(在兩個方向求導,假設被做用圖像爲 I)
水平變化: 將 I 與一個奇數大小的內核 Gx進行卷積。好比,當內核大小爲3時, Gx的計算結果爲:
垂直變化: 將 I 與一個奇數大小的內核 Gy進行卷積。好比,當內核大小爲3時, Gy的計算結果爲:
在圖像的每一像素上,結合以上兩個結果求出近似梯度:
有時也用下面更簡單公式代替,計算速度快:(最終圖像梯度)。
(2)Scharr:當內核大小爲3時, 以上Sobel內核可能產生比較明顯的偏差(畢竟,Sobel算子只是求取了導數的近似值)。 爲解決這一問題,OpenCV提供了 Scharr 函數,但該函數僅做用於大小爲3的內核。該函數的運算與Sobel函數同樣快,但結果卻更加精確,不怕干擾,其內核爲:
(3)Sobel/Scharr提取邊緣(求導)步驟:
1)高斯模糊平滑降噪:
GaussianBlur( src, dst, Size(3,3), 0, 0, BORDER_DEFAULT );
2)轉灰度:
cvtColor( src, gray, COLOR_RGB2GRAY );
3)求X和Y方向的梯度(求導):
Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
Scharr(gray_src, xgrad, CV_16S, 1, 0);
Scharr(gray_src, ygrad, CV_16S, 0, 1);
4)像素取絕對值:
convertScaleAbs(A, B); //計算圖像A的像素絕對值,輸出到圖像B
5)相加X和Y,獲得綜合梯度,稱爲振幅圖像:
addWeighted( A, 0.5,B, 0.5, 0, AB); //混合權重相加,效果較差
或者循環獲取像素,每一個點直接相加,效果更好。
來源:https://zhuanlan.zhihu.com/p/50966625
Sobel算子根據像素點上下、左右鄰點灰度加權差,在邊緣處達到極值這一現象檢測邊緣。對噪聲具備平滑做用,提供較爲精確的邊緣方向信息,邊緣定位精度不夠高。當對精度要求不是很高時,是一種較爲經常使用的邊緣檢測方法。
Sobel算子是典型的基於一階導數的邊緣檢測算子,因爲該算子中引入了相似局部加權平均的運算,所以對噪聲具備平滑做用,能很好的消除噪聲的影響。Sobel算子對於象素的位置的影響作了加權。
Sobel算子包含兩組3x3的矩陣,分別爲橫向及縱向模板,將之與圖像做平面卷積,便可分別得出橫向及縱向的亮度差分近似值。
Sobel算子是典型的基於一階導數的邊緣檢測算子,是離散型的差分算子。該算子對噪聲具備平滑做用,能很好的消除噪聲的影響。Sobel算子對於像素的位置的影響作了加權,與Prewitt算子、Roberts算子相比所以效果更好。
Sobel算子包含兩組3x3的矩陣,分別爲橫向及縱向模板,將之與圖像做平面卷積,便可分別得出橫向及縱向的亮度差分近似值。
import cv2 import numpy as np img = cv2.imread("fengjing.jpg", 0) x = cv2.Sobel(img,cv2.CV_16S,1,0) #1,0表明只計算x方向計算邊緣 y = cv2.Sobel(img,cv2.CV_16S,0,1) #0,1表明只在y方向計算邊緣 absX = cv2.convertScaleAbs(x) absY = cv2.convertScaleAbs(y) dst = cv2.addWeighted(absX,0.5,absY,0.5,0) cv2.imshow("absX", absX) cv2.imshow("absY", absY) cv2.imshow("Result", dst) cv2.waitKey(0) cv2.destroyAllWindows()
測試圖片:
運行結果: