Sobel算子


Sobel算子和梯度計算

一、目的與原理

(1)目的:Sobel算子主要用於邊緣檢測,對噪聲平滑抑制。

(2)原理:圖像梯度用於邊緣檢測。邊緣是像素值發生躍遷的地方,是圖像的顯著特征之一。圖像中有灰度值的變化就會有梯度,從而產生邊緣,在邊緣處,具有變化的強弱及方向。圖像上可以使用一階差分來計算相鄰像素之間的變化率,我們利用卷積和特定的算子來計算相鄰像素的變化率。sobel算子可以計算相鄰三個點之間的變化率。它們用於一階算子的邊緣檢測,利用像素點上下、左右相鄰點的灰度差求取邊緣。計算水平梯度,檢測垂直邊緣 ,計算垂直梯度,檢測水平邊緣,最后通過將水平邊緣圖和垂直邊緣圖相加可近似得總邊緣圖。

 

原信號與求導數之間的變化關系:

 

下圖中灰度值的“躍升”表示邊緣的存在:

 

使用一階微分求導我們可以更加清晰的看到邊緣“躍升”的存在(這里顯示為局部極大值):

 

 

  

梯度理論知識:

圖像是離散函數,在某點的梯度可以用向前差商、向后差商或者中心差商獲得。這里采用中心差商可以獲取圖像某點的導數值。

由於除法會導致低階的重要字節丟失, 所以我們把向量乘與一個數將分母忽略掉,分子寫成一維卷積的形式相當於[1,0,-1]。Sobel模板之所以能夠較好的抑制噪聲效果,

有平滑的效果的原因是將中間行的系數加大,即Sobel卷積模板一般如下:  

 

 

計算圖像梯度值的步驟:

1. 分別與圖像進行卷積

 

 

 

 

 

2. 把得到的值寫在一起得到圖像梯度向量

 

 

 

 

 

 

其中梯度方向為:

 

 

 

 

 

梯度幅度:

 

 

 

 

 

兩個結果求出近似 梯度:

 

 

 

 

也可以用下面更簡單公式代替:

 

 

 

 

 

二、步驟

方法一:

(1)將圖片轉化為灰度圖

(2)通過x方向的卷積核計算出X方向的灰度值

(3)通過y方向的卷積核計算出y方向的灰度值

(4)x方向的y方向的灰度圖疊加成為整體邊緣

 

方法二:

(1)將圖片轉化為灰度圖

(2)根據卷積核權重對像素點的灰度值卷積

(3) 對卷積結果平方根處理

(4) 對平方根結果進行截斷處理

(5) 將最終結果賦值到輸出圖像中

(6) 顯示圖像

 

 

三、偽代碼

方法一:

輸入:原圖src

輸出:結果圖dst

void SobelXY(Mat src, Mat &dst)

{

         If(判斷src是否為灰度圖)

                   不是灰度圖則轉為灰度圖

        

         根據卷積核權重對像素點的灰度值卷積,然后相乘(平方)

         對上一步的平方結果開根號

         對上一步開根號處理結果進行截斷處理

         將結果賦值到輸出圖像

}

 

 

方法二:

輸入:原圖src

輸出:X方向的結果圖dst

void SobelX (Mat src, Mat &dst)

{

         If(判斷src是否為灰度圖)

                   不是灰度圖則轉為灰度圖

        

         根據卷積核權重對像素點的灰度值卷積

         截斷處理

         將結果賦值到輸出圖像,得到X方向的結果圖

}

 

 

輸入:原圖src

輸出:Y方向的結果圖dst

void SobelY (Mat src, Mat &dst)

{

         If(判斷src是否為灰度圖)

                   不是灰度圖則轉為灰度圖

        

         根據卷積核權重對像素點的灰度值卷積

         截斷處理

         將結果賦值到輸出圖像,得到Y方向的結果圖

}

 

四、特點

優點:索貝爾算子不但產生較好的邊緣檢測效果,而且對噪聲具有平滑抑制作用

缺點:得到的邊緣較粗,且可能出現偽邊緣。

 

五、源碼

void SobelXY(Mat src, Mat &dst)

{

    int temp=0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

            temp = sqrt((src.data[(i - 1)*src.step + j + 1]

                + 2 * src.data[i*src.step + j + 1]

                + src.data[(i + 1)*src.step + j + 1]

                - src.data[(i - 1)*src.step + j - 1]

                - 2 * src.data[i*src.step + j - 1]

                - src.data[(i + 1)*src.step + j - 1])*(src.data[(i - 1)*src.step + j + 1]

                    + 2 * src.data[i*src.step + j + 1] + src.data[(i + 1)*src.step + j + 1]

                    - src.data[(i - 1)*src.step + j - 1] - 2 * src.data[i*src.step + j - 1]

                    - src.data[(i + 1)*src.step + j - 1]) + (src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]

                        + src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]

                        - 2 * src.data[(i + 1)*src.step + j]

                        - src.data[(i + 1)*src.step + j + 1])* (src.data[(i - 1)*src.step + j - 1] + 2 * src.data[(i - 1)*src.step + j]

                            + src.data[(i - 1)*src.step + j + 1] - src.data[(i + 1)*src.step + j - 1]

                            - 2 * src.data[(i + 1)*src.step + j]

                            - src.data[(i + 1)*src.step + j + 1]));

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = temp;

 

        }

 

    }

}

 

 

 

 

void SobelX(Mat src, Mat &dst)

{

    int temp=0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

 

            temp =

                +src.data[(i - 1)*src.step + j - 1]

                + 2 * src.data[i*src.step + j - 1]

                + src.data[(i + 1)*src.step + j - 1]

                - src.data[(i - 1)*src.step + j + 1]

                - 2 * src.data[i*src.step + j + 1]

                - src.data[(i + 1)*src.step + j + 1];

 

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = abs(temp);

        }

    }

}

 

 

void SobelY(Mat src,Mat& dst)

{

    int temp = 0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

                temp

                = src.data[(i - 1)*src.step + j - 1]

                + 2 * src.data[(i - 1)*src.step + j]

                + src.data[(i - 1)*src.step + j + 1]

                - src.data[(i + 1)*src.step + j - 1]

                - 2 * src.data[(i + 1)*src.step + j]

                - src.data[(i + 1)*src.step + j + 1];

 

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = abs(temp);

        }

    }

}

 

 

 

 

 

 

六、結果圖

X+Y方式結果圖:

 

 

 

 

平方開根號方式結果圖:

 

 


免責聲明!

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



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