一、 高斯濾波
????????邊緣檢測本身屬于銳化操作,對噪點比較敏感,所以需要進行平滑處理。這里使用的是一個5*5的高斯 核對圖像進行消除噪聲。
二、計算圖像的梯度和方向
三、非極大值抑制
? ? ? ? 在得到每個邊緣的方向之后,其實把它們連起來邊緣檢測就算完了,經過第二步得到的邊緣不經過處理是沒辦法使用的,因為高斯濾波的原因,邊緣會變得模糊,導 致經過第二步后得到的邊緣像素點非常多,因此我們需要對其進行一些過濾操作,而非極大值抑制就是 一個很好的方法,它會對得到的邊緣像素進行一個排除,使邊緣盡可能細一點。
????????在該步驟中,我們需要檢查每個像素點的梯度方向上的相鄰像素,并保留梯度值最大的像素,將其他像 素抑制為零。假設當前像素點為(x,y),其梯度方向是0°,梯度值為G(x,y),那么我們就需要比 較G(x,y)與兩個相鄰像素的梯度值:G(x-1,y)和G(x+1,y)。如果G(x,y)是三個值里面最 大的,就保留該像素值,否則將其抑制為零。
????????并且如果梯度方向不是0°、45°、90°、135°這種特定角度,那么就要用到插值算法來計算當前像素點在 其方向上進行插值的結果了,然后進行比較并判斷是否保留該像素點。這里使用的是單線性插值,通過 A1和A2兩個像素點獲得dTmp1與dTmp2處的插值,然后與中心點C進行比較。具體的插值算法請參考圖 像旋轉實驗。
四、 雙閾值篩選
????????經過非極大值抑制之后,我們還需要設置閾值來進行篩選,當閾值設的太低,就會出現假邊緣,而閾值 設的太高,一些較弱的邊緣就會被丟掉,因此使用了雙閾值來進行篩選,推薦高低閾值的比例為2:1到 3:1之間
????????當某一像素位置的幅值超過最高閾值時,該像素必是邊緣像素;當幅值低于最低像素時,該像素必不是 邊緣像素;幅值處于最高像素與最低像素之間時,如果它能連接到一個高于閾值的邊緣時,則被認為是 邊緣像素,否則就不會被認為是邊緣。
????????也就是說,上圖中的A和C是邊緣,B不是邊緣。因為C雖然不超過 最高閾值,但其與A相連,所以C就是邊緣。
????????具體來說,對于非極大值抑制之后的圖像來說,設置兩個閾值threshold1和threshold2,其中 threshold1是低閾值,threshold2是高閾值。然后遍歷圖像,把梯度值小于低閾值的點的梯度值設為 0,得到圖像1,把梯度值小于高閾值的點的梯度值設為0,得到圖像2。由于圖像2的閾值比較高,所以 其中會損失掉很多有用的圖像信息,而圖像1的閾值比較低,所以會保留很多的信息,包括真正的邊緣和虛假的邊緣。
????????那么我們就可以以圖像2為基礎,以圖像1為補充來連接圖像的邊緣,其具體步驟為:
?????????對圖像2進行遍歷,當遇到一個非零的像素點P時,記錄以P為開始的輪廓線,知道輪廓線的終點位 置Q。
?????????考察圖像1中與圖像2中的Q點位置對應的點S的8鄰近區域,如果在S點的8鄰近區域內有非零像素存 在,就將其作為邊界點放入圖像2中作為點R。然后再從點R開始重復第一步,直到在圖像1和圖像2 中都無法繼續為止。
?????????當完成對包含點P的輪廓線的尋找之后,將這條輪廓線標為已尋找,然后接著尋找下一條輪廓,就 是重復第1步、第2步、第3步,直到圖像2中找不到新的輪廓為止。
????????經過篩選之后的所保存下來的點就是我們圖像中的邊緣點了
五、圖像邊緣檢測?
5.1、有二值化
導入模塊
import cv2
輸入圖像
img=cv2.imread('lenda01.png')
灰度化
img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
二值化
ret1,img_threshold1=cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY)
高斯濾波
img_Guss1=cv2.GaussianBlur(img_threshold1,(5,5),sigmaX=1.5)
梯度與方向
非極大值抑制
雙閾值篩選
img_Canny1=cv2.Canny(img_Guss1,122,127,L2gradient=True)
輸出圖像
cv2.imshow('img',img)
cv2.imshow('img_Canny1',img_Canny1)
cv2.waitKey(0)
完整代碼?
import cv2 img = cv2.imread('lenda01.png') # 將圖像從BGR顏色空間轉換為灰度圖像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 使用全局閾值進行二值化處理
# - ret1: 計算得到的閾值 (127)
# - img_threshold1: 二值化后的圖像,像素值大于127設置為255,否則設置為0
ret1, img_threshold1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) # 使用 Otsu's 閾值法進行二值化處理,并進行反轉
# - ret2: Otsu's算法計算得到的閾值
# - img_threshold2: 二值化后的圖像,像素值小于閾值設置為255,否則設置為0
ret2, img_threshold2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV) # 對二值化后的圖像進行高斯模糊處理,以減少噪聲
# - img_threshold1: 輸入圖像(二值化后的圖像)
# - (5, 5): 高斯核的大小
# - sigmaX=1.5: X方向上的高斯核標準差
img_Guss1 = cv2.GaussianBlur(img_threshold1, (5, 5), sigmaX=1.5) # 使用 Canny 邊緣檢測算法提取圖像的邊緣
# - img_Guss1: 輸入圖像(高斯模糊后的二值化圖像)
# - ret2: 低閾值,用于邊緣檢測的閾值下限 (這里使用Otsu算法計算得到的閾值)
# - ret1: 高閾值,用于邊緣檢測的閾值上限 (這里使用固定閾值127)
# - L2gradient=True: 使用 L2 范數計算圖像梯度,更準確
img_Canny1 = cv2.Canny(img_Guss1, ret2, ret1, L2gradient=True) # 顯示原始圖像
cv2.imshow('img', img)
# 顯示 Canny 邊緣檢測后的圖像
cv2.imshow('img_Canny1', img_Canny1)
# 等待用戶按下鍵盤上的任意鍵
cv2.waitKey(0)
5.2、無二值化?
import cv2img = cv2.imread('lenda01.png')# 將圖像從BGR顏色空間轉換為灰度圖像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 使用全局閾值進行二值化處理
# - ret1: 計算得到的閾值 (127)
# - img_threshold1: 二值化后的圖像,像素值大于127設置為255,否則設置為0
ret1, img_threshold1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)# 使用 Otsu's 閾值法進行二值化處理,并進行反轉
# - ret2: Otsu's算法計算得到的閾值
# - img_threshold2: 二值化后的圖像,像素值小于閾值設置為255,否則設置為0
ret2, img_threshold2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)# 對灰度圖像進行高斯模糊處理,以減少噪聲
# - (5, 5): 高斯核的大小
# - sigmaX=1.5: X方向上的高斯核標準差
img_Guss2 = cv2.GaussianBlur(img_gray, (5, 5), sigmaX=1.5)# 使用 Canny 邊緣檢測算法提取圖像的邊緣
# - img_Guss2: 輸入圖像(高斯模糊后的灰度圖像)
# - ret2: 低閾值,用于邊緣檢測的閾值下限
# - ret1: 高閾值,用于邊緣檢測的閾值上限
# - L2gradient=True: 使用 L2 范數計算圖像梯度,更準確
img_Canny2 = cv2.Canny(img_Guss2, ret2, ret1, L2gradient=True)# 顯示原始圖像
cv2.imshow('img', img)
# 顯示 Canny 邊緣檢測后的圖像
cv2.imshow('img_Canny2', img_Canny2)
# 等待用戶按下鍵盤上的任意鍵
cv2.waitKey(0)
```
六、庫函數
Canny()
使用 Canny 算法查找圖像中的邊緣
該函數在輸入圖像中查找邊緣,并使用 Canny 算法在輸出映射邊緣中標記它們。threshold1 和 threshold2 之間的最小值用于 Edge 鏈接。最大值用于查找強邊緣的初始分段。查看?http://en.wikipedia.org/wiki/Canny_edge_detector
cv.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] ) -> edges
cv.Canny( dx, dy, threshold1, threshold2[, edges[, L2gradient]] ) -> edges
方法 | 描述 |
---|---|
image | 8 位輸入圖像。 |
edges | 輸出邊緣映射;單通道 8 位圖像,其大小與 圖像 相同。 |
threshold1 | 磁滯過程的第一個閾值。 |
threshold2 | 滯后程序的第二個閾值。 |
apertureSize | 孔徑大小。 |
L2gradient | ![]() |
dx | 輸入圖像的 16 位 x 導數(CV_16SC1 或 CV_16SC3) |
dy | 輸入圖像的 16 位 y 導數(與 dx 類型相同)。 |