sobel 算子的基本概念
sobel 算子是一個主要用於邊緣檢測的離散微分算子,它結合了高斯平滑和微分求導,用於計算圖像灰度函數的近似梯度。
其基礎來自於一個事實,即在邊緣部分,像素值出現“跳躍”或者較大的變化。如果在此邊緣部分求取一階導數,會看到極值的出現。正如下圖所示:
sobel 算子的計算過程
(1)分別在 x 和 y 兩個方向求導
x 方向求導:將源圖像與 Gx 進行卷積。對豎線敏感(導數大),橫線不敏感(導數小)。
y 方向求導:將源圖像與 Gy 進行卷積。對豎線不敏感(導數小),橫線敏感(導數大)。
(2)對於圖像的每一點,結合以上兩個結果求出近似梯度
可以簡化成:
Sobel 函數
void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT);
- src,輸入圖像,填 Mat 類型即可。
- dst,輸出圖像,需要和源圖像有一樣的尺寸和類型。
- ddepth,輸出圖像的深度,滿足下列要求:
src.depth() = CV_8U, ddepth = -1 / CV_16S / CV_32F / CV_64F
src.depth() = CV_16U / CV_16S, ddepth = -1 / CV_32F / CV_64F
src.depth() = CV_32F, ddepth = -1 / CV_32F / CV_64F
src.depth() = CV_64F, ddepth = -1 / CV_64F
- dx,x 方向上導數的階數,只能是 0、1、2。若求 x 方向上的一階導數,dx = 1,dy = 0。
- dy,y 方向上導數的階數,只能是 0、1、2。若求 y 方向上的一階導數,dx = 0,dy = 1。
- ksize,默認值為 3,表示 sobel 核的大小,必須取 1、3、5、7。
- scale,計算導數值的縮放因子,默認值為 1,表示默認情況下不進行縮放。
- delta,輸出梯度 = scale * G + delta。
- borderType,Gx 和 Gy 都有一定大小,邊緣會處理不到,需要進行邊緣擴展。這個參數指定邊緣擴充類型。
一般情況下,都是使用 ksize×ksize 內核來計算導數的,然而,當 ksize = 1 時,會使用 3×1、1×3 的內核。這種情況下,並沒有進行高斯平滑操作。
代碼示例:
#include<opencv.hpp>
using namespace cv; int main() { Mat src = imread("C:/Users/齊明洋/Desktop/證件照/7.jpg"); GaussianBlur(src, src, Size(3, 3), 0, 0); imshow("src", src); Mat gray, x_img, y_img, sobel_img; cvtColor(src, gray, COLOR_BGR2GRAY); Sobel(gray, x_img, -1, 1, 0, 3); imshow("x_img", x_img); Sobel(gray, y_img, -1, 0, 1, 3); imshow("y_img", y_img); addWeighted(x_img, 1, y_img, 1, 0, sobel_img);
//https://www.cnblogs.com/bjxqmy/p/11986135.html imshow("sobel_img", sobel_img); waitKey(0); }
效果演示:
補充說明:當內核大小為 3×3 時,sobel 內核可能產生比較明顯的誤差,畢竟 sobel 算子只是求取了導數的近似值而已。為解決這一問題,OpenCV 提供了 Scharr 函數,但該函數僅作用於 3×3 的內核。該函數的運算與 Sobel 函數一樣快,但結果更精確,其內核為
借鑒博客:https://www.cnblogs.com/wxl845235800/p/7700887.html
https://www.cnblogs.com/sevenyuan/p/7874344.html