- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
cv::gapi::Sobel 函數是 OpenCV 的 G-API 模塊中用于執行 Sobel 算子操作的一個函數,主要用于圖像的邊緣檢測。Sobel 算子通過計算圖像強度的梯度來工作,它使用一個內核在水平方向(dx)和垂直方向(dy)上進行卷積運算。
使用擴展的 Sobel 算子計算一階、二階、三階或混合圖像導數。
除了一個特殊情況外,在所有情況下,都會使用 ksize×ksize 可分離核來計算導數。當 ksize = 1 時,使用 3×1 或 1×3 核(即,不進行高斯平滑)。ksize = 1 僅可用于計算一階或二階 x- 或 y- 導數。
還有一個特殊的值 ksize = FILTER_SCHARR (-1),對應于 3×3 Scharr 濾波器,它可能比 3×3 Sobel 濾波器提供更準確的結果。Scharr 孔徑為
[ ? 3 0 3 ? 10 0 10 ? 3 0 3 ] \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \end{bmatrix} ??3?10?3?000?3103? ?
用于 x 導數,或者轉置后用于 y 導數。
該函數通過將圖像與適當的核卷積來計算圖像導數:
dst = ? x o r d e r + y o r d e r src ? x x o r d e r ? y y o r d e r \texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}} dst=?xxorder?yyorder?xorder+yordersrc?
Sobel 算子結合了高斯平滑和微分,因此結果對噪聲具有某種程度的抵抗性。通常,該函數被調用為 ( xorder = 1, yorder = 0, ksize = 3) 或 ( xorder = 0, yorder = 1, ksize = 3),以計算一階 x 或 y 圖像導數。第一種情況對應于以下核:
Sobel x = [ ? 1 0 1 ? 2 0 2 ? 1 0 1 ] \text{Sobel}_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} Sobelx?= ??1?2?1?000?121? ?
第二種情況對應于以下核:
[ ? 1 ? 2 ? 1 0 0 0 1 2 1 ] \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} ??101??202??101? ?
函數原型
GMat cv::gapi::Sobel
(const GMat & src,int ddepth,int dx,int dy,int ksize = 3,double scale = 1,double delta = 0,int borderType = BORDER_DEFAULT,const Scalar & borderValue = Scalar(0)
)
注意:
如果硬件支持,則會進行向最近偶數的舍入;如果不支持,則舍入到最近。
函數文本ID是 “org.opencv.imgproc.filters.sobel”
參數
- 參數 src: 輸入圖像。
- 參數 ddepth: 輸出圖像深度,參見組合;對于8位輸入圖像,導數可能會被截斷。
- 參數 dx: x方向導數的階數。
- 參數 dy: y方向導數的階數。
- 參數 ksize: 擴展 Sobel 核的大小;必須為奇數。
- 參數 scale: 計算導數值的可選比例因子;默認情況下,不應用縮放(詳情參見 cv::getDerivKernels)。
- 參數 delta: 在存儲到 dst 前添加到結果中的可選增量值。
- 參數borderType: 像素外推方法,參見 cv::BorderTypes。
- 參數 borderValue: 在常量邊界類型的情況下的邊界值。
代碼示例
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/imgproc.hpp>
#include <opencv2/opencv.hpp>int main()
{// 讀取輸入圖像cv::Mat src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png", cv::IMREAD_GRAYSCALE );if ( src.empty() ){std::cerr << "無法讀取圖像" << std::endl;return -1;}// 定義G-API網絡cv::GMat in;auto sobelx = cv::gapi::Sobel( in, CV_16S, 1, 0 ); // X方向上的Sobel濾波auto sobely = cv::gapi::Sobel( in, CV_16S, 0, 1 ); // Y方向上的Sobel濾波cv::GComputation comp( cv::GIn( in ), cv::GOut( sobelx, sobely ) );// 應用到源圖像并獲取結果cv::Mat sobelX, sobelY;comp.apply( cv::gin( src ), cv::gout( sobelX, sobelY ) );// 將結果轉換為 CV_8U 并進行歸一化以便顯示cv::Mat sobelXAbs, sobelYAbs;cv::convertScaleAbs( sobelX, sobelXAbs ); // 轉換為 CV_8U 并取絕對值cv::convertScaleAbs( sobelY, sobelYAbs ); // 轉換為 CV_8U 并取絕對值// 可選:進一步歸一化以增強對比度(如果需要)double sobelXMin, sobelXMax;double sobelYMin, sobelYMax;cv::minMaxLoc( sobelXAbs, &sobelXMin, &sobelXMax );cv::minMaxLoc( sobelYAbs, &sobelYMin, &sobelYMax );cv::Mat sobelXNorm, sobelYNorm;sobelXAbs.convertTo( sobelXNorm, CV_8U, 255.0 / ( sobelXMax - sobelXMin ), -sobelXMin * 255.0 / ( sobelXMax - sobelXMin ) );sobelYAbs.convertTo( sobelYNorm, CV_8U, 255.0 / ( sobelYMax - sobelYMin ), -sobelYMin * 255.0 / ( sobelYMax - sobelYMin ) );// 顯示結果cv::imshow( "Original Image", src );cv::imshow( "Sobel X", sobelXNorm );cv::imshow( "Sobel Y", sobelYNorm );cv::waitKey( 0 );return 0;
}