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方式結果圖:
平方開根號方式結果圖: