邊緣檢測詳解:Sobel、Scharr、Laplacian、Canny
邊緣檢測是圖像處理和計算機視覺中的重要步驟,主要用于發現圖像中亮度變化劇烈的區域,即物體的輪廓、邊界或紋理特征。OpenCV 提供了多種常用的邊緣檢測算子,本教程將通過四種方法帶大家詳細學習:Sobel、Scharr、Laplacian、Canny。
圖片準備:
可直接使用下圖,也可自備圖片
以下所有處理后的結果:
一、Sobel 算子
1. 原理
Sobel 算子本質上是 一階導數算子,通過對圖像在 x方向和y方向 上分別求導,檢測像素灰度變化最明顯的部分。
dx=1, dy=0:只檢測水平方向(垂直邊緣)。
dx=0, dy=1:只檢測垂直方向(水平邊緣)。
將兩者結合,可以得到完整的邊緣信息。
2. 函數原型
cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
參數說明:
src:輸入圖像,可以是灰度圖或彩色圖。
ddepth:輸出圖像的深度,常用
cv2.CV_64F
保存負數梯度信息。dx, dy:求導方向,dx=1 表示對x方向求導,dy=1 表示對y方向求導。
ksize:卷積核大小,常用3或5,必須為奇數。
參數 | 說明 |
---|---|
src | 輸入圖像,可以是灰度圖或彩色圖。 |
ddepth | 輸出圖像的深度(如 cv2.CV_64F 保留負值,-1 表示與原圖一致)。 |
dx | x方向導數階數(1 表示對x方向求導)。 |
dy | y方向導數階數(1 表示對y方向求導)。 |
ksize | 卷積核大小(必須為奇數,常用 3、5、7)。 |
scale | 縮放因子,默認 1。 |
delta | 偏移量,默認 0。 |
borderType | 邊界模式,默認 cv2.BORDER_DEFAULT 。 |
3. 示例代碼
import cv2
img = cv2.imread('violet.jpg', flags=0)#不用灰度試試效果
img = cv2.resize(img,(800,500))
cv2.imshow('img',img)
cv2.waitKey(0)img_x_64 = cv2.Sobel(img,cv2.CV_64F,dx=1,dy=0)#默認int8改為float64,可保存負數
img_x_full = cv2.convertScaleAbs(img_x_64)#轉換為絕對值,負數轉換為正數
img_y_64 = cv2.Sobel(img,cv2.CV_64F,dx=0,dy=1)#默認int8改為float64,可保存負數
img_y_full = cv2.convertScaleAbs(img_y_64)#轉換為絕對值,負數轉換為正數
img_xy_sobel_full = cv2.addWeighted(img_x_full, 1, img_y_full, 1, 0)
cv2.imshow('img_xy_sobel_full',img_xy_sobel_full)
cv2.waitKey(0)
4. 特點
簡單高效,適合大多數情況。
容易受噪聲影響。
二、Scharr 算子
1. 原理
Scharr 算子是 Sobel 算子的改進版本,當卷積核大小為 3 時,它在近似旋轉對稱性方面更優,因此檢測效果更清晰、平滑。
2. 函數原型
cv2.Scharr(src, ddepth, dx, dy)
相比 Sobel,參數更少,專門優化了 3×3 核的情況。
參數 | 說明 |
---|---|
src | 輸入圖像。 |
ddepth | 輸出圖像深度(如 cv2.CV_64F )。 |
dx | x方向導數階數(只能取1)。 |
dy | y方向導數階數(只能取1)。 |
scale | 縮放因子,默認 1。 |
delta | 偏移量,默認 0。 |
borderType | 邊界模式,默認 cv2.BORDER_DEFAULT 。 |
3. 示例代碼
img_x_64 = cv2.Scharr(img,cv2.CV_64F,dx=1,dy=0)#默認int8改為float64,可保存負數
img_x_full = cv2.convertScaleAbs(img_x_64)#轉換為絕對值,負數轉換為正數
img_y_64 = cv2.Scharr(img,cv2.CV_64F,dx=0,dy=1)#默認int8改為float64,可保存負數
img_y_full = cv2.convertScaleAbs(img_y_64)#轉換為絕對值,負數轉換為正數
img_xy_Scharr_full = cv2.addWeighted(img_x_full, 1, img_y_full, 1, 0)
cv2.imshow('img_xy_Scharr_full',img_xy_Scharr_full)
cv2.waitKey(0)
4. 特點
對細節和紋理捕捉更好。
運算速度和 Sobel 接近,但效果更佳。
三、Laplacian 算子
1. 原理
Laplacian 算子是 二階導數算子,通過檢測像素灰度的二階變化,直接找出邊緣。
與 Sobel、Scharr 不同,它不分方向,而是直接整體檢測。
2. 函數原型
cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
參數說明:
src:輸入圖像。
ddepth:輸出圖像深度。
ksize:卷積核大小(一般取1、3、5)。
參數 | 說明 |
---|---|
src | 輸入圖像。 |
ddepth | 輸出圖像深度(如 cv2.CV_64F )。 |
dst | 輸出圖像(可選,通常不寫)。 |
ksize | 卷積核大小,必須為正奇數(常用 1、3、5)。 |
scale | 縮放因子,默認 1。 |
delta | 偏移量,默認 0。 |
borderType | 邊界模式,默認 cv2.BORDER_DEFAULT 。 |
3. 示例代碼
img_lap = cv2.Laplacian(img,cv2.CV_64F)
img_lap_full = cv2.convertScaleAbs(img_lap)#轉換為絕對值,負數轉換為正數
cv2.imshow('img_lap_full',img_lap_full)
cv2.waitKey(0)
4. 特點
可以快速檢測邊緣,但更容易受噪聲干擾。
常與高斯濾波結合使用(Laplacian of Gaussian, LoG)
四、Canny 算子
1. 原理
Canny 是經典的 多階段邊緣檢測算法,相比前面三種更穩定、抗噪能力更強。其步驟包括:
高斯濾波去噪。
計算梯度強度與方向。
非極大值抑制(只保留局部最大邊緣)。
雙閾值檢測(區分強邊緣與弱邊緣,并進行連接)。
2. 函數原型
cv2.Canny(image, threshold1, threshold2[, apertureSize[, L2gradient]])
參數說明:
image:輸入圖像,最好是灰度圖。
threshold1:低閾值。
threshold2:高閾值。
apertureSize:Sobel 算子的核大小(默認3)。
參數 | 說明 |
---|---|
image | 輸入圖像(必須是單通道灰度圖)。 |
threshold1 | 低閾值,用于邊緣連接。 |
threshold2 | 高閾值,用于確定強邊緣。 |
apertureSize | Sobel 算子的卷積核大小(默認 3,可取 3、5、7)。 |
L2gradient | 計算梯度幅值的方法,默認為 False (使用 L1 范數),若為 True 使用 L2 范數,邊緣更精確但計算量更大。 |
3. 示例代碼
img_canny = cv2.Canny(img, threshold1=150, threshold2=230)#低,高
cv2.imshow('img_canny',img_canny)
cv2.waitKey(0)
4. 特點
效果最優,邊緣清晰完整。
閾值選擇影響很大。
五、效果對比總結
算子 | 類型 | 是否分方向 | 抗噪性 | 特點 |
---|---|---|---|---|
Sobel | 一階導數 | 是 | 一般 | 快速,適合簡單邊緣檢測 |
Scharr | 一階導數 | 是 | 較好 | Sobel改進,細節更清晰 |
Laplacian | 二階導數 | 否 | 差 | 對噪聲敏感,常與濾波結合 |
Canny | 多階段檢測 | 否 | 強 | 最優,邊緣清晰完整 |
六、實踐建議
快速檢測:用 Sobel 或 Scharr。
細節要求高:優先 Scharr。
檢測輪廓:Laplacian + 高斯濾波。
穩定性優先:Canny。
這樣,一張圖像可以通過這四種算子分別得到不同風格的邊緣信息,從而應用在 目標檢測、圖像分割、OCR、醫學影像分析 等場景中。