文章來源:https://blog.csdn.net/on2way/article/details/46851451
梯度簡單來說就是求導,在圖像上表現出來的就是提取圖像的邊緣(不管是橫向的、縱向的、斜方向的等等),所需要的無非也是一個核模板,模板的不同結果也不同。所以可以看到,所有的這些個算子函數,歸結到底都可以用函數cv2.filter2D()來表示,不同的方法給予不同的核模板,然后演化為不同的算子而已。並且這只是這類濾波函數的一個用途,曾經寫過一個關於matlab下濾波函數imfilter()的擴展應用(等同於opencv的cv2.filter2D函數):
就是很多復雜的計算都是可以通過這個濾波函數組合實現,這樣的話速度快。
(一)關於Sobel算子與Scharr算子
Sobel算子是高斯平滑與微分操作的結合體,所以其抗噪能力很強,用途較多。一般的sobel算子包括x與y兩個方向,算子模板為:
在opencv函數中,還可以設置卷積核(ksize)的大小,如果ksize=-1,就演變為3*3的Scharr算子,模板無非變了個數字:
貼一個相關詳細參考:
(二)關於拉普拉斯(Laplacian)算子
拉普拉斯算子可以實現圖像的二階倒數的定義,至於二階倒數有什么意義,可以看這位博主的詳細介紹:
OpenCV-Python教程(7、Laplacian算子)
其核模板為:
下面是對上述三種模板的實例:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('flower.jpg',0)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)#默認ksize=3
sobely = cv2.Sobel(img,cv2.CV_64F,0,1)
sobelxy = cv2.Sobel(img,cv2.CV_64F,1,1)
laplacian = cv2.Laplacian(img,cv2.CV_64F)#默認ksize=3
#人工生成一個高斯核,去和函數生成的比較
kernel = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]],np.float32)#
img1 = np.float64(img)#轉化為浮點型的
img_filter = cv2.filter2D(img1,-1,kernel)
sobelxy1 = cv2.Sobel(img1,-1,1,1)
plt.subplot(221),plt.imshow(sobelx,'gray')
plt.subplot(222),plt.imshow(sobely,'gray')
plt.subplot(223),plt.imshow(sobelxy,'gray')
plt.subplot(224),plt.imshow(laplacian,'gray')
plt.figure()
plt.imshow(img_filter,'gray')
上述一個很重要的問題需要明白的就是,在濾波函數第二個參數,當我們使用-1表示輸出圖像與輸入圖像的數據類型一致時,如果原始圖像是uint8型的,那么在經過算子計算以后,得到的圖像可能會有負值,如果與原圖像數據類型一致,那么負值就會被截斷變成0或者255,使得結果錯誤,那么針對這種問題有兩種方式改變(上述程序中都有):一種就是改變輸出圖像的數據類型(第二個參數cv2.CV_64F),另一種就是改變原始圖像的數據類型(此時第二個參數可以為-1,與原始圖像一致)。
上述程序從結果上也說明使用函數cv2.filter2D也能達到相同的效果。
(三)Canny邊緣檢測算子
關於canny邊緣檢測算子,細究的話還算比較的復雜,給出一個介紹比較詳細的博客吧:
那么opencv中的函數也非常簡單,直接cv2.Canny(),這個函數需要五個參數,原始圖像,兩個范圍控制值minVal和maxVal(見上述原理介紹),第四個參數用於規定核模板的大小(默認3),最后一個是true與false(默認)的選擇,有一點不同,不太重要,可以試着那個好用那個。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('flower.jpg',0)
edges = cv2.Canny(img,100,200)#其他的默認
plt.subplot(121),plt.imshow(img,'gray')
plt.subplot(122),plt.imshow(edges,'gray')

