OpenCV-C++ Sobel算子使用


Sobel算子

Sobel算子主要用於邊緣檢測;

  • 邊緣:是像素值發生躍遷的地方,是圖像的顯著特征之一,在圖像特征提取, 對象檢測, 模式識別等方面都有重要的作用;
  • 如何提取邊緣,對圖像求它的一階導數;delta = f(x) - f(x-1), delta越大,說明在x方向變化越大;

sobel算子:

  • 是離散微分算子,用來計算圖像灰度的近似梯度
  • sobel算子功能集合高斯平滑和微分求導;
  • 又被稱為一階微分算子,求導算子,在水平和垂直兩個方向上求導,得到圖像x方法與y方向梯度圖像;

那么最終的圖像梯度:

\[G = \sqrt{G_x^2+G_y^2} \]

可以近似為:

\[G = |G_x| + |G_y| \]

改進的版本Scharr算子:

當內核大小為3時,以上Sobel可能產生比較明顯的誤差(畢竟,Sobel算子只是求取了導數的近似值),為了解決這一問題,OpenCV提供了Scharr函數,但該函數僅作用域大小為3的內核;計算速度與Sobel函數一樣快,但結果更加精確,不怕干擾,其內核為:

圖像邊緣提取

使用Sobel算子提取圖像邊緣,包含以下四個步驟:

  1. 對圖像進行高斯模糊;
  2. 將圖像轉換到灰度空間;
  3. 利用Sobel算子或者Scharr算子計算圖像梯度;
  4. 利用提取的梯度,調整圖像灰度值,提取圖像邊緣;

Sobel算子API的使用方式:

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表示輸入的灰度圖像
  • dst表示輸出的梯度;
  • ddepth表示輸出梯度的數據類型,必須大於輸入的圖像數據類型,關系如下圖所示:

  • dx=1, dy=0表示對x方向計算梯度;
  • dx=0, dy=1表示對y方向計算梯度;

Scharr算子的使用方式:

void Scharr( InputArray src, OutputArray dst, int ddepth,
            int dx, int dy, double scale = 1, double delta = 0,
            int borderType = BORDER_DEFAULT );
  • 參數與Sobel算子基本一致;
  • 但是不需要設置核的大小,因為Scharr默認就是3;

完成代碼如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/**
 * 邊緣處理
*/

int main(){
    // 讀取圖像
    Mat src = imread("/home/chen/dataset/lena.jpg");
    if (src.empty()){
        cout << "could not load image." << endl;
        return -1;
    }
    namedWindow("src", WINDOW_AUTOSIZE);
    imshow("src", src); 

    // 1. 高斯模糊
    Mat srcBlur;
    GaussianBlur(src, srcBlur, Size(3, 3), 0, 0);

    // 2. 轉灰度
    Mat srcGray;
    cvtColor(srcBlur, srcGray, COLOR_BGR2GRAY);

    // 3. 求方向梯度
    Mat gradX, gradY;
    Sobel(srcGray, gradX, CV_16S, 1, 0, 3);
    Sobel(srcGray, gradY, CV_16S, 0, 1, 3);
    // Scharr(srcGray, gradX, CV_16S, 1, 0);
    // Scharr(srcGray, gradY, CV_16S, 0, 1);
    convertScaleAbs(gradX, gradX);  // calculates absolute values, and converts the result to 8-bit.
    convertScaleAbs(gradY, gradY);
    namedWindow("gradY", WINDOW_AUTOSIZE);
    imshow("gradX", gradX);
    namedWindow("gradY", WINDOW_AUTOSIZE);
    imshow("gradY", gradY);

    printf("type: %d, %d", gradX.type(), gradY.type());

    // 4. 圖像混合
    Mat dst;
    addWeighted(gradX, 0.5, gradY, 0.5, 0, dst);
    namedWindow("dst", WINDOW_AUTOSIZE);
    imshow("dst", dst);

    // 4.1 
    Mat gradXY = Mat(gradX.size(), gradX.type());
    for (int row = 0; row < gradX.rows; row++){
        for (int col = 0; col < gradX.cols; col++){
            int gX = gradX.at<uchar>(row, col);
            int gY = gradY.at<uchar>(row, col);
            gradXY.at<uchar>(row, col) = saturate_cast<uchar>(gX + gY);
        }
    }
    namedWindow("gradXY", WINDOW_AUTOSIZE);
    imshow("gradXY", gradXY);
  
    waitKey(0);
    return 0;
}
  • 使用Sobel的結果

  • 使用Scharr算子的結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM